mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Improve autoupdate code, move it from Application.
This commit is contained in:
parent
65f968ec1b
commit
993cb987a6
@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "observer_peer.h"
|
||||
#include "auth_session.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
@ -1667,7 +1668,7 @@ namespace {
|
||||
|
||||
void restart() {
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
bool updateReady = (Sandbox::updatingState() == Application::UpdatingReady);
|
||||
bool updateReady = (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready);
|
||||
#else // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
bool updateReady = false;
|
||||
#endif // else for !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
@ -11,11 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "autoupdater.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "messenger.h"
|
||||
#include "base/timer.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "core/crash_report_window.h"
|
||||
|
||||
namespace {
|
||||
@ -65,7 +65,11 @@ Application::Application(
|
||||
int &argc,
|
||||
char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, _launcher(launcher) {
|
||||
, _launcher(launcher)
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
, _updateChecker(std::make_unique<Core::UpdateChecker>())
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
{
|
||||
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
|
||||
char h[33] = { 0 };
|
||||
hashMd5Hex(d.constData(), d.size(), h);
|
||||
@ -86,13 +90,6 @@ Application::Application(
|
||||
QTimer::singleShot(0, this, SLOT(startApplication()));
|
||||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(closeApplication()));
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
_updateCheckTimer.create(this);
|
||||
connect(_updateCheckTimer, SIGNAL(timeout()), this, SLOT(updateCheck()));
|
||||
connect(this, SIGNAL(updateFailed()), this, SLOT(onUpdateFailed()));
|
||||
connect(this, SIGNAL(updateReady()), this, SLOT(onUpdateReady()));
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
if (cManyInstance()) {
|
||||
LOG(("Many instance allowed, starting..."));
|
||||
singleInstanceChecked();
|
||||
@ -180,7 +177,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
|
||||
#endif // !Q_OS_WINRT
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (!cNoStartUpdate() && checkReadyUpdate()) {
|
||||
if (!cNoStartUpdate() && Core::checkReadyUpdate()) {
|
||||
cSetRestartingUpdate(true);
|
||||
DEBUG_LOG(("Application Info: installing update instead of starting app..."));
|
||||
return App::quit();
|
||||
@ -356,168 +353,10 @@ void Application::closeApplication() {
|
||||
_localSocket.close();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
delete _updateReply;
|
||||
_updateReply = 0;
|
||||
if (_updateChecker) _updateChecker->deleteLater();
|
||||
_updateChecker = 0;
|
||||
if (_updateThread) {
|
||||
_updateThread->quit();
|
||||
}
|
||||
_updateThread = 0;
|
||||
_updateChecker = nullptr;
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void Application::updateCheck() {
|
||||
startUpdateCheck(false);
|
||||
}
|
||||
|
||||
void Application::updateGotCurrent() {
|
||||
if (!_updateReply || _updateThread) return;
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(_updateReply->readAll()));
|
||||
if (m.hasMatch()) {
|
||||
uint64 currentVersion = m.captured(1).toULongLong();
|
||||
QString url = m.captured(2);
|
||||
bool betaVersion = false;
|
||||
if (url.startsWith(qstr("beta_"))) {
|
||||
betaVersion = true;
|
||||
url = url.mid(5) + '_' + countBetaVersionSignature(currentVersion);
|
||||
}
|
||||
if ((!betaVersion || cBetaVersion()) && currentVersion > (betaVersion ? cBetaVersion() : uint64(AppVersion))) {
|
||||
_updateThread = new QThread();
|
||||
connect(_updateThread, SIGNAL(finished()), _updateThread, SLOT(deleteLater()));
|
||||
_updateChecker = new UpdateChecker(_updateThread, url);
|
||||
_updateThread->start();
|
||||
}
|
||||
}
|
||||
if (_updateReply) _updateReply->deleteLater();
|
||||
_updateReply = 0;
|
||||
if (!_updateThread) {
|
||||
QDir updates(cWorkingDir() + "tupdates");
|
||||
if (updates.exists()) {
|
||||
QFileInfoList list = updates.entryInfoList(QDir::Files);
|
||||
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
|
||||
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
|
||||
QFile(i->absoluteFilePath()).remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
emit updateLatest();
|
||||
}
|
||||
startUpdateCheck(true);
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
void Application::updateFailedCurrent(QNetworkReply::NetworkError e) {
|
||||
LOG(("App Error: could not get current version (update check): %1").arg(e));
|
||||
if (_updateReply) _updateReply->deleteLater();
|
||||
_updateReply = 0;
|
||||
|
||||
emit updateFailed();
|
||||
startUpdateCheck(true);
|
||||
}
|
||||
|
||||
void Application::onUpdateReady() {
|
||||
if (_updateChecker) {
|
||||
_updateChecker->deleteLater();
|
||||
_updateChecker = nullptr;
|
||||
}
|
||||
_updateCheckTimer->stop();
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
void Application::onUpdateFailed() {
|
||||
if (_updateChecker) {
|
||||
_updateChecker->deleteLater();
|
||||
_updateChecker = 0;
|
||||
if (_updateThread) _updateThread->quit();
|
||||
_updateThread = 0;
|
||||
}
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
Application::UpdatingState Application::updatingState() {
|
||||
if (!_updateThread) return Application::UpdatingNone;
|
||||
if (!_updateChecker) return Application::UpdatingReady;
|
||||
return Application::UpdatingDownload;
|
||||
}
|
||||
|
||||
int32 Application::updatingSize() {
|
||||
if (!_updateChecker) return 0;
|
||||
return _updateChecker->size();
|
||||
}
|
||||
|
||||
int32 Application::updatingReady() {
|
||||
if (!_updateChecker) return 0;
|
||||
return _updateChecker->ready();
|
||||
}
|
||||
|
||||
void Application::stopUpdate() {
|
||||
if (_updateReply) {
|
||||
_updateReply->abort();
|
||||
_updateReply->deleteLater();
|
||||
_updateReply = 0;
|
||||
}
|
||||
if (_updateChecker) {
|
||||
_updateChecker->deleteLater();
|
||||
_updateChecker = 0;
|
||||
if (_updateThread) _updateThread->quit();
|
||||
_updateThread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::startUpdateCheck(bool forceWait) {
|
||||
if (!Sandbox::started()) return;
|
||||
|
||||
_updateCheckTimer->stop();
|
||||
if (_updateThread || _updateReply || !cAutoUpdate() || cExeName().isEmpty()) return;
|
||||
|
||||
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
|
||||
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(rand() % randDelay) - unixtime();
|
||||
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
|
||||
if (!sendRequest && !forceWait) {
|
||||
QDir updates(cWorkingDir() + "tupdates");
|
||||
if (updates.exists()) {
|
||||
QFileInfoList list = updates.entryInfoList(QDir::Files);
|
||||
for (QFileInfoList::iterator i = list.begin(), e = list.end(); i != e; ++i) {
|
||||
if (QRegularExpression("^(tupdate|tmacupd|tmac32upd|tlinuxupd|tlinux32upd)\\d+(_[a-z\\d]+)?$", QRegularExpression::CaseInsensitiveOption).match(i->fileName()).hasMatch()) {
|
||||
sendRequest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cManyInstance() && !cDebug()) return; // only main instance is updating
|
||||
|
||||
if (sendRequest) {
|
||||
QUrl url(cUpdateURL());
|
||||
if (cBetaVersion()) {
|
||||
url.setQuery(qsl("version=%1&beta=%2").arg(AppVersion).arg(cBetaVersion()));
|
||||
} else if (cAlphaVersion()) {
|
||||
url.setQuery(qsl("version=%1&alpha=1").arg(AppVersion));
|
||||
} else {
|
||||
url.setQuery(qsl("version=%1").arg(AppVersion));
|
||||
}
|
||||
QString u = url.toString();
|
||||
QNetworkRequest checkVersion(url);
|
||||
if (_updateReply) _updateReply->deleteLater();
|
||||
|
||||
_updateReply = _updateManager.get(checkVersion);
|
||||
connect(_updateReply, SIGNAL(finished()), this, SLOT(updateGotCurrent()));
|
||||
connect(_updateReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(updateFailedCurrent(QNetworkReply::NetworkError)));
|
||||
emit updateChecking();
|
||||
} else {
|
||||
_updateCheckTimer->start((updateInSecs + 5) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
inline Application *application() {
|
||||
return qobject_cast<Application*>(QApplication::instance());
|
||||
}
|
||||
@ -569,73 +408,6 @@ void adjustSingleTimers() {
|
||||
base::Timer::Adjust();
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
void startUpdateCheck() {
|
||||
if (auto a = application()) {
|
||||
return a->startUpdateCheck(false);
|
||||
}
|
||||
}
|
||||
|
||||
void stopUpdate() {
|
||||
if (auto a = application()) {
|
||||
return a->stopUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
Application::UpdatingState updatingState() {
|
||||
if (auto a = application()) {
|
||||
return a->updatingState();
|
||||
}
|
||||
return Application::UpdatingNone;
|
||||
}
|
||||
|
||||
int32 updatingSize() {
|
||||
if (auto a = application()) {
|
||||
return a->updatingSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 updatingReady() {
|
||||
if (auto a = application()) {
|
||||
return a->updatingReady();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateChecking() {
|
||||
if (auto a = application()) {
|
||||
emit a->updateChecking();
|
||||
}
|
||||
}
|
||||
|
||||
void updateLatest() {
|
||||
if (auto a = application()) {
|
||||
emit a->updateLatest();
|
||||
}
|
||||
}
|
||||
|
||||
void updateProgress(qint64 ready, qint64 total) {
|
||||
if (auto a = application()) {
|
||||
emit a->updateProgress(ready, total);
|
||||
}
|
||||
}
|
||||
|
||||
void updateFailed() {
|
||||
if (auto a = application()) {
|
||||
emit a->updateFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void updateReady() {
|
||||
if (auto a = application()) {
|
||||
emit a->updateReady();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
void connect(const char *signal, QObject *object, const char *method) {
|
||||
if (auto a = application()) {
|
||||
a->connect(a, signal, object, method);
|
||||
|
@ -7,10 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class UpdateChecker;
|
||||
|
||||
namespace Core {
|
||||
class Launcher;
|
||||
class UpdateChecker;
|
||||
} // namespace Core
|
||||
|
||||
class Application : public QApplication {
|
||||
@ -59,46 +58,11 @@ private:
|
||||
|
||||
void singleInstanceChecked();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
// Autoupdating
|
||||
public:
|
||||
void startUpdateCheck(bool forceWait);
|
||||
void stopUpdate();
|
||||
|
||||
enum UpdatingState {
|
||||
UpdatingNone,
|
||||
UpdatingDownload,
|
||||
UpdatingReady,
|
||||
};
|
||||
UpdatingState updatingState();
|
||||
int32 updatingSize();
|
||||
int32 updatingReady();
|
||||
|
||||
signals:
|
||||
void updateChecking();
|
||||
void updateLatest();
|
||||
void updateProgress(qint64 ready, qint64 total);
|
||||
void updateReady();
|
||||
void updateFailed();
|
||||
|
||||
public slots:
|
||||
void updateCheck();
|
||||
|
||||
void updateGotCurrent();
|
||||
void updateFailedCurrent(QNetworkReply::NetworkError e);
|
||||
|
||||
void onUpdateReady();
|
||||
void onUpdateFailed();
|
||||
|
||||
private:
|
||||
object_ptr<SingleTimer> _updateCheckTimer = { nullptr };
|
||||
QNetworkReply *_updateReply = nullptr;
|
||||
QNetworkAccessManager _updateManager;
|
||||
QThread *_updateThread = nullptr;
|
||||
UpdateChecker *_updateChecker = nullptr;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
std::unique_ptr<Core::UpdateChecker> _updateChecker;
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
};
|
||||
|
||||
namespace Sandbox {
|
||||
@ -112,23 +76,6 @@ void execExternal(const QString &cmd);
|
||||
|
||||
void adjustSingleTimers();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
void startUpdateCheck();
|
||||
void stopUpdate();
|
||||
|
||||
Application::UpdatingState updatingState();
|
||||
int32 updatingSize();
|
||||
int32 updatingReady();
|
||||
|
||||
void updateChecking();
|
||||
void updateLatest();
|
||||
void updateProgress(qint64 ready, qint64 total);
|
||||
void updateFailed();
|
||||
void updateReady();
|
||||
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
void refreshGlobalProxy();
|
||||
|
||||
void connect(const char *signal, QObject *object, const char *method);
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <QtNetwork/QLocalServer>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
class UpdateChecker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UpdateChecker(QThread *thread, const QString &url);
|
||||
|
||||
void unpackUpdate();
|
||||
|
||||
int32 ready();
|
||||
int32 size();
|
||||
|
||||
static void clearAll();
|
||||
|
||||
~UpdateChecker();
|
||||
|
||||
public slots:
|
||||
|
||||
void start();
|
||||
void partMetaGot();
|
||||
void partFinished(qint64 got, qint64 total);
|
||||
void partFailed(QNetworkReply::NetworkError e);
|
||||
void sendRequest();
|
||||
|
||||
private:
|
||||
void initOutput();
|
||||
|
||||
void fatalFail();
|
||||
|
||||
QString updateUrl;
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkReply *reply;
|
||||
int32 already, full;
|
||||
QFile outputFile;
|
||||
|
||||
QMutex mutex;
|
||||
|
||||
};
|
||||
|
||||
bool checkReadyUpdate();
|
||||
|
||||
#else // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
class UpdateChecker : public QObject {
|
||||
Q_OBJECT
|
||||
};
|
||||
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
QString countBetaVersionSignature(uint64 version);
|
@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "autoupdater.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "application.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
@ -18,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_boxes.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/update_checker.h"
|
||||
|
||||
AboutBox::AboutBox(QWidget *parent)
|
||||
: _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
|
||||
@ -68,7 +68,7 @@ void AboutBox::showVersionHistory() {
|
||||
case dbipLinux32: url += qsl("linux32/%1.tar.xz"); break;
|
||||
case dbipLinux64: url += qsl("linux/%1.tar.xz"); break;
|
||||
}
|
||||
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(countBetaVersionSignature(cRealBetaVersion())));
|
||||
url = url.arg(qsl("tbeta%1_%2").arg(cRealBetaVersion()).arg(Core::countBetaVersionSignature(cRealBetaVersion())));
|
||||
|
||||
Application::clipboard()->setText(url);
|
||||
|
||||
|
@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/platform_specific.h"
|
||||
#include "application.h"
|
||||
#include "base/zlib_help.h"
|
||||
#include "autoupdater.h"
|
||||
#include "core/update_checker.h"
|
||||
|
||||
PreLaunchWindow *PreLaunchWindowInstance = nullptr;
|
||||
|
||||
@ -299,23 +299,36 @@ LastCrashedWindow::LastCrashedWindow()
|
||||
_updatingSkip.setText(qsl("SKIP"));
|
||||
connect(&_updatingSkip, SIGNAL(clicked()), this, SLOT(onUpdateSkip()));
|
||||
|
||||
Sandbox::connect(SIGNAL(updateChecking()), this, SLOT(onUpdateChecking()));
|
||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onUpdateLatest()));
|
||||
Sandbox::connect(SIGNAL(updateProgress(qint64,qint64)), this, SLOT(onUpdateDownloading(qint64,qint64)));
|
||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onUpdateFailed()));
|
||||
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onUpdateReady()));
|
||||
Core::UpdateChecker checker;
|
||||
using Progress = Core::UpdateChecker::Progress;
|
||||
checker.checking(
|
||||
) | rpl::start_with_next([=] { onUpdateChecking(); }, _lifetime);
|
||||
checker.isLatest(
|
||||
) | rpl::start_with_next([=] { onUpdateLatest(); }, _lifetime);
|
||||
checker.progress(
|
||||
) | rpl::start_with_next([=](const Progress &result) {
|
||||
onUpdateDownloading(result.already, result.size);
|
||||
}, _lifetime);
|
||||
checker.failed(
|
||||
) | rpl::start_with_next([=] { onUpdateFailed(); }, _lifetime);
|
||||
checker.ready(
|
||||
) | rpl::start_with_next([=] { onUpdateReady(); }, _lifetime);
|
||||
|
||||
switch (Sandbox::updatingState()) {
|
||||
case Application::UpdatingDownload:
|
||||
switch (checker.state()) {
|
||||
case Core::UpdateChecker::State::Download:
|
||||
setUpdatingState(UpdatingDownload, true);
|
||||
setDownloadProgress(Sandbox::updatingReady(), Sandbox::updatingSize());
|
||||
break;
|
||||
case Application::UpdatingReady: setUpdatingState(UpdatingReady, true); break;
|
||||
default: setUpdatingState(UpdatingCheck, true); break;
|
||||
setDownloadProgress(checker.already(), checker.size());
|
||||
break;
|
||||
case Core::UpdateChecker::State::Ready:
|
||||
setUpdatingState(UpdatingReady, true);
|
||||
break;
|
||||
default:
|
||||
setUpdatingState(UpdatingCheck, true);
|
||||
break;
|
||||
}
|
||||
|
||||
cSetLastUpdateCheck(0);
|
||||
Sandbox::startUpdateCheck();
|
||||
checker.start();
|
||||
#else // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
_updating.setText(qsl("Please check if there is a new version available."));
|
||||
if (_sendingState != SendingNoReport) {
|
||||
@ -790,9 +803,10 @@ void LastCrashedWindow::onNetworkSettingsSaved(
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if ((_updatingState == UpdatingFail && (_sendingState == SendingNoReport || _sendingState == SendingUpdateCheck)) || (_updatingState == UpdatingCheck)) {
|
||||
Sandbox::stopUpdate();
|
||||
Core::UpdateChecker checker;
|
||||
checker.stop();
|
||||
cSetLastUpdateCheck(0);
|
||||
Sandbox::startUpdateCheck();
|
||||
checker.start();
|
||||
} else
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (_sendingState == SendingFail || _sendingState == SendingProgress) {
|
||||
@ -815,7 +829,7 @@ void LastCrashedWindow::setUpdatingState(UpdatingState state, bool force) {
|
||||
}
|
||||
break;
|
||||
case UpdatingReady:
|
||||
if (checkReadyUpdate()) {
|
||||
if (Core::checkReadyUpdate()) {
|
||||
cSetRestartingUpdate(true);
|
||||
App::quit();
|
||||
return;
|
||||
@ -849,7 +863,8 @@ void LastCrashedWindow::setDownloadProgress(qint64 ready, qint64 total) {
|
||||
|
||||
void LastCrashedWindow::onUpdateRetry() {
|
||||
cSetLastUpdateCheck(0);
|
||||
Sandbox::startUpdateCheck();
|
||||
Core::UpdateChecker checker;
|
||||
checker.start();
|
||||
}
|
||||
|
||||
void LastCrashedWindow::onUpdateSkip() {
|
||||
@ -857,7 +872,8 @@ void LastCrashedWindow::onUpdateSkip() {
|
||||
onContinue();
|
||||
} else {
|
||||
if (_updatingState == UpdatingCheck || _updatingState == UpdatingDownload) {
|
||||
Sandbox::stopUpdate();
|
||||
Core::UpdateChecker checker;
|
||||
checker.stop();
|
||||
setUpdatingState(UpdatingFail);
|
||||
}
|
||||
_sendingState = SendingNone;
|
||||
|
@ -114,6 +114,11 @@ private:
|
||||
QString minidumpFileName();
|
||||
void updateControls();
|
||||
|
||||
void excludeReportUsername();
|
||||
|
||||
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
|
||||
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
|
||||
|
||||
QString _host, _username, _password;
|
||||
quint32 _port;
|
||||
|
||||
@ -128,8 +133,6 @@ private:
|
||||
|
||||
bool _reportShown, _reportSaved;
|
||||
|
||||
void excludeReportUsername();
|
||||
|
||||
enum SendingState {
|
||||
SendingNoReport,
|
||||
SendingUpdateCheck,
|
||||
@ -167,8 +170,7 @@ private:
|
||||
void setDownloadProgress(qint64 ready, qint64 total);
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
QString getReportField(const QLatin1String &name, const QLatin1String &prefix);
|
||||
void addReportFieldPart(const QLatin1String &name, const QLatin1String &prefix, QHttpMultiPart *multipart);
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
|
@ -5,8 +5,12 @@ the official desktop application for the Telegram messaging service.
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "core/update_checker.h"
|
||||
|
||||
#include "autoupdater.h"
|
||||
#include "application.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "base/timer.h"
|
||||
#include "storage/localstorage.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
@ -19,131 +23,554 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <lzma.h>
|
||||
#endif // else of Q_OS_WIN
|
||||
|
||||
#include "application.h"
|
||||
#include "platform/platform_specific.h"
|
||||
namespace Core {
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kCheckTimeout = TimeMs(10000);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
typedef DWORD VerInt;
|
||||
typedef WCHAR VerChar;
|
||||
using VersionInt = DWORD;
|
||||
using VersionChar = WCHAR;
|
||||
#else // Q_OS_WIN
|
||||
typedef int VerInt;
|
||||
typedef wchar_t VerChar;
|
||||
using VersionInt = int;
|
||||
using VersionChar = wchar_t;
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
UpdateChecker::UpdateChecker(QThread *thread, const QString &url) : reply(0), already(0), full(0) {
|
||||
updateUrl = url;
|
||||
moveToThread(thread);
|
||||
manager.moveToThread(thread);
|
||||
using ErrorSignal = void(QNetworkReply::*)(QNetworkReply::NetworkError);
|
||||
const auto QNetworkReply_error = ErrorSignal(&QNetworkReply::error);
|
||||
|
||||
connect(thread, SIGNAL(started()), this, SLOT(start()));
|
||||
std::weak_ptr<Updater> UpdaterInstance;
|
||||
|
||||
std::shared_ptr<Updater> GetUpdaterInstance() {
|
||||
if (const auto result = UpdaterInstance.lock()) {
|
||||
return result;
|
||||
}
|
||||
const auto result = std::make_shared<Updater>();
|
||||
UpdaterInstance = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClearAll() {
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates"));
|
||||
}
|
||||
|
||||
QString FindUpdateFile() {
|
||||
QDir updates(cWorkingDir() + "tupdates");
|
||||
if (!updates.exists()) {
|
||||
return QString();
|
||||
}
|
||||
const auto list = updates.entryInfoList(QDir::Files);
|
||||
for (const auto &info : list) {
|
||||
if (QRegularExpression(
|
||||
"^("
|
||||
"tupdate|"
|
||||
"tmacupd|"
|
||||
"tmac32upd|"
|
||||
"tlinuxupd|"
|
||||
"tlinux32upd"
|
||||
")\\d+(_[a-z\\d]+)?$",
|
||||
QRegularExpression::CaseInsensitiveOption
|
||||
).match(info.fileName()).hasMatch()) {
|
||||
return info.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class Updater : public base::has_weak_ptr {
|
||||
public:
|
||||
using Progress = UpdateChecker::Progress;
|
||||
using State = UpdateChecker::State;
|
||||
|
||||
Updater();
|
||||
|
||||
rpl::producer<> checking() const;
|
||||
rpl::producer<> isLatest() const;
|
||||
rpl::producer<Progress> progress() const;
|
||||
rpl::producer<> failed() const;
|
||||
rpl::producer<> ready() const;
|
||||
|
||||
void start(bool forceWait);
|
||||
void stop();
|
||||
|
||||
State state() const;
|
||||
int already() const;
|
||||
int size() const;
|
||||
|
||||
// Thread-safe methods.
|
||||
void onProgress(Progress progress);
|
||||
void onFailed();
|
||||
void onReady();
|
||||
|
||||
~Updater();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
void check();
|
||||
void handleFailed();
|
||||
void handleReady();
|
||||
void gotResponse();
|
||||
void gotFailure(QNetworkReply::NetworkError e);
|
||||
void clearSentRequest();
|
||||
void requestTimeout();
|
||||
|
||||
bool _isReady = false;
|
||||
base::Timer _timer;
|
||||
base::Timer _retryTimer;
|
||||
rpl::event_stream<> _checking;
|
||||
rpl::event_stream<> _isLatest;
|
||||
rpl::event_stream<Progress> _progress;
|
||||
rpl::event_stream<> _failed;
|
||||
rpl::event_stream<> _ready;
|
||||
std::unique_ptr<QNetworkAccessManager> _manager;
|
||||
QNetworkReply *_reply = nullptr;
|
||||
std::unique_ptr<QThread> _thread;
|
||||
Private *_private = nullptr;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
class Updater::Private : public QObject {
|
||||
public:
|
||||
Private(
|
||||
not_null<Updater*> parent,
|
||||
not_null<QThread*> thread,
|
||||
const QString &url);
|
||||
|
||||
void unpackUpdate();
|
||||
|
||||
// Thread-safe methods.
|
||||
int already() const;
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
void start();
|
||||
void sendRequest();
|
||||
void initOutput();
|
||||
|
||||
void gotMetaData();
|
||||
void partFinished(qint64 got, qint64 total);
|
||||
void partFailed(QNetworkReply::NetworkError e);
|
||||
|
||||
void fatalFail();
|
||||
|
||||
not_null<Updater*> _parent;
|
||||
QString _url;
|
||||
QNetworkAccessManager _manager;
|
||||
std::unique_ptr<QNetworkReply> _reply;
|
||||
int _already = 0;
|
||||
int _size = 0;
|
||||
QFile _output;
|
||||
|
||||
mutable QMutex _mutex;
|
||||
|
||||
};
|
||||
|
||||
Updater::Updater()
|
||||
: _timer([=] { check(); })
|
||||
, _retryTimer([=] { requestTimeout(); }) {
|
||||
failed() | rpl::start_with_next([=] {
|
||||
handleFailed();
|
||||
}, _lifetime);
|
||||
ready() | rpl::start_with_next([=] {
|
||||
handleReady();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
rpl::producer<> Updater::checking() const {
|
||||
return _checking.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Updater::isLatest() const {
|
||||
return _isLatest.events();
|
||||
}
|
||||
|
||||
auto Updater::progress() const
|
||||
-> rpl::producer<Progress> {
|
||||
return _progress.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Updater::failed() const {
|
||||
return _failed.events();
|
||||
}
|
||||
|
||||
rpl::producer<> Updater::ready() const {
|
||||
return _ready.events();
|
||||
}
|
||||
|
||||
void Updater::onProgress(Progress progress) {
|
||||
crl::on_main(this, [=] {
|
||||
_progress.fire_copy(progress);
|
||||
});
|
||||
}
|
||||
|
||||
void Updater::onFailed() {
|
||||
crl::on_main(this, [=] {
|
||||
_failed.fire({});
|
||||
});
|
||||
}
|
||||
|
||||
void Updater::onReady() {
|
||||
crl::on_main(this, [=] {
|
||||
_ready.fire({});
|
||||
});
|
||||
}
|
||||
|
||||
void Updater::check() {
|
||||
start(false);
|
||||
}
|
||||
|
||||
void Updater::gotResponse() {
|
||||
if (!_reply || _thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
const auto m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(_reply->readAll()));
|
||||
if (m.hasMatch()) {
|
||||
uint64 currentVersion = m.captured(1).toULongLong();
|
||||
QString url = m.captured(2);
|
||||
bool betaVersion = false;
|
||||
if (url.startsWith(qstr("beta_"))) {
|
||||
betaVersion = true;
|
||||
url = url.mid(5) + '_' + Core::countBetaVersionSignature(currentVersion);
|
||||
}
|
||||
if ((!betaVersion || cBetaVersion()) && currentVersion > (betaVersion ? cBetaVersion() : uint64(AppVersion))) {
|
||||
_thread = std::make_unique<QThread>();
|
||||
_private = new Private(this, _thread.get(), url);
|
||||
_thread->start();
|
||||
}
|
||||
}
|
||||
clearSentRequest();
|
||||
if (!_thread) {
|
||||
if (const auto update = FindUpdateFile(); !update.isEmpty()) {
|
||||
QFile(update).remove();
|
||||
}
|
||||
_isLatest.fire({});
|
||||
}
|
||||
start(true);
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
void Updater::gotFailure(QNetworkReply::NetworkError e) {
|
||||
LOG(("App Error: could not get current version (update check): %1").arg(e));
|
||||
if (const auto reply = base::take(_reply)) {
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
_failed.fire({});
|
||||
start(true);
|
||||
}
|
||||
|
||||
void Updater::handleReady() {
|
||||
_isReady = true;
|
||||
stop();
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
void Updater::handleFailed() {
|
||||
stop();
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
auto Updater::state() const -> State {
|
||||
if (_isReady) {
|
||||
return State::Ready;
|
||||
} else if (!_thread) {
|
||||
return State::None;
|
||||
}
|
||||
return State::Download;
|
||||
}
|
||||
|
||||
int Updater::size() const {
|
||||
return _private ? _private->size() : 0;
|
||||
}
|
||||
|
||||
int Updater::already() const {
|
||||
return _private ? _private->already() : 0;
|
||||
}
|
||||
|
||||
void Updater::clearSentRequest() {
|
||||
const auto reply = base::take(_reply);
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
reply->disconnect(reply, &QNetworkReply::finished, nullptr, nullptr);
|
||||
reply->disconnect(reply, QNetworkReply_error, nullptr, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
_manager = nullptr;
|
||||
}
|
||||
|
||||
void Updater::stop() {
|
||||
clearSentRequest();
|
||||
if (const auto checker = base::take(_private)) {
|
||||
InvokeQueued(checker, [=] { checker->deleteLater(); });
|
||||
if (const auto thread = base::take(_thread)) {
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Updater::start(bool forceWait) {
|
||||
if (!Sandbox::started() || _isReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
_timer.cancel();
|
||||
if (_thread || _reply || !cAutoUpdate() || cExeName().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_retryTimer.cancel();
|
||||
const auto constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart;
|
||||
const auto randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
|
||||
const auto updateInSecs = cLastUpdateCheck()
|
||||
+ constDelay
|
||||
+ int(rand() % randDelay)
|
||||
- unixtime();
|
||||
auto sendRequest = (updateInSecs <= 0)
|
||||
|| (updateInSecs > constDelay + randDelay);
|
||||
if (!sendRequest && !forceWait) {
|
||||
if (!FindUpdateFile().isEmpty()) {
|
||||
sendRequest = true;
|
||||
}
|
||||
}
|
||||
if (cManyInstance() && !cDebug()) {
|
||||
// Only main instance is updating.
|
||||
return;
|
||||
}
|
||||
|
||||
if (sendRequest) {
|
||||
clearSentRequest();
|
||||
|
||||
auto url = QUrl(cUpdateURL());
|
||||
if (cBetaVersion()) {
|
||||
url.setQuery(qsl("version=%1&beta=%2"
|
||||
).arg(AppVersion
|
||||
).arg(cBetaVersion()));
|
||||
} else if (cAlphaVersion()) {
|
||||
url.setQuery(qsl("version=%1&alpha=1").arg(AppVersion));
|
||||
} else {
|
||||
url.setQuery(qsl("version=%1").arg(AppVersion));
|
||||
}
|
||||
DEBUG_LOG(("App Info: requesting update state from '%1'"
|
||||
).arg(url.toDisplayString()));
|
||||
const auto request = QNetworkRequest(url);
|
||||
_manager = std::make_unique<QNetworkAccessManager>();
|
||||
_reply = _manager->get(request);
|
||||
_reply->connect(_reply, &QNetworkReply::finished, [=] {
|
||||
gotResponse();
|
||||
});
|
||||
_reply->connect(_reply, QNetworkReply_error, [=](auto e) {
|
||||
gotFailure(e);
|
||||
});
|
||||
_checking.fire({});
|
||||
_retryTimer.callOnce(kCheckTimeout);
|
||||
} else {
|
||||
_timer.callOnce((updateInSecs + 5) * TimeMs(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void Updater::requestTimeout() {
|
||||
if (_reply) {
|
||||
stop();
|
||||
_failed.fire({});
|
||||
cSetLastUpdateCheck(0);
|
||||
_timer.callOnce(kCheckTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
Updater::~Updater() {
|
||||
stop();
|
||||
}
|
||||
|
||||
UpdateChecker::UpdateChecker()
|
||||
: _updater(GetUpdaterInstance()) {
|
||||
}
|
||||
|
||||
rpl::producer<> UpdateChecker::checking() const {
|
||||
return _updater->checking();
|
||||
}
|
||||
|
||||
rpl::producer<> UpdateChecker::isLatest() const {
|
||||
return _updater->isLatest();
|
||||
}
|
||||
|
||||
auto UpdateChecker::progress() const
|
||||
-> rpl::producer<Progress> {
|
||||
return _updater->progress();
|
||||
}
|
||||
|
||||
rpl::producer<> UpdateChecker::failed() const {
|
||||
return _updater->failed();
|
||||
}
|
||||
|
||||
rpl::producer<> UpdateChecker::ready() const {
|
||||
return _updater->ready();
|
||||
}
|
||||
|
||||
void UpdateChecker::start(bool forceWait) {
|
||||
_updater->start(forceWait);
|
||||
}
|
||||
|
||||
void UpdateChecker::stop() {
|
||||
_updater->stop();
|
||||
}
|
||||
|
||||
auto UpdateChecker::state() const
|
||||
-> State {
|
||||
return _updater->state();
|
||||
}
|
||||
|
||||
int UpdateChecker::already() const {
|
||||
return _updater->already();
|
||||
}
|
||||
|
||||
int UpdateChecker::size() const {
|
||||
return _updater->size();
|
||||
}
|
||||
|
||||
Updater::Private::Private(
|
||||
not_null<Updater*> parent,
|
||||
not_null<QThread*> thread,
|
||||
const QString &url)
|
||||
: _parent(parent) {
|
||||
_url = url;
|
||||
moveToThread(thread);
|
||||
_manager.moveToThread(thread);
|
||||
|
||||
connect(thread, &QThread::started, this, [=] { start(); });
|
||||
initOutput();
|
||||
}
|
||||
|
||||
void UpdateChecker::initOutput() {
|
||||
QString fileName;
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)")).match(updateUrl);
|
||||
if (m.hasMatch()) {
|
||||
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
|
||||
}
|
||||
if (fileName.isEmpty()) {
|
||||
fileName = qsl("tupdate-%1").arg(rand_value<uint32>() % 1000000);
|
||||
}
|
||||
QString dirStr = cWorkingDir() + qsl("tupdates/");
|
||||
fileName = dirStr + fileName;
|
||||
QFileInfo file(fileName);
|
||||
void Updater::Private::initOutput() {
|
||||
auto fileName = QString();
|
||||
const auto nameRegExp = QRegularExpression(qsl("/([^/\\?]+)(\\?|$)"));
|
||||
const auto nameMatch = nameRegExp.match(_url);
|
||||
|
||||
QDir dir(dirStr);
|
||||
if (nameMatch.hasMatch()) {
|
||||
fileName = nameMatch.captured(1).replace(
|
||||
QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")),
|
||||
QString());
|
||||
} else if (fileName.isEmpty()) {
|
||||
fileName = qsl("tupdate-%1").arg(rand() % 1000000);
|
||||
}
|
||||
const auto folder = cWorkingDir() + qsl("tupdates/");
|
||||
const auto finalName = folder + fileName;
|
||||
|
||||
QFileInfo info(finalName);
|
||||
QDir dir(folder);
|
||||
if (dir.exists()) {
|
||||
QFileInfoList all = dir.entryInfoList(QDir::Files);
|
||||
for (QFileInfoList::iterator i = all.begin(), e = all.end(); i != e; ++i) {
|
||||
if (i->absoluteFilePath() != file.absoluteFilePath()) {
|
||||
const auto all = dir.entryInfoList(QDir::Files);
|
||||
for (auto i = all.begin(), e = all.end(); i != e; ++i) {
|
||||
if (i->absoluteFilePath() != info.absoluteFilePath()) {
|
||||
QFile::remove(i->absoluteFilePath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dir.mkdir(dir.absolutePath());
|
||||
}
|
||||
outputFile.setFileName(fileName);
|
||||
if (file.exists()) {
|
||||
uint64 fullSize = file.size();
|
||||
_output.setFileName(finalName);
|
||||
if (info.exists()) {
|
||||
uint64 fullSize = info.size();
|
||||
if (fullSize < INT_MAX) {
|
||||
int32 goodSize = (int32)fullSize;
|
||||
if (goodSize % UpdateChunk) {
|
||||
goodSize = goodSize - (goodSize % UpdateChunk);
|
||||
if (goodSize) {
|
||||
if (outputFile.open(QIODevice::ReadOnly)) {
|
||||
QByteArray goodData = outputFile.readAll().mid(0, goodSize);
|
||||
outputFile.close();
|
||||
if (outputFile.open(QIODevice::WriteOnly)) {
|
||||
outputFile.write(goodData);
|
||||
outputFile.close();
|
||||
if (_output.open(QIODevice::ReadOnly)) {
|
||||
QByteArray goodData = _output.readAll().mid(0, goodSize);
|
||||
_output.close();
|
||||
if (_output.open(QIODevice::WriteOnly)) {
|
||||
_output.write(goodData);
|
||||
_output.close();
|
||||
|
||||
QMutexLocker lock(&mutex);
|
||||
already = goodSize;
|
||||
QMutexLocker lock(&_mutex);
|
||||
_already = goodSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QMutexLocker lock(&mutex);
|
||||
already = goodSize;
|
||||
QMutexLocker lock(&_mutex);
|
||||
_already = goodSize;
|
||||
}
|
||||
}
|
||||
if (!already) {
|
||||
QFile::remove(fileName);
|
||||
if (!_already) {
|
||||
QFile::remove(finalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateChecker::start() {
|
||||
void Updater::Private::start() {
|
||||
sendRequest();
|
||||
}
|
||||
|
||||
void UpdateChecker::sendRequest() {
|
||||
QNetworkRequest req(updateUrl);
|
||||
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(already) + "-";
|
||||
req.setRawHeader("Range", rangeHeaderValue);
|
||||
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
|
||||
if (reply) reply->deleteLater();
|
||||
reply = manager.get(req);
|
||||
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(partFinished(qint64,qint64)));
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(partFailed(QNetworkReply::NetworkError)));
|
||||
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(partMetaGot()));
|
||||
void Updater::Private::sendRequest() {
|
||||
auto request = QNetworkRequest(_url);
|
||||
const auto rangeHeaderValue = "bytes="
|
||||
+ QByteArray::number(_already)
|
||||
+ "-";
|
||||
request.setRawHeader("Range", rangeHeaderValue);
|
||||
request.setAttribute(
|
||||
QNetworkRequest::HttpPipeliningAllowedAttribute,
|
||||
true);
|
||||
_reply.reset(_manager.get(request));
|
||||
connect(
|
||||
_reply.get(),
|
||||
&QNetworkReply::downloadProgress,
|
||||
this,
|
||||
&Private::partFinished);
|
||||
connect(_reply.get(), QNetworkReply_error, [=](auto error) {
|
||||
partFailed(error);
|
||||
});
|
||||
connect(_reply.get(), &QNetworkReply::metaDataChanged, [=] {
|
||||
gotMetaData();
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateChecker::partMetaGot() {
|
||||
typedef QList<QNetworkReply::RawHeaderPair> Pairs;
|
||||
Pairs pairs = reply->rawHeaderPairs();
|
||||
for (Pairs::iterator i = pairs.begin(), e = pairs.end(); i != e; ++i) {
|
||||
if (QString::fromUtf8(i->first).toLower() == "content-range") {
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(i->second));
|
||||
void Updater::Private::gotMetaData() {
|
||||
const auto pairs = _reply->rawHeaderPairs();
|
||||
for (const auto pair : pairs) {
|
||||
if (QString::fromUtf8(pair.first).toLower() == "content-range") {
|
||||
const auto m = QRegularExpression(qsl("/(\\d+)([^\\d]|$)")).match(QString::fromUtf8(pair.second));
|
||||
if (m.hasMatch()) {
|
||||
{
|
||||
QMutexLocker lock(&mutex);
|
||||
full = m.captured(1).toInt();
|
||||
QMutexLocker lock(&_mutex);
|
||||
_size = m.captured(1).toInt();
|
||||
}
|
||||
|
||||
Sandbox::updateProgress(already, full);
|
||||
_parent->onProgress({ _already, _size });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 UpdateChecker::ready() {
|
||||
QMutexLocker lock(&mutex);
|
||||
return already;
|
||||
int Updater::Private::already() const {
|
||||
QMutexLocker lock(&_mutex);
|
||||
return _already;
|
||||
}
|
||||
|
||||
int32 UpdateChecker::size() {
|
||||
QMutexLocker lock(&mutex);
|
||||
return full;
|
||||
int Updater::Private::size() const {
|
||||
QMutexLocker lock(&_mutex);
|
||||
return _size;
|
||||
}
|
||||
|
||||
void UpdateChecker::partFinished(qint64 got, qint64 total) {
|
||||
if (!reply) return;
|
||||
void Updater::Private::partFinished(qint64 got, qint64 total) {
|
||||
if (!_reply) return;
|
||||
|
||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
QVariant statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
if (statusCode.isValid()) {
|
||||
int status = statusCode.toInt();
|
||||
if (status != 200 && status != 206 && status != 416) {
|
||||
@ -152,60 +579,55 @@ void UpdateChecker::partFinished(qint64 got, qint64 total) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!already && !full) {
|
||||
QMutexLocker lock(&mutex);
|
||||
full = total;
|
||||
if (!_already && !_size) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
_size = total;
|
||||
}
|
||||
DEBUG_LOG(("Update Info: part %1 of %2").arg(got).arg(total));
|
||||
|
||||
if (!outputFile.isOpen()) {
|
||||
if (!outputFile.open(QIODevice::Append)) {
|
||||
LOG(("Update Error: Could not open output file '%1' for appending").arg(outputFile.fileName()));
|
||||
if (!_output.isOpen()) {
|
||||
if (!_output.open(QIODevice::Append)) {
|
||||
LOG(("Update Error: Could not open output file '%1' for appending").arg(_output.fileName()));
|
||||
return fatalFail();
|
||||
}
|
||||
}
|
||||
QByteArray r = reply->readAll();
|
||||
QByteArray r = _reply->readAll();
|
||||
if (!r.isEmpty()) {
|
||||
outputFile.write(r);
|
||||
_output.write(r);
|
||||
|
||||
QMutexLocker lock(&mutex);
|
||||
already += r.size();
|
||||
QMutexLocker lock(&_mutex);
|
||||
_already += r.size();
|
||||
}
|
||||
if (got >= total) {
|
||||
reply->deleteLater();
|
||||
reply = 0;
|
||||
outputFile.close();
|
||||
_reply.release()->deleteLater();
|
||||
_output.close();
|
||||
unpackUpdate();
|
||||
} else {
|
||||
Sandbox::updateProgress(already, full);
|
||||
_parent->onProgress({ _already, _size });
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateChecker::partFailed(QNetworkReply::NetworkError e) {
|
||||
if (!reply) return;
|
||||
void Updater::Private::partFailed(QNetworkReply::NetworkError e) {
|
||||
if (!_reply) return;
|
||||
|
||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
reply->deleteLater();
|
||||
reply = 0;
|
||||
const auto statusCode = _reply->attribute(
|
||||
QNetworkRequest::HttpStatusCodeAttribute);
|
||||
_reply.release()->deleteLater();
|
||||
if (statusCode.isValid()) {
|
||||
int status = statusCode.toInt();
|
||||
if (status == 416) { // Requested range not satisfiable
|
||||
outputFile.close();
|
||||
_output.close();
|
||||
unpackUpdate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG(("Update Error: failed to download part starting from %1, error %2").arg(already).arg(e));
|
||||
Sandbox::updateFailed();
|
||||
LOG(("Update Error: failed to download part starting from %1, error %2").arg(_already).arg(e));
|
||||
_parent->onFailed();
|
||||
}
|
||||
|
||||
void UpdateChecker::fatalFail() {
|
||||
clearAll();
|
||||
Sandbox::updateFailed();
|
||||
}
|
||||
|
||||
void UpdateChecker::clearAll() {
|
||||
psDeleteDir(cWorkingDir() + qsl("tupdates"));
|
||||
void Updater::Private::fatalFail() {
|
||||
ClearAll();
|
||||
_parent->onFailed();
|
||||
}
|
||||
|
||||
//QString winapiErrorWrap() {
|
||||
@ -223,9 +645,9 @@ void UpdateChecker::clearAll() {
|
||||
// return QString::fromWCharArray(errMsg);
|
||||
//}
|
||||
|
||||
void UpdateChecker::unpackUpdate() {
|
||||
void Updater::Private::unpackUpdate() {
|
||||
QByteArray packed;
|
||||
if (!outputFile.open(QIODevice::ReadOnly)) {
|
||||
if (!_output.open(QIODevice::ReadOnly)) {
|
||||
LOG(("Update Error: cant read updates file!"));
|
||||
return fatalFail();
|
||||
}
|
||||
@ -236,13 +658,13 @@ void UpdateChecker::unpackUpdate() {
|
||||
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
QByteArray compressed = outputFile.readAll();
|
||||
QByteArray compressed = _output.readAll();
|
||||
int32 compressedLen = compressed.size() - hSize;
|
||||
if (compressedLen <= 0) {
|
||||
LOG(("Update Error: bad compressed size: %1").arg(compressed.size()));
|
||||
return fatalFail();
|
||||
}
|
||||
outputFile.close();
|
||||
_output.close();
|
||||
|
||||
QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready");
|
||||
psDeleteDir(tempDirPath);
|
||||
@ -429,8 +851,9 @@ void UpdateChecker::unpackUpdate() {
|
||||
tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath());
|
||||
std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString();
|
||||
|
||||
VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar));
|
||||
VerChar versionStr[32];
|
||||
const auto versionNum = VersionInt(version);
|
||||
const auto versionLen = VersionInt(versionString.size() * sizeof(VersionChar));
|
||||
VersionChar versionStr[32];
|
||||
memcpy(versionStr, versionString.c_str(), versionLen);
|
||||
|
||||
QFile fVersion(tempDirPath + qsl("/tdata/version"));
|
||||
@ -438,11 +861,11 @@ void UpdateChecker::unpackUpdate() {
|
||||
LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version")));
|
||||
return fatalFail();
|
||||
}
|
||||
fVersion.write((const char*)&versionNum, sizeof(VerInt));
|
||||
fVersion.write((const char*)&versionNum, sizeof(VersionInt));
|
||||
if (versionNum == 0x7FFFFFFF) { // beta version
|
||||
fVersion.write((const char*)&betaVersion, sizeof(quint64));
|
||||
} else {
|
||||
fVersion.write((const char*)&versionLen, sizeof(VerInt));
|
||||
fVersion.write((const char*)&versionLen, sizeof(VersionInt));
|
||||
fVersion.write((const char*)&versionStr[0], versionLen);
|
||||
}
|
||||
fVersion.close();
|
||||
@ -460,21 +883,16 @@ void UpdateChecker::unpackUpdate() {
|
||||
LOG(("Update Error: cant create ready file '%1'").arg(readyFilePath));
|
||||
return fatalFail();
|
||||
}
|
||||
outputFile.remove();
|
||||
_output.remove();
|
||||
|
||||
Sandbox::updateReady();
|
||||
}
|
||||
|
||||
UpdateChecker::~UpdateChecker() {
|
||||
delete reply;
|
||||
reply = 0;
|
||||
_parent->onReady();
|
||||
}
|
||||
|
||||
bool checkReadyUpdate() {
|
||||
QString readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"), readyPath = cWorkingDir() + qsl("tupdates/temp");
|
||||
if (!QFile(readyFilePath).exists() || cExeName().isEmpty()) {
|
||||
if (QDir(cWorkingDir() + qsl("tupdates/ready")).exists() || QDir(cWorkingDir() + qsl("tupdates/temp")).exists()) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -485,30 +903,30 @@ bool checkReadyUpdate() {
|
||||
QFile fVersion(versionPath);
|
||||
if (!fVersion.open(QIODevice::ReadOnly)) {
|
||||
LOG(("Update Error: cant read version file '%1'").arg(versionPath));
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
VerInt versionNum;
|
||||
if (fVersion.read((char*)&versionNum, sizeof(VerInt)) != sizeof(VerInt)) {
|
||||
auto versionNum = VersionInt();
|
||||
if (fVersion.read((char*)&versionNum, sizeof(VersionInt)) != sizeof(VersionInt)) {
|
||||
LOG(("Update Error: cant read version from file '%1'").arg(versionPath));
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
if (versionNum == 0x7FFFFFFF) { // beta version
|
||||
quint64 betaVersion = 0;
|
||||
if (fVersion.read((char*)&betaVersion, sizeof(quint64)) != sizeof(quint64)) {
|
||||
LOG(("Update Error: cant read beta version from file '%1'").arg(versionPath));
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
if (!cBetaVersion() || betaVersion <= cBetaVersion()) {
|
||||
LOG(("Update Error: cant install beta version %1 having beta version %2").arg(betaVersion).arg(cBetaVersion()));
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
} else if (versionNum <= AppVersion) {
|
||||
LOG(("Update Error: cant install version %1 having version %2").arg(versionNum).arg(AppVersion));
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
fVersion.close();
|
||||
@ -527,11 +945,11 @@ bool checkReadyUpdate() {
|
||||
if (!updater.exists()) {
|
||||
QFileInfo current(curUpdater);
|
||||
if (!current.exists()) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
if (!QFile(current.absoluteFilePath()).copy(updater.absoluteFilePath())) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -542,24 +960,24 @@ bool checkReadyUpdate() {
|
||||
cSetWriteProtected(true);
|
||||
return true;
|
||||
} else {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
||||
QDir().mkpath(QFileInfo(curUpdater).absolutePath());
|
||||
DEBUG_LOG(("Update Info: moving %1 to %2...").arg(updater.absoluteFilePath()).arg(curUpdater));
|
||||
if (!objc_moveFile(updater.absoluteFilePath(), curUpdater)) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
#elif defined Q_OS_LINUX // Q_OS_MAC
|
||||
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
|
||||
UpdateChecker::clearAll();
|
||||
ClearAll();
|
||||
return false;
|
||||
}
|
||||
#endif // Q_OS_LINUX
|
||||
@ -611,3 +1029,5 @@ QString countBetaVersionSignature(uint64 version) { // duplicated in packer.cpp
|
||||
signature = signature.replace('-', '8').replace('_', 'B');
|
||||
return QString::fromUtf8(signature.mid(19, 32));
|
||||
}
|
||||
|
||||
} // namespace Core
|
58
Telegram/SourceFiles/core/update_checker.h
Normal file
58
Telegram/SourceFiles/core/update_checker.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
class Updater;
|
||||
|
||||
class UpdateChecker {
|
||||
public:
|
||||
enum class State {
|
||||
None,
|
||||
Download,
|
||||
Ready,
|
||||
};
|
||||
struct Progress {
|
||||
int64 already;
|
||||
int64 size;
|
||||
};
|
||||
|
||||
UpdateChecker();
|
||||
|
||||
rpl::producer<> checking() const;
|
||||
rpl::producer<> isLatest() const;
|
||||
rpl::producer<Progress> progress() const;
|
||||
rpl::producer<> failed() const;
|
||||
rpl::producer<> ready() const;
|
||||
|
||||
void start(bool forceWait = false);
|
||||
void stop();
|
||||
|
||||
State state() const;
|
||||
int already() const;
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
const std::shared_ptr<Updater> _updater;
|
||||
|
||||
};
|
||||
|
||||
bool checkReadyUpdate();
|
||||
|
||||
#else // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
class UpdateChecker {
|
||||
};
|
||||
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
QString countBetaVersionSignature(uint64 version);
|
||||
|
||||
} // namespace Core
|
@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "application.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "autoupdater.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "auth_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "messenger.h"
|
||||
@ -119,10 +119,15 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
|
||||
connect(_filter, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onFilterCursorMoved(int,int)));
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onCheckUpdateStatus()));
|
||||
onCheckUpdateStatus();
|
||||
Core::UpdateChecker checker;
|
||||
rpl::merge(
|
||||
rpl::single(rpl::empty_value()),
|
||||
checker.isLatest(),
|
||||
checker.failed(),
|
||||
checker.ready()
|
||||
) | rpl::start_with_next([=] {
|
||||
checkUpdateStatus();
|
||||
}, lifetime());
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
subscribe(Adaptive::Changed(), [this] { updateForwardBar(); });
|
||||
@ -168,13 +173,14 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void DialogsWidget::onCheckUpdateStatus() {
|
||||
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
||||
void DialogsWidget::checkUpdateStatus() {
|
||||
using Checker = Core::UpdateChecker;
|
||||
if (Checker().state() == Checker::State::Ready) {
|
||||
if (_updateTelegram) return;
|
||||
_updateTelegram.create(this);
|
||||
_updateTelegram->show();
|
||||
_updateTelegram->setClickedCallback([] {
|
||||
checkReadyUpdate();
|
||||
Core::checkReadyUpdate();
|
||||
App::restart();
|
||||
});
|
||||
} else {
|
||||
|
@ -120,10 +120,6 @@ public slots:
|
||||
private slots:
|
||||
void onDraggingScrollTimer();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void onCheckUpdateStatus();
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *e) override;
|
||||
void dragMoveEvent(QDragMoveEvent *e) override;
|
||||
@ -167,6 +163,10 @@ private:
|
||||
void updateControlsGeometry();
|
||||
void updateForwardBar();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void checkUpdateStatus();
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
bool dialogsFailed(const RPCError &error, mtpRequestId req);
|
||||
bool searchFailed(DialogsSearchRequestType type, const RPCError &error, mtpRequestId req);
|
||||
bool peopleFailed(const RPCError &error, mtpRequestId req);
|
||||
|
@ -396,7 +396,7 @@ bool CheckBetaVersionDir() {
|
||||
quint64 v;
|
||||
QByteArray k;
|
||||
dataStream >> v >> k;
|
||||
if (dataStream.status() == QDataStream::Ok) {
|
||||
if (dataStream.status() == QDataStream::Ok && !k.isEmpty()) {
|
||||
cSetBetaVersion(qMax(v, AppVersion * 1000ULL));
|
||||
cSetBetaPrivateKey(k);
|
||||
cSetRealBetaVersion(v);
|
||||
|
@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/effects/slide_animation.h"
|
||||
#include "autoupdater.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "window/window_slide_animation.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_intro.h"
|
||||
@ -42,7 +42,7 @@ constexpr str_const kDefaultCountry = "US";
|
||||
|
||||
} // namespace
|
||||
|
||||
Widget::Widget(QWidget *parent) : TWidget(parent)
|
||||
Widget::Widget(QWidget *parent) : RpWidget(parent)
|
||||
, _back(this, object_ptr<Ui::IconButton>(this, st::introBackButton))
|
||||
, _settings(
|
||||
this,
|
||||
@ -82,10 +82,17 @@ Widget::Widget(QWidget *parent) : TWidget(parent)
|
||||
cSetPasswordRecovered(false);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::startUpdateCheck();
|
||||
Core::UpdateChecker checker;
|
||||
checker.isLatest() | rpl::start_with_next([=] {
|
||||
onCheckUpdateStatus();
|
||||
}, lifetime());
|
||||
checker.failed() | rpl::start_with_next([=] {
|
||||
onCheckUpdateStatus();
|
||||
}, lifetime());
|
||||
checker.ready() | rpl::start_with_next([=] {
|
||||
onCheckUpdateStatus();
|
||||
}, lifetime());
|
||||
checker.start();
|
||||
onCheckUpdateStatus();
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
}
|
||||
@ -132,7 +139,7 @@ void Widget::createLanguageLink() {
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void Widget::onCheckUpdateStatus() {
|
||||
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
||||
if (Core::UpdateChecker().state() == Core::UpdateChecker::State::Ready) {
|
||||
if (_update) return;
|
||||
_update.create(
|
||||
this,
|
||||
@ -144,7 +151,7 @@ void Widget::onCheckUpdateStatus() {
|
||||
_update->setVisible(true);
|
||||
}
|
||||
_update->entity()->setClickedCallback([] {
|
||||
checkReadyUpdate();
|
||||
Core::checkReadyUpdate();
|
||||
App::restart();
|
||||
});
|
||||
} else {
|
||||
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui {
|
||||
class IconButton;
|
||||
@ -22,7 +23,7 @@ class FadeWrap;
|
||||
|
||||
namespace Intro {
|
||||
|
||||
class Widget : public TWidget, private MTP::Sender, private base::Subscriber {
|
||||
class Widget : public Ui::RpWidget, private MTP::Sender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -74,6 +74,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "mtproto/dc_options.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "calls/calls_top_bar.h"
|
||||
#include "auth_session.h"
|
||||
@ -323,7 +324,8 @@ MainWidget::MainWidget(
|
||||
orderWidgets();
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
Sandbox::startUpdateCheck();
|
||||
Core::UpdateChecker checker;
|
||||
checker.start();
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
}
|
||||
|
||||
@ -704,7 +706,7 @@ void MainWidget::finishForwarding(not_null<History*> history) {
|
||||
}
|
||||
|
||||
void MainWidget::updateMutedIn(TimeMs delay) {
|
||||
accumulate_max(delay, 24 * 3600 * 1000LL);
|
||||
accumulate_min(delay, 24 * 3600 * 1000LL);
|
||||
if (!_updateMutedTimer.isActive()
|
||||
|| _updateMutedTimer.remainingTime() > delay) {
|
||||
_updateMutedTimer.start(delay);
|
||||
|
@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_file_parser.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "messenger.h"
|
||||
#include "autoupdater.h"
|
||||
#include "core/update_checker.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
@ -34,21 +34,37 @@ UpdateStateRow::UpdateStateRow(QWidget *parent) : RpWidget(parent)
|
||||
connect(_check, SIGNAL(clicked()), this, SLOT(onCheck()));
|
||||
connect(_restart, SIGNAL(clicked()), this, SIGNAL(restart()));
|
||||
|
||||
Sandbox::connect(SIGNAL(updateChecking()), this, SLOT(onChecking()));
|
||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onLatest()));
|
||||
Sandbox::connect(SIGNAL(updateProgress(qint64, qint64)), this, SLOT(onDownloading(qint64, qint64)));
|
||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onFailed()));
|
||||
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onReady()));
|
||||
|
||||
_versionText = lng_settings_current_version_label(lt_version, currentVersionText());
|
||||
|
||||
switch (Sandbox::updatingState()) {
|
||||
case Application::UpdatingDownload:
|
||||
Core::UpdateChecker checker;
|
||||
checker.checking() | rpl::start_with_next([=] {
|
||||
onChecking();
|
||||
}, lifetime());
|
||||
checker.isLatest() | rpl::start_with_next([=] {
|
||||
onLatest();
|
||||
}, lifetime());
|
||||
checker.progress(
|
||||
) | rpl::start_with_next([=](Core::UpdateChecker::Progress progress) {
|
||||
onDownloading(progress.already, progress.size);
|
||||
}, lifetime());
|
||||
checker.failed() | rpl::start_with_next([=] {
|
||||
onFailed();
|
||||
}, lifetime());
|
||||
checker.ready() | rpl::start_with_next([=] {
|
||||
onReady();
|
||||
}, lifetime());
|
||||
|
||||
switch (checker.state()) {
|
||||
case Core::UpdateChecker::State::Download:
|
||||
setState(State::Download, true);
|
||||
setDownloadProgress(Sandbox::updatingReady(), Sandbox::updatingSize());
|
||||
break;
|
||||
case Application::UpdatingReady: setState(State::Ready, true); break;
|
||||
default: setState(State::None, true); break;
|
||||
setDownloadProgress(checker.already(), checker.size());
|
||||
break;
|
||||
case Core::UpdateChecker::State::Ready:
|
||||
setState(State::Ready, true);
|
||||
break;
|
||||
default:
|
||||
setState(State::None, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +105,11 @@ void UpdateStateRow::paintEvent(QPaintEvent *e) {
|
||||
void UpdateStateRow::onCheck() {
|
||||
if (!cAutoUpdate()) return;
|
||||
|
||||
Core::UpdateChecker checker;
|
||||
|
||||
setState(State::Check);
|
||||
cSetLastUpdateCheck(0);
|
||||
Sandbox::startUpdateCheck();
|
||||
checker.start();
|
||||
}
|
||||
|
||||
void UpdateStateRow::setState(State state, bool force) {
|
||||
@ -212,7 +230,7 @@ void GeneralWidget::onChangeLanguage() {
|
||||
|
||||
void GeneralWidget::onRestart() {
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
checkReadyUpdate();
|
||||
Core::checkReadyUpdate();
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
App::restart();
|
||||
}
|
||||
@ -224,10 +242,11 @@ void GeneralWidget::onUpdateAutomatically() {
|
||||
_updateRow->toggle(
|
||||
cAutoUpdate(),
|
||||
anim::type::normal);
|
||||
Core::UpdateChecker checker;
|
||||
if (cAutoUpdate()) {
|
||||
Sandbox::startUpdateCheck();
|
||||
checker.start();
|
||||
} else {
|
||||
Sandbox::stopUpdate();
|
||||
checker.stop();
|
||||
}
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/send_files_box.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "observer_peer.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
@ -1251,7 +1252,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
||||
cSetAutoUpdate(v == 1);
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
if (!cAutoUpdate()) {
|
||||
Sandbox::stopUpdate();
|
||||
Core::UpdateChecker().stop();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
|
||||
} break;
|
||||
|
@ -158,6 +158,8 @@
|
||||
<(src_loc)/core/single_timer.cpp
|
||||
<(src_loc)/core/single_timer.h
|
||||
<(src_loc)/core/tl_help.h
|
||||
<(src_loc)/core/update_checker.cpp
|
||||
<(src_loc)/core/update_checker.h
|
||||
<(src_loc)/core/utils.cpp
|
||||
<(src_loc)/core/utils.h
|
||||
<(src_loc)/core/version.h
|
||||
@ -725,8 +727,6 @@
|
||||
<(src_loc)/application.h
|
||||
<(src_loc)/auth_session.cpp
|
||||
<(src_loc)/auth_session.h
|
||||
<(src_loc)/autoupdater.cpp
|
||||
<(src_loc)/autoupdater.h
|
||||
<(src_loc)/config.h
|
||||
<(src_loc)/countries.h
|
||||
<(src_loc)/facades.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user