From 923537402ea00d3df78e18a6a1e04f9594cea373 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 28 Jun 2019 22:55:59 -0400 Subject: [PATCH] Add updater.hpp/cpp and more advanced app updating functionality. --- Makefile | 4 +- include/app/common.hpp | 21 +++++------ include/updater.hpp | 26 +++++++++++++ src/app/MenuBar.cpp | 53 ++++++++++++++++++++------- src/app/common.cpp | 49 +++++++------------------ src/main.cpp | 3 +- src/plugin.cpp | 12 +----- src/updater.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 179 insertions(+), 72 deletions(-) create mode 100644 include/updater.hpp create mode 100644 src/updater.cpp diff --git a/Makefile b/Makefile index bc6f6957..187305ae 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ RACK_DIR ?= . -# VERSION := 1.dev.$(shell git rev-parse --short HEAD) -VERSION := 1.1.0 +VERSION := 1.dev.$(shell git rev-parse --short HEAD) +# VERSION := 1.1.0 FLAGS += -DVERSION=$(VERSION) FLAGS += -Iinclude -Idep/include diff --git a/include/app/common.hpp b/include/app/common.hpp index 21c3496a..2b015180 100644 --- a/include/app/common.hpp +++ b/include/app/common.hpp @@ -12,15 +12,17 @@ namespace rack { namespace app { -extern std::string APP_NAME; -extern std::string APP_VERSION; -extern std::string APP_VERSION_UPDATE; -extern std::string API_URL; -extern std::string API_VERSION; -extern std::string ABI_VERSION; +extern const std::string APP_NAME; +extern const std::string APP_VERSION; +extern const std::string APP_ARCH; -static const float SVG_DPI = 75.0; -static const float MM_PER_IN = 25.4; +extern const std::string ABI_VERSION; + +extern const std::string API_URL; +extern const std::string API_VERSION; + +static const float SVG_DPI = 75.f; +static const float MM_PER_IN = 25.4f; /** Converts inch measurements to pixels */ @@ -50,8 +52,5 @@ static const math::Vec RACK_OFFSET = RACK_GRID_SIZE.mult(math::Vec(2000, 100)); static const math::Vec BUS_BOARD_GRID_SIZE = math::Vec(RACK_GRID_WIDTH * 20, RACK_GRID_HEIGHT); -void init(); - - } // namespace app } // namespace rack diff --git a/include/updater.hpp b/include/updater.hpp new file mode 100644 index 00000000..8ac80a97 --- /dev/null +++ b/include/updater.hpp @@ -0,0 +1,26 @@ +#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 b61d2f6b..baf6197c 100644 --- a/src/app/MenuBar.cpp +++ b/src/app/MenuBar.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,16 @@ struct UrlItem : ui::MenuItem { } }; +struct FolderItem : ui::MenuItem { + std::string path; + void onAction(const event::Action &e) override { + std::thread t([=] { + system::openFolder(path); + }); + t.detach(); + } +}; + //////////////////// // File //////////////////// @@ -701,15 +712,35 @@ struct LibraryButton : MenuButton { // Help //////////////////// -struct UserFolderItem : ui::MenuItem { +struct UpdateItem : ui::MenuItem { + ui::Menu *createChildMenu() override { + ui::Menu *menu = new ui::Menu; + + UrlItem *changelogUrl = new UrlItem; + changelogUrl->text = "Changelog"; + changelogUrl->url = updater::changelogUrl; + menu->addChild(changelogUrl); + + return menu; + } + + void step() override { + if (updater::progress > 0) { + rightText = string::f("%.0f%%", updater::progress * 100.f); + } + MenuItem::step(); + } + void onAction(const event::Action &e) override { - std::thread t([] { - system::openFolder(asset::user("")); + std::thread t([=] { + updater::update(); }); t.detach(); + e.consume(NULL); } }; + struct HelpButton : MenuButton { NotificationIcon *notification; @@ -723,11 +754,10 @@ struct HelpButton : MenuButton { menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); menu->box.size.x = box.size.x; - if (hasUpdate()) { - UrlItem *updateItem = new UrlItem; + if (updater::isUpdateAvailable()) { + UpdateItem *updateItem = new UpdateItem; updateItem->text = "Update " + APP_NAME; - updateItem->rightText = APP_VERSION + " → " + APP_VERSION_UPDATE; - updateItem->url = "https://vcvrack.com/"; + updateItem->rightText = APP_VERSION + " → " + updater::version; menu->addChild(updateItem); } @@ -742,20 +772,17 @@ struct HelpButton : MenuButton { websiteItem->url = "https://vcvrack.com/"; menu->addChild(websiteItem); - UserFolderItem *folderItem = new UserFolderItem; + FolderItem *folderItem = new FolderItem; folderItem->text = "Open user folder"; + folderItem->path = asset::user(""); menu->addChild(folderItem); } void step() override { notification->box.pos = math::Vec(0, 0); - notification->visible = hasUpdate(); + notification->visible = updater::isUpdateAvailable(); MenuButton::step(); } - - bool hasUpdate() { - return !APP_VERSION_UPDATE.empty() && APP_VERSION_UPDATE != APP_VERSION; - } }; //////////////////// diff --git a/src/app/common.cpp b/src/app/common.cpp index 9524531c..418ee105 100644 --- a/src/app/common.cpp +++ b/src/app/common.cpp @@ -1,45 +1,24 @@ #include -#include -#include -#include namespace rack { namespace app { -std::string APP_NAME = "VCV Rack"; -std::string APP_VERSION = TOSTRING(VERSION); -std::string APP_VERSION_UPDATE; -std::string API_URL = "https://api.vcvrack.com"; -std::string API_VERSION = "1"; -std::string ABI_VERSION = "1"; - - -static void checkVersion() { - std::string versionUrl = app::API_URL + "/version"; - json_t *versionResJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); - if (!versionResJ) { - WARN("Request for version failed"); - return; - } - DEFER({ - json_decref(versionResJ); - }); - - json_t *versionJ = json_object_get(versionResJ, "version"); - if (versionJ) - APP_VERSION_UPDATE = json_string_value(versionJ); -} - -void init() { - if (!settings::devMode) { - std::thread t([] { - checkVersion(); - }); - t.detach(); - } -} +const std::string APP_NAME = "VCV Rack"; +const std::string APP_VERSION = TOSTRING(VERSION); +#if defined ARCH_WIN + const std::string APP_ARCH = "win"; +#elif ARCH_MAC + const std::string APP_ARCH = "mac"; +#elif defined ARCH_LIN + const std::string APP_ARCH = "lin"; +#endif + +const std::string ABI_VERSION = "1"; + +const std::string API_URL = "https://api.vcvrack.com"; +const std::string API_VERSION = "1"; } // namespace app diff --git a/src/main.cpp b/src/main.cpp index 64e4e80a..961e490b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -150,7 +151,7 @@ int main(int argc, char *argv[]) { keyboard::init(); gamepad::init(); plugin::init(); - app::init(); + updater::init(); if (!settings::headless) { ui::init(); windowInit(); diff --git a/src/plugin.cpp b/src/plugin.cpp index d6cf6b6d..ed6ec303 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -476,21 +476,13 @@ void syncUpdate(Update *update) { isSyncingUpdate = false; }); -#if defined ARCH_WIN - std::string arch = "win"; -#elif ARCH_MAC - std::string arch = "mac"; -#elif defined ARCH_LIN - std::string arch = "lin"; -#endif - std::string downloadUrl = app::API_URL + "/download"; downloadUrl += "?token=" + network::encodeUrl(settings::token); downloadUrl += "&slug=" + network::encodeUrl(update->pluginSlug); downloadUrl += "&version=" + network::encodeUrl(update->version); - downloadUrl += "&arch=" + network::encodeUrl(arch); + downloadUrl += "&arch=" + network::encodeUrl(app::APP_ARCH); - INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), arch.c_str()); + INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), app::APP_ARCH.c_str()); // Download zip std::string pluginDest = asset::pluginsPath + "/" + update->pluginSlug + ".zip"; diff --git a/src/updater.cpp b/src/updater.cpp new file mode 100644 index 00000000..7721d04b --- /dev/null +++ b/src/updater.cpp @@ -0,0 +1,83 @@ +#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 = app::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::APP_ARCH.c_str()); + if (downloadUrlJ) + downloadUrl = json_string_value(downloadUrlJ); + } +} + + +void init() { + if (!settings::devMode) { + std::thread t([] { + checkVersion(); + }); + t.detach(); + } +} + + +void update() { + if (downloadUrl == "") + return; + +#if defined ARCH_WIN + // Download and launch the installer on Windows + std::string path = asset::user("Rack-setup.exe"); + network::requestDownload(downloadUrl, path, &progress); + system::runProcessDetached(path); +#else + // Open the browser on Mac and Linux. The user will know what to do. + system::openBrowser(downloadUrl); +#endif + + APP->window->close(); +} + + +bool isUpdateAvailable() { + return (version != "") && (version != app::APP_VERSION); +} + + +} // namespace updater +} // namespace rack