Skip to content

Commit

Permalink
Updater: Manual and automatic update checks
Browse files Browse the repository at this point in the history
If enough time has passed, do an automatic check when launching.
On Mac OS X, the app menu can be used to check for updates
manually.

Todo: Checking via console command and Control Panel.
  • Loading branch information
skyjake committed Jun 6, 2012
1 parent 6c8378c commit 3fa515a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 13 deletions.
12 changes: 12 additions & 0 deletions doomsday/engine/portable/include/updater.h
Expand Up @@ -43,12 +43,18 @@ class Updater : public QObject
public slots:
void gotReply(QNetworkReply*);
void downloadCompleted(int result);
void checkNow();

private:
struct Instance;
Instance* d;
};

/**
* @return Returns the singleton Updater instance.
*/
Updater* Updater_Instance();

#endif // __cplusplus

#ifdef __cplusplus
Expand All @@ -67,6 +73,12 @@ void Updater_Init(void);
*/
void Updater_Shutdown(void);

/**
* Tells the updater to check for updates now. This is called when a manual
* check is requested.
*/
void Updater_CheckNow(void);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
21 changes: 18 additions & 3 deletions doomsday/engine/portable/src/dd_init.cpp
Expand Up @@ -58,6 +58,8 @@

#include <QApplication>
#include <QSettings>
#include <QAction>
#include <QMenuBar>
#include <QNetworkProxyFactory>
#include <QDebug>
#include <stdlib.h>
Expand Down Expand Up @@ -95,9 +97,6 @@ LegacyCore* de2LegacyCore;

static void continueInitWithEventLoopRunning(void)
{
// Check for updates automatically.
Updater_Init();

// This function only needs to be called once, so clear the callback.
LegacyCore_SetLoopFunc(de2LegacyCore, 0);

Expand Down Expand Up @@ -154,9 +153,23 @@ int main(int argc, char** argv)
de2LegacyCore = LegacyCore_New(&dengApp);
LegacyCore_SetTerminateFunc(de2LegacyCore, handleLegacyCoreTerminate);

QMenuBar* menuBar = 0;
if(useGUI)
{
DisplayMode_Init();

// Check for updates automatically.
Updater_Init();

#ifdef MACOSX
// Set up the application-wide menu.
menuBar = new QMenuBar;

QMenu* gameMenu = menuBar->addMenu("&Game");

QAction* checkForUpdates = gameMenu->addAction("Check For &Updates...", Updater_Instance(), SLOT(checkNow()));
checkForUpdates->setMenuRole(QAction::ApplicationSpecificRole);
#endif
}

// Initialize.
Expand All @@ -181,5 +194,7 @@ int main(int argc, char** argv)
DD_Shutdown();
LegacyCore_Delete(de2LegacyCore);

delete menuBar;

return result;
}
92 changes: 82 additions & 10 deletions doomsday/engine/portable/src/updater.cpp
Expand Up @@ -85,6 +85,7 @@ struct Updater::Instance
Updater* self;
QNetworkAccessManager* network;
DownloadDialog* download;
bool alwaysShowNotification;

VersionInfo latestVersion;
QString latestPackageUri;
Expand All @@ -97,6 +98,8 @@ struct Updater::Instance

~Instance()
{
// Delete the ongoing download.
if(download) delete download;
}

QString composeCheckUri()
Expand All @@ -111,9 +114,52 @@ struct Updater::Instance
return uri;
}

void queryLatestVersion()
bool shouldCheckForUpdate() const
{
UpdaterSettings st;
float dayInterval;

switch(st.frequency())
{
case UpdaterSettings::Daily:
dayInterval = 1;
break;

case UpdaterSettings::Biweekly:
dayInterval = 5;
break;

case UpdaterSettings::Weekly:
dayInterval = 7;
break;

default:
dayInterval = 30;
break;
}

de::Time now;

// Check always when the day interval has passed.
if(st.lastCheckTime().deltaTo(now).asDays() >= dayInterval)
return true;

if(st.frequency() == UpdaterSettings::Biweekly)
{
// Check on Tuesday and Saturday, as the builds are usually on
// Monday and Friday.
int weekday = now.asDateTime().date().dayOfWeek();
if(weekday == 2 || weekday == 6) return true;
}

// No need to check right now.
return false;
}

void queryLatestVersion(bool notifyAlways)
{
UpdaterSettings().setLastCheckTime(de::Time());
alwaysShowNotification = notifyAlways;
network->get(QNetworkRequest(composeCheckUri()));
}

Expand All @@ -130,23 +176,27 @@ struct Updater::Instance

latestVersion = VersionInfo(map["version"].toString(), map["build_uniqueid"].toInt());

VersionInfo currentVersion;

LOG_VERBOSE("Received latest version information:\n"
" - version: %s (running %s)\n"
" - package: %s\n"
" - change log: %s")
<< latestVersion.asText()
<< VersionInfo().asText()
<< currentVersion.asText()
<< latestPackageUri << latestLogUri;

// Is this newer than what we're running?
// TODO: Silent check flag.
UpdateAvailableDialog dlg(latestVersion, latestLogUri);
if(dlg.exec())
if(latestVersion > currentVersion || alwaysShowNotification)
{
LOG_MSG("Download and install.");
download = new DownloadDialog(latestPackageUri);
QObject::connect(download, SIGNAL(finished(int)), self, SLOT(downloadCompleted(int)));
download->show();
UpdateAvailableDialog dlg(latestVersion, latestLogUri);
if(dlg.exec())
{
LOG_MSG("Download and install.");
download = new DownloadDialog(latestPackageUri);
QObject::connect(download, SIGNAL(finished(int)), self, SLOT(downloadCompleted(int)));
download->show();
}
}
}

Expand Down Expand Up @@ -239,7 +289,11 @@ Updater::Updater(QObject *parent) : QObject(parent)
d = new Instance(this);
connect(d->network, SIGNAL(finished(QNetworkReply*)), this, SLOT(gotReply(QNetworkReply*)));

d->queryLatestVersion();
// Do a silent auto-update check when starting.
if(d->shouldCheckForUpdate())
{
d->queryLatestVersion(false);
}
}

Updater::~Updater()
Expand Down Expand Up @@ -269,6 +323,14 @@ void Updater::downloadCompleted(int result)
d->download = 0;
}

void Updater::checkNow()
{
// Not if there is an ongoing download.
if(d->download) return;

d->queryLatestVersion(true /* manual check: show notification always */);
}

void Updater_Init(void)
{
updater = new Updater;
Expand All @@ -278,3 +340,13 @@ void Updater_Shutdown(void)
{
delete updater;
}

Updater* Updater_Instance(void)
{
return updater;
}

void Updater_CheckNow(void)
{
updater->checkNow();
}

0 comments on commit 3fa515a

Please sign in to comment.