| @@ -18,8 +18,8 @@ std::string user(std::string filename); | |||
| std::string plugin(Plugin *plugin, std::string filename); | |||
| extern std::string gSystemDir; | |||
| extern std::string gUserDir; | |||
| extern std::string systemDir; | |||
| extern std::string userDir; | |||
| } // namespace asset | |||
| @@ -11,7 +11,6 @@ namespace event { | |||
| struct Scene; | |||
| struct Engine; | |||
| struct PluginManager; | |||
| struct Window; | |||
| @@ -19,7 +18,6 @@ struct Context { | |||
| event::Context *event = NULL; | |||
| Scene *scene = NULL; | |||
| Engine *engine = NULL; | |||
| PluginManager *plugin = NULL; | |||
| Window *window = NULL; | |||
| }; | |||
| @@ -0,0 +1,33 @@ | |||
| #pragma once | |||
| #include "common.hpp" | |||
| #include "plugin/Plugin.hpp" | |||
| #include "plugin/Model.hpp" | |||
| #include <list> | |||
| namespace rack { | |||
| namespace plugin { | |||
| void init(bool devMode); | |||
| void destroy(); | |||
| void logIn(std::string email, std::string password); | |||
| void logOut(); | |||
| /** Returns whether a new plugin is available, and downloads it unless doing a dry run */ | |||
| bool sync(bool dryRun); | |||
| void cancelDownload(); | |||
| bool isLoggedIn(); | |||
| Plugin *getPlugin(std::string pluginSlug); | |||
| Model *getModel(std::string pluginSlug, std::string modelSlug); | |||
| extern std::list<Plugin*> plugins; | |||
| extern std::string token; | |||
| extern bool isDownloading; | |||
| extern float downloadProgress; | |||
| extern std::string downloadName; | |||
| extern std::string loginStatus; | |||
| } // namespace plugin | |||
| } // namespace rack | |||
| @@ -1,44 +0,0 @@ | |||
| #pragma once | |||
| #include "common.hpp" | |||
| #include "plugin/Plugin.hpp" | |||
| #include "plugin/Model.hpp" | |||
| #include <list> | |||
| namespace rack { | |||
| struct PluginManager { | |||
| std::list<Plugin*> plugins; | |||
| std::string token; | |||
| bool isDownloading = false; | |||
| float downloadProgress = 0.f; | |||
| std::string downloadName; | |||
| std::string loginStatus; | |||
| PluginManager(bool devMode); | |||
| ~PluginManager(); | |||
| void logIn(std::string email, std::string password); | |||
| void logOut(); | |||
| /** Returns whether a new plugin is available, and downloads it unless doing a dry run */ | |||
| bool sync(bool dryRun); | |||
| void cancelDownload(); | |||
| bool isLoggedIn(); | |||
| Plugin *getPlugin(std::string pluginSlug); | |||
| Model *getModel(std::string pluginSlug, std::string modelSlug); | |||
| }; | |||
| } // namespace rack | |||
| //////////////////// | |||
| // Implemented by plugin | |||
| //////////////////// | |||
| /** Called once to initialize and return the Plugin instance. | |||
| You must implement this in your plugin | |||
| */ | |||
| extern "C" | |||
| void init(rack::Plugin *plugin); | |||
| @@ -10,7 +10,7 @@ | |||
| #include "app/Scene.hpp" | |||
| #include "ui/List.hpp" | |||
| #include "ui/TextField.hpp" | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "context.hpp" | |||
| @@ -323,7 +323,7 @@ struct ModuleBrowser : OpaqueWidget { | |||
| addChild(moduleScroll); | |||
| // Collect authors | |||
| for (Plugin *plugin : context()->plugin->plugins) { | |||
| for (Plugin *plugin : plugin::plugins) { | |||
| for (Model *model : plugin->models) { | |||
| // Insert author | |||
| if (!model->author.empty()) | |||
| @@ -428,7 +428,7 @@ struct ModuleBrowser : OpaqueWidget { | |||
| moduleList->addChild(item); | |||
| } | |||
| // Modules | |||
| for (Plugin *plugin : context()->plugin->plugins) { | |||
| for (Plugin *plugin : plugin::plugins) { | |||
| for (Model *model : plugin->models) { | |||
| if (isModelFiltered(model) && isModelMatch(model, search)) { | |||
| ModelItem *item = new ModelItem; | |||
| @@ -588,7 +588,7 @@ void moduleBrowserFromJson(json_t *rootJ) { | |||
| continue; | |||
| std::string pluginSlug = json_string_value(pluginJ); | |||
| std::string modelSlug = json_string_value(modelJ); | |||
| Model *model = context()->plugin->getModel(pluginSlug, modelSlug); | |||
| Model *model = plugin::getModel(pluginSlug, modelSlug); | |||
| if (!model) | |||
| continue; | |||
| sFavoriteModels.insert(model); | |||
| @@ -7,7 +7,7 @@ | |||
| #include "ui/TextField.hpp" | |||
| #include "ui/PasswordField.hpp" | |||
| #include "ui/Label.hpp" | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "context.hpp" | |||
| #include "window.hpp" | |||
| #include "helpers.hpp" | |||
| @@ -32,7 +32,7 @@ struct LogInButton : Button { | |||
| TextField *passwordField; | |||
| void onAction(event::Action &e) override { | |||
| std::thread t([&]() { | |||
| context()->plugin->logIn(emailField->text, passwordField->text); | |||
| plugin::logIn(emailField->text, passwordField->text); | |||
| }); | |||
| t.detach(); | |||
| passwordField->text = ""; | |||
| @@ -42,7 +42,7 @@ struct LogInButton : Button { | |||
| struct StatusLabel : Label { | |||
| void step() override { | |||
| text = context()->plugin->loginStatus; | |||
| text = plugin::loginStatus; | |||
| } | |||
| }; | |||
| @@ -68,7 +68,7 @@ struct SyncButton : Button { | |||
| // Check for plugin update on first step() | |||
| if (!checked) { | |||
| std::thread t([this]() { | |||
| if (context()->plugin->sync(true)) | |||
| if (plugin::sync(true)) | |||
| available = true; | |||
| }); | |||
| t.detach(); | |||
| @@ -97,7 +97,7 @@ struct SyncButton : Button { | |||
| void onAction(event::Action &e) override { | |||
| available = false; | |||
| std::thread t([this]() { | |||
| if (context()->plugin->sync(false)) | |||
| if (plugin::sync(false)) | |||
| completed = true; | |||
| }); | |||
| t.detach(); | |||
| @@ -107,14 +107,14 @@ struct SyncButton : Button { | |||
| struct LogOutButton : Button { | |||
| void onAction(event::Action &e) override { | |||
| context()->plugin->logOut(); | |||
| plugin::logOut(); | |||
| } | |||
| }; | |||
| struct DownloadQuantity : Quantity { | |||
| float getValue() override { | |||
| return context()->plugin->downloadProgress; | |||
| return plugin::downloadProgress; | |||
| } | |||
| float getDisplayValue() override { | |||
| @@ -124,7 +124,7 @@ struct DownloadQuantity : Quantity { | |||
| int getDisplayPrecision() override {return 0;} | |||
| std::string getLabel() override { | |||
| return "Downloading " + context()->plugin->downloadName; | |||
| return "Downloading " + plugin::downloadName; | |||
| } | |||
| std::string getUnit() override {return "%";} | |||
| @@ -140,7 +140,7 @@ struct DownloadProgressBar : ProgressBar { | |||
| struct CancelButton : Button { | |||
| void onAction(event::Action &e) override { | |||
| context()->plugin->cancelDownload(); | |||
| plugin::cancelDownload(); | |||
| } | |||
| }; | |||
| @@ -227,9 +227,9 @@ void PluginManagerWidget::step() { | |||
| manageWidget->visible = false; | |||
| downloadWidget->visible = false; | |||
| if (context()->plugin->isDownloading) | |||
| if (plugin::isDownloading) | |||
| downloadWidget->visible = true; | |||
| else if (context()->plugin->isLoggedIn()) | |||
| else if (plugin::isLoggedIn()) | |||
| manageWidget->visible = true; | |||
| else | |||
| loginWidget->visible = true; | |||
| @@ -9,7 +9,7 @@ | |||
| #include "asset.hpp" | |||
| #include "system.hpp" | |||
| #include "logger.hpp" | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "context.hpp" | |||
| @@ -379,7 +379,7 @@ ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) { | |||
| std::string modelSlug = json_string_value(modelSlugJ); | |||
| // Get Model | |||
| Model *model = context()->plugin->getModel(pluginSlug, modelSlug); | |||
| Model *model = plugin::getModel(pluginSlug, modelSlug); | |||
| if (!model) | |||
| return NULL; | |||
| @@ -26,9 +26,9 @@ namespace asset { | |||
| void init(bool devMode) { | |||
| // Get system dir | |||
| if (gSystemDir.empty()) { | |||
| if (systemDir.empty()) { | |||
| if (devMode) { | |||
| gSystemDir = "."; | |||
| systemDir = "."; | |||
| } | |||
| else { | |||
| #if ARCH_MAC | |||
| @@ -39,26 +39,26 @@ void init(bool devMode) { | |||
| Boolean success = CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8*) resourcesBuf, sizeof(resourcesBuf)); | |||
| assert(success); | |||
| CFRelease(resourcesUrl); | |||
| gSystemDir = resourcesBuf; | |||
| systemDir = resourcesBuf; | |||
| #endif | |||
| #if ARCH_WIN | |||
| char moduleBuf[MAX_PATH]; | |||
| DWORD length = GetModuleFileName(NULL, moduleBuf, sizeof(moduleBuf)); | |||
| assert(length > 0); | |||
| PathRemoveFileSpec(moduleBuf); | |||
| gSystemDir = moduleBuf; | |||
| systemDir = moduleBuf; | |||
| #endif | |||
| #if ARCH_LIN | |||
| // TODO For now, users should launch Rack from their terminal in the system directory | |||
| gSystemDir = "."; | |||
| systemDir = "."; | |||
| #endif | |||
| } | |||
| } | |||
| // Get user dir | |||
| if (gUserDir.empty()) { | |||
| if (userDir.empty()) { | |||
| if (devMode) { | |||
| gUserDir = "."; | |||
| userDir = "."; | |||
| } | |||
| else { | |||
| #if ARCH_WIN | |||
| @@ -66,15 +66,15 @@ void init(bool devMode) { | |||
| char documentsBuf[MAX_PATH]; | |||
| HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, documentsBuf); | |||
| assert(result == S_OK); | |||
| gUserDir = documentsBuf; | |||
| gUserDir += "/Rack"; | |||
| userDir = documentsBuf; | |||
| userDir += "/Rack"; | |||
| #endif | |||
| #if ARCH_MAC | |||
| // Get home directory | |||
| struct passwd *pw = getpwuid(getuid()); | |||
| assert(pw); | |||
| gUserDir = pw->pw_dir; | |||
| gUserDir += "/Documents/Rack"; | |||
| userDir = pw->pw_dir; | |||
| userDir += "/Documents/Rack"; | |||
| #endif | |||
| #if ARCH_LIN | |||
| // Get home directory | |||
| @@ -84,24 +84,24 @@ void init(bool devMode) { | |||
| assert(pw); | |||
| homeBuf = pw->pw_dir; | |||
| } | |||
| gUserDir = homeBuf; | |||
| gUserDir += "/.Rack"; | |||
| userDir = homeBuf; | |||
| userDir += "/.Rack"; | |||
| #endif | |||
| } | |||
| } | |||
| system::createDirectory(gSystemDir); | |||
| system::createDirectory(gUserDir); | |||
| system::createDirectory(systemDir); | |||
| system::createDirectory(userDir); | |||
| } | |||
| std::string system(std::string filename) { | |||
| return gSystemDir + "/" + filename; | |||
| return systemDir + "/" + filename; | |||
| } | |||
| std::string user(std::string filename) { | |||
| return gUserDir + "/" + filename; | |||
| return userDir + "/" + filename; | |||
| } | |||
| @@ -111,8 +111,8 @@ std::string plugin(Plugin *plugin, std::string filename) { | |||
| } | |||
| std::string gSystemDir; | |||
| std::string gUserDir; | |||
| std::string systemDir; | |||
| std::string userDir; | |||
| } // namespace asset | |||
| @@ -10,7 +10,7 @@ | |||
| #include "engine/Engine.hpp" | |||
| #include "app/Scene.hpp" | |||
| #include "tags.hpp" | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "context.hpp" | |||
| #include "ui.hpp" | |||
| @@ -48,10 +48,10 @@ int main(int argc, char *argv[]) { | |||
| devMode = true; | |||
| } break; | |||
| case 's': { | |||
| asset::gSystemDir = optarg; | |||
| asset::systemDir = optarg; | |||
| } break; | |||
| case 'u': { | |||
| asset::gUserDir = optarg; | |||
| asset::userDir = optarg; | |||
| } break; | |||
| default: break; | |||
| } | |||
| @@ -70,16 +70,16 @@ int main(int argc, char *argv[]) { | |||
| keyboard::init(); | |||
| gamepad::init(); | |||
| uiInit(); | |||
| plugin::init(devMode); | |||
| // Log environment | |||
| INFO("%s %s", APP_NAME.c_str(), APP_VERSION.c_str()); | |||
| if (devMode) | |||
| INFO("Development mode"); | |||
| INFO("System directory: %s", asset::gSystemDir.c_str()); | |||
| INFO("User directory: %s", asset::gUserDir.c_str()); | |||
| INFO("System directory: %s", asset::systemDir.c_str()); | |||
| INFO("User directory: %s", asset::userDir.c_str()); | |||
| // Initialize app | |||
| context()->plugin = new PluginManager(devMode); | |||
| context()->engine = new Engine; | |||
| context()->event = new event::Context; | |||
| context()->scene = new Scene; | |||
| @@ -125,10 +125,9 @@ int main(int argc, char *argv[]) { | |||
| context()->window = NULL; | |||
| delete context()->engine; | |||
| context()->engine = NULL; | |||
| delete context()->plugin; | |||
| context()->plugin = NULL; | |||
| // Destroy environment | |||
| plugin::destroy(); | |||
| uiDestroy(); | |||
| bridgeDestroy(); | |||
| midiDestroy(); | |||
| @@ -1,4 +1,4 @@ | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "system.hpp" | |||
| #include "logger.hpp" | |||
| #include "network.hpp" | |||
| @@ -6,6 +6,7 @@ | |||
| #include "string.hpp" | |||
| #include "context.hpp" | |||
| #include "app/common.hpp" | |||
| #include "plugin/callbacks.hpp" | |||
| #include <unistd.h> | |||
| #include <sys/types.h> | |||
| @@ -31,13 +32,14 @@ | |||
| namespace rack { | |||
| namespace plugin { | |||
| //////////////////// | |||
| // private API | |||
| //////////////////// | |||
| static bool PluginManager_loadPlugin(PluginManager *pluginManager, std::string path) { | |||
| static bool loadPlugin(std::string path) { | |||
| std::string libraryFilename; | |||
| #if ARCH_LIN | |||
| libraryFilename = path + "/" + "plugin.so"; | |||
| @@ -91,7 +93,7 @@ static bool PluginManager_loadPlugin(PluginManager *pluginManager, std::string p | |||
| initCallback(plugin); | |||
| // Reject plugin if slug already exists | |||
| Plugin *oldPlugin = pluginManager->getPlugin(plugin->slug); | |||
| Plugin *oldPlugin = getPlugin(plugin->slug); | |||
| if (oldPlugin) { | |||
| WARN("Plugin \"%s\" is already loaded, not attempting to load it again", plugin->slug.c_str()); | |||
| // TODO | |||
| @@ -100,13 +102,13 @@ static bool PluginManager_loadPlugin(PluginManager *pluginManager, std::string p | |||
| } | |||
| // Add plugin to list | |||
| pluginManager->plugins.push_back(plugin); | |||
| plugins.push_back(plugin); | |||
| INFO("Loaded plugin %s %s from %s", plugin->slug.c_str(), plugin->version.c_str(), libraryFilename.c_str()); | |||
| return true; | |||
| } | |||
| static bool PluginManager_syncPlugin(PluginManager *pluginManager, std::string slug, json_t *manifestJ, bool dryRun) { | |||
| static bool syncPlugin(std::string slug, json_t *manifestJ, bool dryRun) { | |||
| // Check that "status" is "available" | |||
| json_t *statusJ = json_object_get(manifestJ, "status"); | |||
| if (!statusJ) { | |||
| @@ -126,7 +128,7 @@ static bool PluginManager_syncPlugin(PluginManager *pluginManager, std::string s | |||
| std::string latestVersion = json_string_value(latestVersionJ); | |||
| // Check whether we already have a plugin with the same slug and version | |||
| Plugin *plugin = pluginManager->getPlugin(slug); | |||
| Plugin *plugin = getPlugin(slug); | |||
| if (plugin && plugin->version == latestVersion) { | |||
| return false; | |||
| } | |||
| @@ -154,7 +156,7 @@ static bool PluginManager_syncPlugin(PluginManager *pluginManager, std::string s | |||
| if (dryRun) { | |||
| downloadUrl += "/available"; | |||
| } | |||
| downloadUrl += "?token=" + network::encodeUrl(pluginManager->token); | |||
| downloadUrl += "?token=" + network::encodeUrl(token); | |||
| downloadUrl += "&slug=" + network::encodeUrl(slug); | |||
| downloadUrl += "&version=" + network::encodeUrl(latestVersion); | |||
| downloadUrl += "&arch=" + network::encodeUrl(arch); | |||
| @@ -173,28 +175,28 @@ static bool PluginManager_syncPlugin(PluginManager *pluginManager, std::string s | |||
| return json_boolean_value(successJ); | |||
| } | |||
| else { | |||
| pluginManager->downloadName = name; | |||
| pluginManager->downloadProgress = 0.0; | |||
| downloadName = name; | |||
| downloadProgress = 0.0; | |||
| INFO("Downloading plugin %s %s %s", slug.c_str(), latestVersion.c_str(), arch.c_str()); | |||
| // Download zip | |||
| std::string pluginDest = asset::user("plugins/" + slug + ".zip"); | |||
| if (!network::requestDownload(downloadUrl, pluginDest, &pluginManager->downloadProgress)) { | |||
| if (!network::requestDownload(downloadUrl, pluginDest, &downloadProgress)) { | |||
| WARN("Plugin %s download was unsuccessful", slug.c_str()); | |||
| return false; | |||
| } | |||
| pluginManager->downloadName = ""; | |||
| downloadName = ""; | |||
| return true; | |||
| } | |||
| } | |||
| static void PluginManager_loadPlugins(PluginManager *pluginManager, std::string path) { | |||
| static void loadPlugins(std::string path) { | |||
| std::string message; | |||
| for (std::string pluginPath : system::listEntries(path)) { | |||
| if (!system::isDirectory(pluginPath)) | |||
| continue; | |||
| if (!PluginManager_loadPlugin(pluginManager, pluginPath)) { | |||
| if (!loadPlugin(pluginPath)) { | |||
| message += string::f("Could not load plugin %s\n", pluginPath.c_str()); | |||
| } | |||
| } | |||
| @@ -300,18 +302,18 @@ static void extractPackages(std::string path) { | |||
| // public API | |||
| //////////////////// | |||
| PluginManager::PluginManager(bool devMode) { | |||
| void init(bool devMode) { | |||
| // Load core | |||
| // This function is defined in core.cpp | |||
| Plugin *corePlugin = new Plugin; | |||
| init(corePlugin); | |||
| ::init(corePlugin); | |||
| plugins.push_back(corePlugin); | |||
| // Get user plugins directory | |||
| std::string userPlugins = asset::user("plugins"); | |||
| mkdir(userPlugins.c_str(), 0755); | |||
| if (devMode) { | |||
| if (!devMode) { | |||
| // Copy Fundamental package to plugins directory if folder does not exist | |||
| std::string fundamentalSrc = asset::system("Fundamental.zip"); | |||
| std::string fundamentalDest = asset::user("plugins/Fundamental.zip"); | |||
| @@ -323,10 +325,10 @@ PluginManager::PluginManager(bool devMode) { | |||
| // Extract packages and load plugins | |||
| extractPackages(userPlugins); | |||
| PluginManager_loadPlugins(this, userPlugins); | |||
| loadPlugins(userPlugins); | |||
| } | |||
| PluginManager::~PluginManager() { | |||
| void destroy() { | |||
| for (Plugin *plugin : plugins) { | |||
| // Free library handle | |||
| #if ARCH_WIN | |||
| @@ -344,7 +346,7 @@ PluginManager::~PluginManager() { | |||
| plugins.clear(); | |||
| } | |||
| void PluginManager::logIn(std::string email, std::string password) { | |||
| void logIn(std::string email, std::string password) { | |||
| 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())); | |||
| @@ -369,11 +371,11 @@ void PluginManager::logIn(std::string email, std::string password) { | |||
| } | |||
| } | |||
| void PluginManager::logOut() { | |||
| void logOut() { | |||
| token = ""; | |||
| } | |||
| bool PluginManager::sync(bool dryRun) { | |||
| bool sync(bool dryRun) { | |||
| if (token.empty()) | |||
| return false; | |||
| @@ -444,7 +446,7 @@ bool PluginManager::sync(bool dryRun) { | |||
| if (!manifestJ) | |||
| continue; | |||
| if (PluginManager_syncPlugin(this, slug, manifestJ, dryRun)) { | |||
| if (syncPlugin(slug, manifestJ, dryRun)) { | |||
| available = true; | |||
| } | |||
| } | |||
| @@ -452,15 +454,15 @@ bool PluginManager::sync(bool dryRun) { | |||
| return available; | |||
| } | |||
| void PluginManager::cancelDownload() { | |||
| void cancelDownload() { | |||
| // TODO | |||
| } | |||
| bool PluginManager::isLoggedIn() { | |||
| bool isLoggedIn() { | |||
| return token != ""; | |||
| } | |||
| Plugin *PluginManager::getPlugin(std::string pluginSlug) { | |||
| Plugin *getPlugin(std::string pluginSlug) { | |||
| for (Plugin *plugin : plugins) { | |||
| if (plugin->slug == pluginSlug) { | |||
| return plugin; | |||
| @@ -469,7 +471,7 @@ Plugin *PluginManager::getPlugin(std::string pluginSlug) { | |||
| return NULL; | |||
| } | |||
| Model *PluginManager::getModel(std::string pluginSlug, std::string modelSlug) { | |||
| Model *getModel(std::string pluginSlug, std::string modelSlug) { | |||
| Plugin *plugin = getPlugin(pluginSlug); | |||
| if (plugin) { | |||
| for (Model *model : plugin->models) { | |||
| @@ -482,4 +484,13 @@ Model *PluginManager::getModel(std::string pluginSlug, std::string modelSlug) { | |||
| } | |||
| std::list<Plugin*> plugins; | |||
| std::string token; | |||
| bool isDownloading = false; | |||
| float downloadProgress = 0.f; | |||
| std::string downloadName; | |||
| std::string loginStatus; | |||
| } // namespace plugin | |||
| } // namespace rack | |||
| @@ -1,7 +1,7 @@ | |||
| #include "settings.hpp" | |||
| #include "logger.hpp" | |||
| #include "window.hpp" | |||
| #include "plugin/PluginManager.hpp" | |||
| #include "plugin.hpp" | |||
| #include "app/Scene.hpp" | |||
| #include "app/ModuleBrowser.hpp" | |||
| #include "engine/Engine.hpp" | |||
| @@ -21,7 +21,7 @@ static json_t *settingsToJson() { | |||
| json_t *rootJ = json_object(); | |||
| // token | |||
| json_t *tokenJ = json_string(context()->plugin->token.c_str()); | |||
| json_t *tokenJ = json_string(plugin::token.c_str()); | |||
| json_object_set_new(rootJ, "token", tokenJ); | |||
| if (!context()->window->isMaximized()) { | |||
| @@ -84,7 +84,7 @@ static void settingsFromJson(json_t *rootJ) { | |||
| // token | |||
| json_t *tokenJ = json_object_get(rootJ, "token"); | |||
| if (tokenJ) | |||
| context()->plugin->token = json_string_value(tokenJ); | |||
| plugin::token = json_string_value(tokenJ); | |||
| // windowSize | |||
| json_t *windowSizeJ = json_object_get(rootJ, "windowSize"); | |||