[win] onlinstaller: switch from hard URL to appcast

This commit is contained in:
SimplestStudio
2025-04-30 14:21:41 +03:00
parent a6f38eba15
commit 88f0a8f2b3
10 changed files with 3809 additions and 42 deletions

View File

@ -7,11 +7,11 @@ DEFINES += APP_LANG_PATH=\"./langs/langs.iss\"
OTHER_FILES += $$PWD/res/langs/langs.iss
ENV_URL_INSTALL = $$(DESKTOP_URL_INSTALL_CHANNEL)
ENV_URL_INSTALL = $$(DESKTOP_URL_UPDATES_MAIN_CHANNEL)
isEmpty(ENV_URL_INSTALL): DEFINES += URL_INSTALL=\\\"\\\"
else: DEFINES += URL_INSTALL=\\\"$${ENV_URL_INSTALL}\\\"
ENV_URL_INSTALL_DEV = $$(DESKTOP_URL_INSTALL_DEV_CHANNEL)
ENV_URL_INSTALL_DEV = $$(DESKTOP_URL_UPDATES_DEV_CHANNEL)
isEmpty(ENV_URL_INSTALL_DEV): DEFINES += URL_INSTALL_DEV=\\\"\\\"
else: DEFINES += URL_INSTALL_DEV=\\\"$${ENV_URL_INSTALL_DEV}\\\"

View File

@ -22,6 +22,8 @@ HEADERS += $$PWD/src/version.h \
$$PWD/src/mainwindow.h \
$$PWD/src/cdownloader.h \
$$PWD/src/translator.h \
$$PWD/src/cjson_p.h \
$$PWD/src/cjson.h \
$$PWD/src/utils.h \
$$UICLASSES/commondefines.h \
$$UICLASSES/baseutils.h \
@ -49,6 +51,7 @@ SOURCES += $$PWD/src/main.cpp \
$$PWD/src/mainwindow.cpp \
$$PWD/src/cdownloader.cpp \
$$PWD/src/translator.cpp \
$$PWD/src/cjson.cpp \
$$PWD/src/utils.cpp \
$$UICLASSES/baseutils.cpp \
$$UICLASSES/common.cpp \

View File

@ -0,0 +1,185 @@
/*
* (c) Copyright Ascensio System SIA 2010-2019
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "cjson.h"
#include "cjson_p.h"
#include <codecvt>
static std::string TStrToUtf8(const tstring &str)
{
#ifdef _WIN32
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> utf8_conv;
return utf8_conv.to_bytes(str);
#else
return str;
#endif
}
class JsonObjectPrivate
{
public:
json_object_s *obj = nullptr;
};
class JsonValuePrivate
{
public:
json_value_s *val = nullptr;
};
class JsonDocumentPrivate
{
public:
json_value_s *root = nullptr;
};
JsonValue::JsonValue() : pimpl(new JsonValuePrivate)
{}
JsonValue::JsonValue(const JsonValue &jval) : JsonValue()
{
pimpl->val = jval.pimpl->val;
}
JsonValue::~JsonValue()
{
delete pimpl, pimpl = nullptr;
}
JsonValue& JsonValue::operator=(const JsonValue &jval)
{
if (this == &jval)
return *this;
pimpl->val = jval.pimpl->val;
return *this;
}
JsonObject JsonValue::toObject()
{
JsonObject jobj;
if (pimpl->val && pimpl->val->type == json_type_object)
jobj.pimpl->obj = (json_object_s*)pimpl->val->payload;
return jobj;
}
tstring JsonValue::toTString()
{
tstring str;
if (pimpl->val && pimpl->val->type == json_type_string) {
json_string_s *jstr = (json_string_s*)pimpl->val->payload;
#ifdef _WIN32
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
str = converter.from_bytes(std::string(jstr->string, jstr->string_size));
#else
str = std::string(jstr->string, jstr->string_size);
#endif
}
return str;
}
JsonObject::JsonObject() : pimpl(new JsonObjectPrivate)
{}
JsonObject::JsonObject(const JsonObject &jobj) : JsonObject()
{
pimpl->obj = jobj.pimpl->obj;
}
JsonObject::~JsonObject()
{
delete pimpl, pimpl = nullptr;
}
JsonObject& JsonObject::operator=(const JsonObject &jobj)
{
if (this == &jobj)
return *this;
pimpl->obj = jobj.pimpl->obj;
return *this;
}
JsonValue JsonObject::value(const tstring &key)
{
std::string utf8_key = TStrToUtf8(key);
JsonValue jval;
json_object_element_s *element;
if (pimpl->obj && (element = pimpl->obj->start) != NULL) {
do {
if (strcmp(element->name->string, utf8_key.c_str()) == 0) {
jval.pimpl->val = element->value;
break;
}
} while ((element = element->next) != NULL);
}
return jval;
}
bool JsonObject::contains(const tstring &key)
{
std::string utf8_key = TStrToUtf8(key);
json_object_element_s *element;
if (pimpl->obj && (element = pimpl->obj->start) != NULL) {
do {
if (strcmp(element->name->string, utf8_key.c_str()) == 0)
return true;
} while ((element = element->next) != NULL);
}
return false;
}
JsonDocument::JsonDocument() : pimpl(new JsonDocumentPrivate)
{}
JsonDocument::JsonDocument(const tstring &json) : JsonDocument()
{
std::string utf8_json = TStrToUtf8(json);
pimpl->root = json_parse(utf8_json.c_str(), utf8_json.length());
}
JsonDocument::~JsonDocument()
{
if (pimpl->root)
free(pimpl->root);
delete pimpl, pimpl = nullptr;
}
JsonObject JsonDocument::object()
{
JsonObject obj;
if (pimpl->root && pimpl->root->type == json_type_object && pimpl->root->payload)
obj.pimpl->obj = (json_object_s*)pimpl->root->payload;
return obj;
}

View File

@ -0,0 +1,96 @@
/*
* (c) Copyright Ascensio System SIA 2010-2019
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#ifndef CJSON_H
#define CJSON_H
#include <string>
#ifdef _WIN32
# include <tchar.h>
# define tstring std::wstring
#else
# define _T(str) str
# define tstring std::string
#endif
class JsonObject;
class JsonObjectPrivate;
class JsonValuePrivate;
class JsonDocumentPrivate;
class JsonValue
{
public:
JsonValue();
JsonValue(const JsonValue&);
~JsonValue();
JsonValue& operator=(const JsonValue&);
JsonObject toObject();
tstring toTString();
private:
friend class JsonObject;
JsonValuePrivate *pimpl;
};
class JsonObject
{
public:
JsonObject();
JsonObject(const JsonObject&);
~JsonObject();
JsonObject& operator=(const JsonObject&);
JsonValue value(const tstring&);
bool contains(const tstring&);
private:
friend class JsonDocument;
friend class JsonValue;
JsonObjectPrivate *pimpl;
};
class JsonDocument
{
public:
JsonDocument(const tstring&);
~JsonDocument();
JsonObject object();
private:
JsonDocument();
JsonDocumentPrivate *pimpl;
};
#endif // CJSON_H

File diff suppressed because it is too large Load Diff

View File

@ -44,15 +44,8 @@ int WINAPI _tWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In
return 0;
}
wstring url_or_path, arch;
bool app_installed = NS_Utils::IsAppInstalled(url_or_path, &arch);
if (!app_installed) {
url_or_path = NS_Utils::cmdArgContains(_T("--appcast-dev-channel")) ? _T(URL_INSTALL_DEV) : _T(URL_INSTALL);
wstring url_filename = L"DesktopEditors_";
url_filename += NS_Utils::IsWin64() ? _T("x64") : _T("x86");
url_filename += _T(".exe");
NS_Utils::Replace(url_or_path, _T("<file>"), url_filename);
}
wstring path, arch;
bool app_installed = NS_Utils::IsAppInstalled(path, &arch);
Application app(hInst, lpCmdLine, nCmdShow);
app.setFont(L"Segoe UI");
@ -67,7 +60,7 @@ int WINAPI _tWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In
app.exit(0);
});
if (!app_installed)
w.initInstallationMode(url_or_path);
w.initInstallationMode();
else
w.initControlMode(arch);
w.showAll();

View File

@ -14,9 +14,11 @@
#include "translator.h"
#include "cdownloader.h"
#include "baseutils.h"
#include "cjson.h"
#include <Msi.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <numeric>
#include "../../src/defines.h"
#include "../../src/prop/defines_p.h"
@ -174,7 +176,7 @@ MainWindow::~MainWindow()
m_future.wait();
}
void MainWindow::initInstallationMode(const std::wstring &url)
void MainWindow::initInstallationMode()
{
m_is_checked = true;
m_mode = Mode::Install;
@ -215,7 +217,7 @@ void MainWindow::initInstallationMode(const std::wstring &url)
chkBox->close();
comntLbl->close();
instlBtn->close();
startInstall(url);
startInstall();
});
m_resize_conn = m_cenPanel->onResize([chkBox, comntLbl, instlBtn](int w, int h) {
@ -266,7 +268,7 @@ bool MainWindow::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
return Window::event(msg, wParam, lParam, result);
}
void MainWindow::startInstall(const std::wstring &url)
void MainWindow::startInstall()
{
/* Comment section */
m_comntLbl = new Label(m_cenPanel);
@ -297,7 +299,7 @@ void MainWindow::startInstall(const std::wstring &url)
m_bar->show();
wstring path = NS_File::generateTmpFileName(L".exe");
startDownload(url, path, [=]() {
startDownload(L"iss", NS_Utils::IsWin64() ? _T("x64") : _T("x86"), path, [=]() {
wstring args;
if (m_is_checked) {
args = _T("/VERYSILENT");
@ -399,12 +401,7 @@ void MainWindow::startUpdate()
tmp_path = NS_File::toNativeSeparators(NS_File::generateTmpFileName(L"." + m_package));
}
wstring url = NS_Utils::cmdArgContains(_T("--appcast-dev-channel")) ? _T(URL_INSTALL_DEV) : _T(URL_INSTALL);
wstring url_filename = L"DesktopEditors_" + m_arch;
url_filename.append(L"." + m_package);
NS_Utils::Replace(url, _T("<file>"), url_filename);
CDownloader *dnl = startDownload(url, tmp_path, [=]() {
CDownloader *dnl = startDownload(m_package == L"msi" ? L"msi" : L"iss", m_arch, tmp_path, [=]() {
if (!NS_Utils::checkAndWaitForAppClosure(nativeWindowHandle())) {
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_ERR_CANCELLED), true);
@ -481,7 +478,7 @@ void MainWindow::startUpdate()
// NS_Utils::Replace(url, L"%4", url_filename);
// }
// CDownloader *dnl = startDownload(url, tmp_path, [=]() {
// CDownloader *dnl = startDownload(m_package == L"msi" ? L"msi" : L"iss", m_arch, tmp_path, [=]() {
// if (!NS_Utils::checkAndWaitForAppClosure(nativeWindowHandle())) {
// m_bar->setProgress(0);
// m_comntInfoLbl->setText(_TR(LABEL_ERR_CANCELLED), true);
@ -823,35 +820,79 @@ wstring MainWindow::fillInstalledVerInfo()
return text;
}
CDownloader* MainWindow::startDownload(const std::wstring &url, const std::wstring &path, const std::function<void()> &onComplete)
CDownloader* MainWindow::startDownload(const std::wstring &install_type, const std::wstring &arch, const std::wstring &path, const std::function<void()> &onComplete)
{
wstring appcast_url = NS_Utils::cmdArgContains(_T("--appcast-dev-channel")) ? _T(URL_INSTALL_DEV) : _T(URL_INSTALL);
wstring tmp_path = NS_File::toNativeSeparators(NS_File::generateTmpFileName(L".json"));
CDownloader *dnl = new CDownloader();
dnl->onProgress([=](int percent) {
m_bar->setProgress(percent);
});
dnl->onComplete([=](ulong error) {
if (m_mode == Mode::Control)
m_cancelBtn->setDisabled(true);
if (error == ERROR_SUCCESS) {
if (NS_File::verifyEmbeddedSignature(path)) {
onComplete();
list<tstring> lst;
if (NS_File::readFile(tmp_path, lst)) {
tstring json = std::accumulate(lst.begin(), lst.end(), tstring());
JsonDocument doc(json);
JsonObject root = doc.object();
// tstring version = root.value(_T("version")).toTString();
JsonObject package = root.value(_T("package")).toObject();
#ifdef _WIN32
JsonObject win = package.value(arch == _T("x64") ? _T("win_64") : _T("win_32")).toObject();
#else
JsonObject win = package.value(_T("linux_64")).toObject();
#endif
JsonObject package_type = win.value(install_type).toObject();
tstring url = package_type.value(_T("url")).toTString();
// tstring hash = package_type.value(_T("md5")).toTString();
// std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
NS_File::removeFile(tmp_path);
invokeMethod([=]() {
dnl->stop();
dnl->onProgress([=](int percent) {
m_bar->setProgress(percent);
});
dnl->onComplete([=](ulong error) {
if (m_mode == Mode::Control)
m_cancelBtn->setDisabled(true);
if (error == ERROR_SUCCESS) {
if (NS_File::verifyEmbeddedSignature(path)) {
onComplete();
} else {
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_NO_VER_AVAIL), true);
}
if (NS_File::fileExists(path))
NS_File::removeFile(path);
} else
if (error == ERROR_CANCELLED) {
m_comntInfoLbl->setText(_TR(LABEL_ERR_CANCELLED), true);
} else {
m_comntInfoLbl->setText(NS_Utils::GetLastErrorAsString(error), true);
}
if (m_mode == Mode::Control)
createCloseAndBackButtons();
});
dnl->downloadFile(url, path);
});
} else {
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_NO_VER_AVAIL), true);
NS_File::removeFile(tmp_path);
m_comntInfoLbl->setText(_TR(LABEL_ERR_COMMON), true);
if (m_mode == Mode::Control)
createCloseAndBackButtons();
}
if (NS_File::fileExists(path))
NS_File::removeFile(path);
} else
if (error == ERROR_CANCELLED) {
m_comntInfoLbl->setText(_TR(LABEL_ERR_CANCELLED), true);
if (m_mode == Mode::Control)
createCloseAndBackButtons();
} else {
m_comntInfoLbl->setText(NS_Utils::GetLastErrorAsString(error), true);
if (m_mode == Mode::Control)
createCloseAndBackButtons();
}
if (m_mode == Mode::Control)
createCloseAndBackButtons();
});
dnl->downloadFile(url, path);
dnl->downloadFile(appcast_url, tmp_path);
onAboutToDestroy([=]() {
delete dnl;
});

View File

@ -19,14 +19,14 @@ public:
MainWindow(Widget *parent, const Rect &rc);
~MainWindow();
void initInstallationMode(const std::wstring &url);
void initInstallationMode();
void initControlMode(const std::wstring &arch);
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
void startInstall(const std::wstring &url);
void startInstall();
void finishInstall(const std::wstring &app_path);
void startUpdate();
// void startRepair();
@ -36,7 +36,7 @@ private:
void createCloseButton();
void createCloseAndBackButtons();
std::wstring fillInstalledVerInfo();
CDownloader* startDownload(const std::wstring &url, const std::wstring &path, const std::function<void()> &onComplete);
CDownloader* startDownload(const std::wstring &install_type, const std::wstring &arch, const std::wstring &path, const std::function<void()> &onComplete);
template<typename Fn, typename... Args>
void invokeMethod(Fn&& fn, Args&&... args);

View File

@ -356,6 +356,21 @@ namespace NS_File
// return false;
// }
bool readFile(const wstring &filePath, list<wstring> &linesList)
{
std::wifstream file(filePath.c_str(), std::ios_base::in);
if (!file.is_open()) {
NS_Logger::WriteLog(L"An error occurred while opening: " + filePath);
return false;
}
wstring line;
while (std::getline(file, line))
linesList.push_back(line);
file.close();
return true;
}
bool fileExists(const wstring &filePath)
{
DWORD attr = ::GetFileAttributes(filePath.c_str());

View File

@ -35,10 +35,12 @@
#include <Windows.h>
#include <string>
#include <list>
using std::string;
using std::wstring;
using std::to_wstring;
using std::list;
#define ERROR_LAUNCH 0x20000000
#define DEFAULT_ERROR_MESSAGE _T("An error occurred: ") + \
@ -69,6 +71,7 @@ namespace NS_File
{
DWORD runProcess(const wstring &fileName, const wstring &args, bool runAsAdmin = false, bool wait = true);
// bool isProcessRunning(const wstring &fileName);
bool readFile(const wstring &filePath, list<wstring> &linesList);
bool fileExists(const wstring &filePath);
bool removeFile(const wstring &filePath);
bool removeDirRecursively(const wstring &dir);