diff --git a/include/library.hpp b/include/library.hpp new file mode 100644 index 00000000..17fd1ced --- /dev/null +++ b/include/library.hpp @@ -0,0 +1,51 @@ +#pragma once +#include + +#include + + +namespace rack { + + +/** Synchronizes plugins with the VCV Library and updates Rack itself +*/ +namespace library { + + +struct Update { + std::string pluginSlug; + std::string pluginName; + std::string version; + std::string changelogUrl; + float progress = 0.f; +}; + + +extern std::string version; +extern std::string changelogUrl; +extern float progress; + +void init(); +bool isLoggedIn(); +void logIn(const std::string& email, const std::string& password); +void logOut(); +bool isUpdateAvailable(); +void queryUpdates(); +bool hasUpdates(); +void syncUpdate(Update* update); +void syncUpdates(); +bool isSyncing(); +/** Updates Rack automatically or opens the browser to the URL. +Blocking. Call on a detached thread. +*/ +void update(); + + +extern std::string loginStatus; +extern std::vector updates; +extern std::string updateStatus; +extern bool restartRequested; + + +} // namespace library +} // namespace rack diff --git a/include/plugin.hpp b/include/plugin.hpp index 69918dbb..77c426e3 100644 --- a/include/plugin.hpp +++ b/include/plugin.hpp @@ -9,30 +9,13 @@ namespace rack { -/** Plugin loader and VCV Library synchronizer +/** Loads and manages plugins */ namespace plugin { -struct Update { - std::string pluginSlug; - std::string pluginName; - std::string version; - std::string changelogUrl; - float progress = 0.f; -}; - - void init(); void destroy(); -void logIn(const std::string& email, const std::string& password); -void logOut(); -bool isLoggedIn(); -void queryUpdates(); -bool hasUpdates(); -void syncUpdate(Update* update); -void syncUpdates(); -bool isSyncing(); Plugin* getPlugin(const std::string& pluginSlug); Model* getModel(const std::string& pluginSlug, const std::string& modelSlug); /** Creates a Model from a JSON module object. @@ -47,11 +30,6 @@ std::string normalizeSlug(const std::string& slug); extern std::vector plugins; -extern std::string loginStatus; -extern std::vector updates; -extern std::string updateStatus; -extern bool restartRequested; - } // namespace plugin } // namespace rack diff --git a/include/updater.hpp b/include/updater.hpp deleted file mode 100644 index 8ac80a97..00000000 --- a/include/updater.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include - - -namespace rack { - - -/** Automatically updates the application. -*/ -namespace updater { - - -extern std::string version; -extern std::string changelogUrl; -extern float progress; - -void init(); -bool isUpdateAvailable(); -/** Updates Rack automatically or opens the browser to the URL. -Blocking. Call on a detached thread. -*/ -void update(); - - -} // namespace updater -} // namespace rack diff --git a/src/app/MenuBar.cpp b/src/app/MenuBar.cpp index 660073e3..a1d8906e 100644 --- a/src/app/MenuBar.cpp +++ b/src/app/MenuBar.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace rack { @@ -608,7 +608,7 @@ struct LogInItem : ui::MenuItem { std::string email = emailField->text; std::string password = passwordField->text; std::thread t([ = ] { - plugin::logIn(email, password); + library::logIn(email, password); isLoggingIn = false; }); t.detach(); @@ -618,7 +618,7 @@ struct LogInItem : ui::MenuItem { void step() override { disabled = isLoggingIn; text = "Log in"; - rightText = plugin::loginStatus; + rightText = library::loginStatus; MenuItem::step(); } }; @@ -626,13 +626,13 @@ struct LogInItem : ui::MenuItem { struct SyncItem : ui::MenuItem { void step() override { disabled = true; - if (plugin::updateStatus != "") { - text = plugin::updateStatus; + if (library::updateStatus != "") { + text = library::updateStatus; } - else if (plugin::isSyncing()) { + else if (library::isSyncing()) { text = "Updating..."; } - else if (!plugin::hasUpdates()) { + else if (!library::hasUpdates()) { text = "Up-to-date"; } else { @@ -644,7 +644,7 @@ struct SyncItem : ui::MenuItem { void onAction(const event::Action& e) override { std::thread t([ = ] { - plugin::syncUpdates(); + library::syncUpdates(); }); t.detach(); e.consume(NULL); @@ -652,9 +652,9 @@ struct SyncItem : ui::MenuItem { }; struct PluginSyncItem : ui::MenuItem { - plugin::Update* update; + library::Update* update; - void setUpdate(plugin::Update* update) { + void setUpdate(library::Update* update) { this->update = update; text = update->pluginName; plugin::Plugin* p = plugin::getPlugin(update->pluginSlug); @@ -679,7 +679,7 @@ struct PluginSyncItem : ui::MenuItem { } void step() override { - disabled = plugin::isSyncing(); + disabled = library::isSyncing(); if (update->progress >= 1) { rightText = CHECKMARK_STRING; disabled = true; @@ -692,7 +692,7 @@ struct PluginSyncItem : ui::MenuItem { void onAction(const event::Action& e) override { std::thread t([ = ] { - plugin::syncUpdate(update); + library::syncUpdate(update); }); t.detach(); e.consume(NULL); @@ -701,7 +701,7 @@ struct PluginSyncItem : ui::MenuItem { struct LogOutItem : ui::MenuItem { void onAction(const event::Action& e) override { - plugin::logOut(); + library::logOut(); } }; @@ -714,7 +714,7 @@ struct LibraryMenu : ui::Menu { void step() override { // Refresh menu when appropriate - if (!loggedIn && plugin::isLoggedIn()) + if (!loggedIn && library::isLoggedIn()) refresh(); Menu::step(); } @@ -726,7 +726,7 @@ struct LibraryMenu : ui::Menu { if (settings::devMode) { addChild(createMenuLabel("Disabled in development mode")); } - else if (!plugin::isLoggedIn()) { + else if (!library::isLoggedIn()) { UrlItem* registerItem = new UrlItem; registerItem->text = "Register VCV account"; registerItem->url = "https://vcvrack.com/"; @@ -765,14 +765,14 @@ struct LibraryMenu : ui::Menu { syncItem->text = "Update all"; addChild(syncItem); - if (plugin::hasUpdates()) { + if (library::hasUpdates()) { addChild(new ui::MenuSeparator); ui::MenuLabel* updatesLabel = new ui::MenuLabel; updatesLabel->text = "Updates"; addChild(updatesLabel); - for (plugin::Update& update : plugin::updates) { + for (library::Update& update : library::updates) { PluginSyncItem* updateItem = new PluginSyncItem; updateItem->setUpdate(&update); addChild(updateItem); @@ -799,11 +799,11 @@ struct LibraryButton : MenuButton { void step() override { notification->box.pos = math::Vec(0, 0); - notification->visible = plugin::hasUpdates(); + notification->visible = library::hasUpdates(); // Popup when updates finish downloading - if (plugin::restartRequested) { - plugin::restartRequested = false; + if (library::restartRequested) { + library::restartRequested = false; if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been downloaded. Close and re-launch Rack to load new updates.")) { APP->window->close(); } @@ -823,22 +823,22 @@ struct UpdateItem : ui::MenuItem { UrlItem* changelogUrl = new UrlItem; changelogUrl->text = "Changelog"; - changelogUrl->url = updater::changelogUrl; + changelogUrl->url = library::changelogUrl; menu->addChild(changelogUrl); return menu; } void step() override { - if (updater::progress > 0) { - rightText = string::f("%.0f%%", updater::progress * 100.f); + if (library::progress > 0) { + rightText = string::f("%.0f%%", library::progress * 100.f); } MenuItem::step(); } void onAction(const event::Action& e) override { std::thread t([ = ] { - updater::update(); + library::update(); }); t.detach(); e.consume(NULL); @@ -859,10 +859,10 @@ struct HelpButton : MenuButton { menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); menu->box.size.x = box.size.x; - if (updater::isUpdateAvailable()) { + if (library::isUpdateAvailable()) { UpdateItem* updateItem = new UpdateItem; updateItem->text = "Update " + APP_NAME; - updateItem->rightText = APP_VERSION + " → " + updater::version; + updateItem->rightText = APP_VERSION + " → " + library::version; menu->addChild(updateItem); } @@ -885,7 +885,7 @@ struct HelpButton : MenuButton { void step() override { notification->box.pos = math::Vec(0, 0); - notification->visible = updater::isUpdateAvailable(); + notification->visible = library::isUpdateAvailable(); MenuButton::step(); } }; diff --git a/src/library.cpp b/src/library.cpp new file mode 100644 index 00000000..ac20ba58 --- /dev/null +++ b/src/library.cpp @@ -0,0 +1,359 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace rack { +namespace library { + + +std::string version; +std::string changelogUrl; +float progress = 0.f; +static std::string downloadUrl; + + +static void checkVersion() { + std::string versionUrl = API_URL + "/version"; + json_t* resJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); + if (!resJ) { + WARN("Request for version failed"); + return; + } + DEFER({json_decref(resJ);}); + + json_t* versionJ = json_object_get(resJ, "version"); + if (versionJ) + version = json_string_value(versionJ); + + json_t* changelogUrlJ = json_object_get(resJ, "changelogUrl"); + if (changelogUrlJ) + changelogUrl = json_string_value(changelogUrlJ); + + json_t* downloadUrlsJ = json_object_get(resJ, "downloadUrls"); + if (downloadUrlsJ) { + json_t* downloadUrlJ = json_object_get(downloadUrlsJ, APP_ARCH.c_str()); + if (downloadUrlJ) + downloadUrl = 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 isLoggedIn() { + return settings::token != ""; +} + + +void logIn(const std::string& email, const std::string& password) { + loginStatus = "Logging in..."; + json_t* reqJ = json_object(); + json_object_set(reqJ, "email", json_string(email.c_str())); + json_object_set(reqJ, "password", json_string(password.c_str())); + std::string url = API_URL + "/token"; + json_t* resJ = network::requestJson(network::METHOD_POST, url, reqJ); + json_decref(reqJ); + + if (!resJ) { + loginStatus = "No response from server"; + return; + } + DEFER({ + json_decref(resJ); + }); + + json_t* errorJ = json_object_get(resJ, "error"); + if (errorJ) { + const char* errorStr = json_string_value(errorJ); + loginStatus = errorStr; + return; + } + + json_t* tokenJ = json_object_get(resJ, "token"); + if (!tokenJ) { + loginStatus = "No token in response"; + return; + } + + const char* tokenStr = json_string_value(tokenJ); + settings::token = tokenStr; + loginStatus = ""; + queryUpdates(); +} + + +void logOut() { + settings::token = ""; + updates.clear(); +} + + +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() { + if (settings::token.empty()) + return; + + updates.clear(); + updateStatus = "Querying for updates..."; + + // Get user's plugins list + std::string pluginsUrl = API_URL + "/plugins"; + network::CookieMap cookies; + cookies["token"] = settings::token; + json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, cookies); + if (!pluginsResJ) { + WARN("Request for user's plugins failed"); + updateStatus = "Could not query updates"; + return; + } + DEFER({ + json_decref(pluginsResJ); + }); + + json_t* errorJ = json_object_get(pluginsResJ, "error"); + if (errorJ) { + WARN("Request for user's plugins returned an error: %s", json_string_value(errorJ)); + updateStatus = "Could not query updates"; + return; + } + + // Get library manifests + std::string manifestsUrl = API_URL + "/library/manifests"; + json_t* manifestsReq = json_object(); + json_object_set(manifestsReq, "version", json_string(API_VERSION.c_str())); + json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); + json_decref(manifestsReq); + if (!manifestsResJ) { + WARN("Request for library manifests failed"); + updateStatus = "Could not query updates"; + return; + } + DEFER({ + json_decref(manifestsResJ); + }); + + json_t* manifestsJ = json_object_get(manifestsResJ, "manifests"); + json_t* pluginsJ = json_object_get(pluginsResJ, "plugins"); + + size_t pluginIndex; + json_t* pluginJ; + json_array_foreach(pluginsJ, pluginIndex, pluginJ) { + Update update; + // Get plugin manifest + update.pluginSlug = json_string_value(pluginJ); + json_t* manifestJ = json_object_get(manifestsJ, update.pluginSlug.c_str()); + if (!manifestJ) { + WARN("VCV account has plugin %s but no manifest was found", update.pluginSlug.c_str()); + continue; + } + + // Get plugin name + json_t* nameJ = json_object_get(manifestJ, "name"); + if (nameJ) + update.pluginName = json_string_value(nameJ); + + // Get version + json_t* versionJ = json_object_get(manifestJ, "version"); + if (!versionJ) { + WARN("Plugin %s has no version in manifest", update.pluginSlug.c_str()); + continue; + } + update.version = json_string_value(versionJ); + + // Check if update is needed + plugin::Plugin* p = plugin::getPlugin(update.pluginSlug); + if (p && p->version == update.version) + continue; + + // Check status + json_t* statusJ = json_object_get(manifestJ, "status"); + if (!statusJ) + continue; + std::string status = json_string_value(statusJ); + if (status != "available") + continue; + + // Get changelog URL + json_t* changelogUrlJ = json_object_get(manifestJ, "changelogUrl"); + if (changelogUrlJ) { + update.changelogUrl = json_string_value(changelogUrlJ); + } + + updates.push_back(update); + } + + + // Get module whitelist + { + std::string whitelistUrl = API_URL + "/moduleWhitelist"; + json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, cookies); + if (!whitelistResJ) { + WARN("Request for module whitelist failed"); + updateStatus = "Could not query updates"; + return; + } + DEFER({ + json_decref(whitelistResJ); + }); + + std::map> moduleWhitelist; + json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); + + // Iterate plugins + const char* pluginSlug; + json_t* modulesJ; + json_object_foreach(pluginsJ, pluginSlug, modulesJ) { + // Iterate modules in plugin + size_t moduleIndex; + json_t* moduleSlugJ; + json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { + std::string moduleSlug = json_string_value(moduleSlugJ); + // Insert module in whitelist + moduleWhitelist[pluginSlug].insert(moduleSlug); + } + } + + settings::moduleWhitelist = moduleWhitelist; + } + + updateStatus = ""; +} + + +bool hasUpdates() { + for (Update& update : updates) { + if (update.progress < 1.f) + return true; + } + return false; +} + + +static bool isSyncingUpdate = false; +static bool isSyncingUpdates = false; + + +void syncUpdate(Update* update) { + isSyncingUpdate = true; + DEFER({ + isSyncingUpdate = false; + }); + + std::string downloadUrl = API_URL + "/download"; + downloadUrl += "?slug=" + network::encodeUrl(update->pluginSlug); + downloadUrl += "&version=" + network::encodeUrl(update->version); + downloadUrl += "&arch=" + network::encodeUrl(APP_ARCH); + + network::CookieMap cookies; + cookies["token"] = settings::token; + + INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), APP_ARCH.c_str()); + + // Download zip + std::string pluginDest = system::join(asset::pluginsPath, update->pluginSlug + ".zip"); + if (!network::requestDownload(downloadUrl, pluginDest, &update->progress, cookies)) { + WARN("Plugin %s download was unsuccessful", update->pluginSlug.c_str()); + return; + } +} + + +void syncUpdates() { + isSyncingUpdates = true; + DEFER({ + isSyncingUpdates = false; + }); + + if (settings::token.empty()) + return; + + for (Update& update : updates) { + if (update.progress < 1.f) + syncUpdate(&update); + } + restartRequested = true; +} + + +bool isSyncing() { + return isSyncingUpdate || isSyncingUpdates; +} + + +std::string loginStatus; +std::vector updates; +std::string updateStatus; +bool restartRequested = false; + + +} // namespace library +} // namespace rack diff --git a/src/plugin.cpp b/src/plugin.cpp index fc388fc8..b200bbd9 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -11,7 +11,7 @@ #include #include #else - #include + #include // for dlopen #endif #include @@ -20,14 +20,11 @@ #include #include -#include #include #include #include -#include #include #include -#include namespace rack { @@ -232,14 +229,6 @@ void init() { system::unarchiveToFolder(fundamentalSrc.c_str(), asset::pluginsPath.c_str()); loadPlugin(fundamentalDir); } - - // Sync in a detached thread - if (!settings::devMode) { - std::thread t([] { - queryUpdates(); - }); - t.detach(); - } } @@ -262,245 +251,6 @@ void destroy() { } -void logIn(const std::string& email, const std::string& password) { - loginStatus = "Logging in..."; - json_t* reqJ = json_object(); - json_object_set(reqJ, "email", json_string(email.c_str())); - json_object_set(reqJ, "password", json_string(password.c_str())); - std::string url = API_URL + "/token"; - json_t* resJ = network::requestJson(network::METHOD_POST, url, reqJ); - json_decref(reqJ); - - if (!resJ) { - loginStatus = "No response from server"; - return; - } - DEFER({ - json_decref(resJ); - }); - - json_t* errorJ = json_object_get(resJ, "error"); - if (errorJ) { - const char* errorStr = json_string_value(errorJ); - loginStatus = errorStr; - return; - } - - json_t* tokenJ = json_object_get(resJ, "token"); - if (!tokenJ) { - loginStatus = "No token in response"; - return; - } - - const char* tokenStr = json_string_value(tokenJ); - settings::token = tokenStr; - loginStatus = ""; - queryUpdates(); -} - - -void logOut() { - settings::token = ""; - updates.clear(); -} - - -bool isLoggedIn() { - return settings::token != ""; -} - - -void queryUpdates() { - if (settings::token.empty()) - return; - - updates.clear(); - updateStatus = "Querying for updates..."; - - // Get user's plugins list - std::string pluginsUrl = API_URL + "/plugins"; - network::CookieMap cookies; - cookies["token"] = settings::token; - json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, cookies); - if (!pluginsResJ) { - WARN("Request for user's plugins failed"); - updateStatus = "Could not query updates"; - return; - } - DEFER({ - json_decref(pluginsResJ); - }); - - json_t* errorJ = json_object_get(pluginsResJ, "error"); - if (errorJ) { - WARN("Request for user's plugins returned an error: %s", json_string_value(errorJ)); - updateStatus = "Could not query updates"; - return; - } - - // Get library manifests - std::string manifestsUrl = API_URL + "/library/manifests"; - json_t* manifestsReq = json_object(); - json_object_set(manifestsReq, "version", json_string(API_VERSION.c_str())); - json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); - json_decref(manifestsReq); - if (!manifestsResJ) { - WARN("Request for library manifests failed"); - updateStatus = "Could not query updates"; - return; - } - DEFER({ - json_decref(manifestsResJ); - }); - - json_t* manifestsJ = json_object_get(manifestsResJ, "manifests"); - json_t* pluginsJ = json_object_get(pluginsResJ, "plugins"); - - size_t pluginIndex; - json_t* pluginJ; - json_array_foreach(pluginsJ, pluginIndex, pluginJ) { - Update update; - // Get plugin manifest - update.pluginSlug = json_string_value(pluginJ); - json_t* manifestJ = json_object_get(manifestsJ, update.pluginSlug.c_str()); - if (!manifestJ) { - WARN("VCV account has plugin %s but no manifest was found", update.pluginSlug.c_str()); - continue; - } - - // Get plugin name - json_t* nameJ = json_object_get(manifestJ, "name"); - if (nameJ) - update.pluginName = json_string_value(nameJ); - - // Get version - json_t* versionJ = json_object_get(manifestJ, "version"); - if (!versionJ) { - WARN("Plugin %s has no version in manifest", update.pluginSlug.c_str()); - continue; - } - update.version = json_string_value(versionJ); - - // Check if update is needed - Plugin* p = getPlugin(update.pluginSlug); - if (p && p->version == update.version) - continue; - - // Check status - json_t* statusJ = json_object_get(manifestJ, "status"); - if (!statusJ) - continue; - std::string status = json_string_value(statusJ); - if (status != "available") - continue; - - // Get changelog URL - json_t* changelogUrlJ = json_object_get(manifestJ, "changelogUrl"); - if (changelogUrlJ) { - update.changelogUrl = json_string_value(changelogUrlJ); - } - - updates.push_back(update); - } - - - // Get module whitelist - { - std::string whitelistUrl = API_URL + "/moduleWhitelist"; - json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, cookies); - if (!whitelistResJ) { - WARN("Request for module whitelist failed"); - updateStatus = "Could not query updates"; - return; - } - DEFER({ - json_decref(whitelistResJ); - }); - - std::map> moduleWhitelist; - json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); - - // Iterate plugins - const char* pluginSlug; - json_t* modulesJ; - json_object_foreach(pluginsJ, pluginSlug, modulesJ) { - // Iterate modules in plugin - size_t moduleIndex; - json_t* moduleSlugJ; - json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { - std::string moduleSlug = json_string_value(moduleSlugJ); - // Insert module in whitelist - moduleWhitelist[pluginSlug].insert(moduleSlug); - } - } - - settings::moduleWhitelist = moduleWhitelist; - } - - updateStatus = ""; -} - - -bool hasUpdates() { - for (Update& update : updates) { - if (update.progress < 1.f) - return true; - } - return false; -} - - -static bool isSyncingUpdate = false; -static bool isSyncingUpdates = false; - - -void syncUpdate(Update* update) { - isSyncingUpdate = true; - DEFER({ - isSyncingUpdate = false; - }); - - std::string downloadUrl = API_URL + "/download"; - downloadUrl += "?slug=" + network::encodeUrl(update->pluginSlug); - downloadUrl += "&version=" + network::encodeUrl(update->version); - downloadUrl += "&arch=" + network::encodeUrl(APP_ARCH); - - network::CookieMap cookies; - cookies["token"] = settings::token; - - INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), APP_ARCH.c_str()); - - // Download zip - std::string pluginDest = system::join(asset::pluginsPath, update->pluginSlug + ".zip"); - if (!network::requestDownload(downloadUrl, pluginDest, &update->progress, cookies)) { - WARN("Plugin %s download was unsuccessful", update->pluginSlug.c_str()); - return; - } -} - - -void syncUpdates() { - isSyncingUpdates = true; - DEFER({ - isSyncingUpdates = false; - }); - - if (settings::token.empty()) - return; - - for (Update& update : updates) { - if (update.progress < 1.f) - syncUpdate(&update); - } - restartRequested = true; -} - - -bool isSyncing() { - return isSyncingUpdate || isSyncingUpdates; -} - - Plugin* getPlugin(const std::string& pluginSlug) { for (Plugin* plugin : plugins) { if (plugin->slug == pluginSlug) { @@ -566,11 +316,6 @@ std::string normalizeSlug(const std::string& slug) { std::vector plugins; -std::string loginStatus; -std::vector updates; -std::string updateStatus; -bool restartRequested = false; - } // namespace plugin } // namespace rack diff --git a/src/updater.cpp b/src/updater.cpp deleted file mode 100644 index 39a86272..00000000 --- a/src/updater.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace rack { -namespace updater { - - -std::string version; -std::string changelogUrl; -float progress = 0.f; -static std::string downloadUrl; - - -static void checkVersion() { - std::string versionUrl = API_URL + "/version"; - json_t* resJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); - if (!resJ) { - WARN("Request for version failed"); - return; - } - DEFER({ - json_decref(resJ); - }); - - json_t* versionJ = json_object_get(resJ, "version"); - if (versionJ) - version = json_string_value(versionJ); - - json_t* changelogUrlJ = json_object_get(resJ, "changelogUrl"); - if (changelogUrlJ) - changelogUrl = json_string_value(changelogUrlJ); - - json_t* downloadUrlsJ = json_object_get(resJ, "downloadUrls"); - if (downloadUrlsJ) { - json_t* downloadUrlJ = json_object_get(downloadUrlsJ, APP_ARCH.c_str()); - if (downloadUrlJ) - downloadUrl = json_string_value(downloadUrlJ); - } -} - - -void init() { - if (settings::devMode) - return; - - std::thread t([]() { - checkVersion(); - }); - t.detach(); -} - - -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); -} - - -} // namespace updater -} // namespace rack diff --git a/standalone/main.cpp b/standalone/main.cpp index f9a9a9b5..7e3342b4 100644 --- a/standalone/main.cpp +++ b/standalone/main.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -168,7 +168,7 @@ int main(int argc, char* argv[]) { keyboard::init(); gamepad::init(); plugin::init(); - updater::init(); + library::init(); if (!settings::headless) { ui::init(); windowInit();