@@ -21,26 +21,25 @@ struct Update { | |||||
}; | }; | ||||
extern std::string version; | |||||
extern std::string changelogUrl; | |||||
extern float progress; | |||||
void init(); | void init(); | ||||
void destroy(); | |||||
bool isAppUpdateAvailable(); | |||||
bool isLoggedIn(); | bool isLoggedIn(); | ||||
void logIn(const std::string& email, const std::string& password); | void logIn(const std::string& email, const std::string& password); | ||||
void logOut(); | void logOut(); | ||||
bool isUpdateAvailable(); | |||||
void queryUpdates(); | void queryUpdates(); | ||||
bool hasUpdates(); | bool hasUpdates(); | ||||
void syncUpdate(Update* update); | void syncUpdate(Update* update); | ||||
void syncUpdates(); | void syncUpdates(); | ||||
bool isSyncing(); | bool isSyncing(); | ||||
/** Updates Rack automatically or opens the browser to the URL. | |||||
Blocking. Call on a detached thread. | |||||
*/ | |||||
void update(); | |||||
extern std::string appVersion; | |||||
extern std::string appDownloadUrl; | |||||
extern std::string appChangelogUrl; | |||||
extern std::string loginStatus; | extern std::string loginStatus; | ||||
extern std::vector<Update> updates; | extern std::vector<Update> updates; | ||||
extern std::string updateStatus; | extern std::string updateStatus; | ||||
@@ -817,30 +817,21 @@ struct LibraryButton : MenuButton { | |||||
// Help | // Help | ||||
//////////////////// | //////////////////// | ||||
struct UpdateItem : ui::MenuItem { | |||||
struct AppUpdateItem : ui::MenuItem { | |||||
ui::Menu* createChildMenu() override { | ui::Menu* createChildMenu() override { | ||||
ui::Menu* menu = new ui::Menu; | ui::Menu* menu = new ui::Menu; | ||||
UrlItem* changelogUrl = new UrlItem; | |||||
changelogUrl->text = "Changelog"; | |||||
changelogUrl->url = library::changelogUrl; | |||||
menu->addChild(changelogUrl); | |||||
UrlItem* changelogItem = new UrlItem; | |||||
changelogItem->text = "Changelog"; | |||||
changelogItem->url = library::appChangelogUrl; | |||||
menu->addChild(changelogItem); | |||||
return menu; | return menu; | ||||
} | } | ||||
void step() override { | |||||
if (library::progress > 0) { | |||||
rightText = string::f("%.0f%%", library::progress * 100.f); | |||||
} | |||||
MenuItem::step(); | |||||
} | |||||
void onAction(const event::Action& e) override { | void onAction(const event::Action& e) override { | ||||
std::thread t([ = ] { | |||||
library::update(); | |||||
}); | |||||
t.detach(); | |||||
system::openBrowser(library::appDownloadUrl); | |||||
APP->window->close(); | |||||
e.consume(NULL); | e.consume(NULL); | ||||
} | } | ||||
}; | }; | ||||
@@ -859,11 +850,11 @@ struct HelpButton : MenuButton { | |||||
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
if (library::isUpdateAvailable()) { | |||||
UpdateItem* updateItem = new UpdateItem; | |||||
updateItem->text = "Update " + APP_NAME; | |||||
updateItem->rightText = APP_VERSION + " → " + library::version; | |||||
menu->addChild(updateItem); | |||||
if (library::isAppUpdateAvailable()) { | |||||
AppUpdateItem* appUpdateItem = new AppUpdateItem; | |||||
appUpdateItem->text = "Update " + APP_NAME; | |||||
appUpdateItem->rightText = APP_VERSION + " → " + library::appVersion; | |||||
menu->addChild(appUpdateItem); | |||||
} | } | ||||
UrlItem* manualItem = new UrlItem; | UrlItem* manualItem = new UrlItem; | ||||
@@ -885,7 +876,7 @@ struct HelpButton : MenuButton { | |||||
void step() override { | void step() override { | ||||
notification->box.pos = math::Vec(0, 0); | notification->box.pos = math::Vec(0, 0); | ||||
notification->visible = library::isUpdateAvailable(); | |||||
notification->visible = library::isAppUpdateAvailable(); | |||||
MenuButton::step(); | MenuButton::step(); | ||||
} | } | ||||
}; | }; | ||||
@@ -16,13 +16,30 @@ namespace rack { | |||||
namespace library { | namespace library { | ||||
std::string version; | |||||
std::string changelogUrl; | |||||
float progress = 0.f; | |||||
static std::string downloadUrl; | |||||
static void queryAppUpdate(); | |||||
static void checkVersion() { | |||||
void init() { | |||||
if (settings::devMode) | |||||
return; | |||||
std::thread t([&]() { | |||||
queryAppUpdate(); | |||||
}); | |||||
t.detach(); | |||||
std::thread t2([&] { | |||||
queryUpdates(); | |||||
}); | |||||
t2.detach(); | |||||
} | |||||
void destroy() { | |||||
} | |||||
static void queryAppUpdate() { | |||||
std::string versionUrl = API_URL + "/version"; | std::string versionUrl = API_URL + "/version"; | ||||
json_t* resJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); | json_t* resJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); | ||||
if (!resJ) { | if (!resJ) { | ||||
@@ -33,37 +50,23 @@ static void checkVersion() { | |||||
json_t* versionJ = json_object_get(resJ, "version"); | json_t* versionJ = json_object_get(resJ, "version"); | ||||
if (versionJ) | if (versionJ) | ||||
version = json_string_value(versionJ); | |||||
appVersion = json_string_value(versionJ); | |||||
json_t* changelogUrlJ = json_object_get(resJ, "changelogUrl"); | json_t* changelogUrlJ = json_object_get(resJ, "changelogUrl"); | ||||
if (changelogUrlJ) | if (changelogUrlJ) | ||||
changelogUrl = json_string_value(changelogUrlJ); | |||||
appChangelogUrl = json_string_value(changelogUrlJ); | |||||
json_t* downloadUrlsJ = json_object_get(resJ, "downloadUrls"); | json_t* downloadUrlsJ = json_object_get(resJ, "downloadUrls"); | ||||
if (downloadUrlsJ) { | if (downloadUrlsJ) { | ||||
json_t* downloadUrlJ = json_object_get(downloadUrlsJ, APP_ARCH.c_str()); | json_t* downloadUrlJ = json_object_get(downloadUrlsJ, APP_ARCH.c_str()); | ||||
if (downloadUrlJ) | if (downloadUrlJ) | ||||
downloadUrl = json_string_value(downloadUrlJ); | |||||
appDownloadUrl = json_string_value(downloadUrlJ); | |||||
} | } | ||||
} | } | ||||
void init() { | |||||
if (settings::devMode) | |||||
return; | |||||
std::thread t([]() { | |||||
checkVersion(); | |||||
}); | |||||
t.detach(); | |||||
// Sync in a detached thread | |||||
if (!settings::devMode) { | |||||
std::thread t([] { | |||||
queryUpdates(); | |||||
}); | |||||
t.detach(); | |||||
} | |||||
bool isAppUpdateAvailable() { | |||||
return (appVersion != "") && (appVersion != APP_VERSION); | |||||
} | } | ||||
@@ -115,49 +118,6 @@ void logOut() { | |||||
} | } | ||||
void update() { | |||||
if (downloadUrl == "") | |||||
return; | |||||
// Download update | |||||
// HACK getFilename is only supposed to be used for filesystem paths, not URLs. | |||||
std::string filename = system::getFilename(network::urlPath(downloadUrl)); | |||||
std::string path = asset::user(filename); | |||||
INFO("Downloading update %s to %s", downloadUrl.c_str(), path.c_str()); | |||||
network::requestDownload(downloadUrl, path, &progress); | |||||
#if defined ARCH_WIN | |||||
// Launch the installer | |||||
INFO("Launching update %s", path.c_str()); | |||||
system::runProcessDetached(path); | |||||
#elif defined ARCH_MAC | |||||
std::string cmd; | |||||
// std::string appPath = system::join(asset::userDir, "Rack.app"); | |||||
// cmd = "rm -rf '" + appPath + "'"; | |||||
// std::system(cmd.c_str()); | |||||
// // Unzip app using Apple's unzipper, since Rack's unzipper doesn't handle the metadata stuff correctly. | |||||
// cmd = "unzip -q '" + path + "' -d '" + asset::userDir + "'"; | |||||
// std::system(cmd.c_str()); | |||||
// // Open app in Finder | |||||
// cmd = "open -R '" + appPath + "'"; | |||||
// std::system(cmd.c_str()); | |||||
// Open Archive Utility | |||||
cmd = "open '" + path + "'"; | |||||
std::system(cmd.c_str()); | |||||
#elif defined ARCH_LIN | |||||
system::openFolder(asset::user("")); | |||||
#endif | |||||
APP->window->close(); | |||||
} | |||||
bool isUpdateAvailable() { | |||||
return (version != "") && (version != APP_VERSION); | |||||
} | |||||
void queryUpdates() { | void queryUpdates() { | ||||
if (settings::token.empty()) | if (settings::token.empty()) | ||||
return; | return; | ||||
@@ -354,6 +314,10 @@ std::vector<Update> updates; | |||||
std::string updateStatus; | std::string updateStatus; | ||||
bool restartRequested = false; | bool restartRequested = false; | ||||
std::string appVersion; | |||||
std::string appDownloadUrl; | |||||
std::string appChangelogUrl; | |||||
} // namespace library | } // namespace library | ||||
} // namespace rack | } // namespace rack |
@@ -245,6 +245,7 @@ int main(int argc, char* argv[]) { | |||||
windowDestroy(); | windowDestroy(); | ||||
ui::destroy(); | ui::destroy(); | ||||
} | } | ||||
library::destroy(); | |||||
midi::destroy(); | midi::destroy(); | ||||
audio::destroy(); | audio::destroy(); | ||||
plugin::destroy(); | plugin::destroy(); | ||||