Browse Source

Add settingsToJson() and settingsFromJson() to root namespace plugin API, allowing plugins to store plugin-wide user settings.

tags/v2.1.1
Andrew Belt 2 years ago
parent
commit
e57b50604e
6 changed files with 80 additions and 11 deletions
  1. +1
    -0
      adapters/standalone.cpp
  2. +1
    -0
      include/plugin.hpp
  3. +16
    -0
      include/plugin/callbacks.hpp
  4. +2
    -0
      include/settings.hpp
  5. +37
    -11
      src/plugin.cpp
  6. +23
    -0
      src/settings.cpp

+ 1
- 0
adapters/standalone.cpp View File

@@ -273,6 +273,7 @@ int main(int argc, char* argv[]) {
plugin::destroy(); plugin::destroy();
INFO("Destroying network"); INFO("Destroying network");
network::destroy(); network::destroy();
settings::destroy();
INFO("Destroying logger"); INFO("Destroying logger");
logger::destroy(); logger::destroy();




+ 1
- 0
include/plugin.hpp View File

@@ -13,6 +13,7 @@ namespace plugin {


PRIVATE void init(); PRIVATE void init();
PRIVATE void destroy(); PRIVATE void destroy();
PRIVATE void settingsMergeJson(json_t* rootJ);


/** Finds a loaded Plugin by slug. */ /** Finds a loaded Plugin by slug. */
Plugin* getPlugin(const std::string& pluginSlug); Plugin* getPlugin(const std::string& pluginSlug);


+ 16
- 0
include/plugin/callbacks.hpp View File

@@ -16,3 +16,19 @@ Optional in plugins.
*/ */
extern "C" extern "C"
void destroy(); void destroy();

/** Called when saving user settings.
Stored in `settings["pluginSettings"][pluginSlug]`.
Useful for persisting plugin-wide settings.

Optional in plugins.
*/
extern "C"
json_t* settingsToJson();

/** Called after initializing plugin if user plugin settings property is defined.

Optional in plugins.
*/
extern "C"
void settingsFromJson(json_t* rootJ);

+ 2
- 0
include/settings.hpp View File

@@ -83,6 +83,7 @@ enum BrowserSort {
}; };
extern BrowserSort browserSort; extern BrowserSort browserSort;
extern float browserZoom; extern float browserZoom;
extern json_t* pluginSettingsJ;


struct ModuleInfo { struct ModuleInfo {
bool enabled = true; bool enabled = true;
@@ -110,6 +111,7 @@ extern std::map<std::string, PluginWhitelist> moduleWhitelist;
bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug); bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug);


PRIVATE void init(); PRIVATE void init();
PRIVATE void destroy();
PRIVATE json_t* toJson(); PRIVATE json_t* toJson();
PRIVATE void fromJson(json_t* rootJ); PRIVATE void fromJson(json_t* rootJ);
PRIVATE void save(std::string path = ""); PRIVATE void save(std::string path = "");


+ 37
- 11
src/plugin.cpp View File

@@ -41,6 +41,18 @@ namespace plugin {
// private API // private API
//////////////////// ////////////////////



static void* getSymbol(void* handle, const char* name) {
if (!handle)
return NULL;

#if defined ARCH_WIN
return GetProcAddress((HMODULE) handle, name);
#else
return dlsym(handle, name);
#endif
}

/** Returns library handle */ /** Returns library handle */
static void* loadLibrary(std::string libraryPath) { static void* loadLibrary(std::string libraryPath) {
#if defined ARCH_WIN #if defined ARCH_WIN
@@ -100,12 +112,7 @@ static InitCallback loadPluginCallback(Plugin* plugin) {
plugin->handle = loadLibrary(libraryPath); plugin->handle = loadLibrary(libraryPath);


// Get plugin's init() function // Get plugin's init() function
InitCallback initCallback;
#if defined ARCH_WIN
initCallback = (InitCallback) GetProcAddress((HMODULE) plugin->handle, "init");
#else
initCallback = (InitCallback) dlsym(plugin->handle, "init");
#endif
InitCallback initCallback = (InitCallback) getSymbol(plugin->handle, "init");
if (!initCallback) if (!initCallback)
throw Exception("Failed to read init() symbol in %s", libraryPath.c_str()); throw Exception("Failed to read init() symbol in %s", libraryPath.c_str());


@@ -169,6 +176,15 @@ static Plugin* loadPlugin(std::string path) {
Plugin* existingPlugin = getPlugin(plugin->slug); Plugin* existingPlugin = getPlugin(plugin->slug);
if (existingPlugin) if (existingPlugin)
throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str()); throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str());

// Call settingsFromJson() if exists
// Returns NULL for Core.
auto settingsFromJson = (decltype(&::settingsFromJson)) getSymbol(plugin->handle, "settingsFromJson");
if (settingsFromJson) {
json_t* settingsJ = json_object_get(settings::pluginSettingsJ, plugin->slug.c_str());
if (settingsJ)
settingsFromJson(settingsJ);
}
} }
catch (Exception& e) { catch (Exception& e) {
WARN("Could not load plugin %s: %s", path.c_str(), e.what()); WARN("Could not load plugin %s: %s", path.c_str(), e.what());
@@ -265,11 +281,7 @@ static void destroyPlugin(Plugin* plugin) {
typedef void (*DestroyCallback)(); typedef void (*DestroyCallback)();
DestroyCallback destroyCallback = NULL; DestroyCallback destroyCallback = NULL;
if (handle) { if (handle) {
#if defined ARCH_WIN
destroyCallback = (DestroyCallback) GetProcAddress((HMODULE) handle, "destroy");
#else
destroyCallback = (DestroyCallback) dlsym(handle, "destroy");
#endif
destroyCallback = (DestroyCallback) getSymbol(handle, "destroy");
} }
if (destroyCallback) { if (destroyCallback) {
try { try {
@@ -303,6 +315,20 @@ void destroy() {
} }




void settingsMergeJson(json_t* rootJ) {
for (Plugin* plugin : plugins) {
auto settingsToJson = (decltype(&::settingsToJson)) getSymbol(plugin->handle, "settingsToJson");
if (settingsToJson) {
json_t* settingsJ = settingsToJson();
json_object_set_new(rootJ, plugin->slug.c_str(), settingsJ);
}
else {
json_object_del(rootJ, plugin->slug.c_str());
}
}
}


/** Given slug => fallback slug. /** Given slug => fallback slug.
Correctly handles bidirectional fallbacks. Correctly handles bidirectional fallbacks.
To request fallback slugs to be added to this list, open a GitHub issue. To request fallback slugs to be added to this list, open a GitHub issue.


+ 23
- 0
src/settings.cpp View File

@@ -61,6 +61,7 @@ int tipIndex = -1;
bool discordUpdateActivity = true; bool discordUpdateActivity = true;
BrowserSort browserSort = BROWSER_SORT_UPDATED; BrowserSort browserSort = BROWSER_SORT_UPDATED;
float browserZoom = -1.f; float browserZoom = -1.f;
json_t* pluginSettingsJ = NULL;
std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos; std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos;
std::map<std::string, PluginWhitelist> moduleWhitelist; std::map<std::string, PluginWhitelist> moduleWhitelist;


@@ -98,6 +99,12 @@ void init() {
} }




void destroy() {
if (pluginSettingsJ)
json_decref(pluginSettingsJ);
}


json_t* toJson() { json_t* toJson() {
json_t* rootJ = json_object(); json_t* rootJ = json_object();


@@ -176,6 +183,13 @@ json_t* toJson() {


json_object_set_new(rootJ, "browserZoom", json_real(browserZoom)); json_object_set_new(rootJ, "browserZoom", json_real(browserZoom));


// Merge pluginSettings instead of replace so plugins that fail to load don't cause their settings to be deleted.
if (!pluginSettingsJ)
pluginSettingsJ = json_object();
plugin::settingsMergeJson(pluginSettingsJ);
// Don't use *_set_new() here because we need to keep the reference to pluginSettingsJ.
json_object_set(rootJ, "pluginSettings", pluginSettingsJ);

// moduleInfos // moduleInfos
json_t* moduleInfosJ = json_object(); json_t* moduleInfosJ = json_object();
for (const auto& pluginPair : moduleInfos) { for (const auto& pluginPair : moduleInfos) {
@@ -375,6 +389,15 @@ void fromJson(json_t* rootJ) {
if (browserZoomJ) if (browserZoomJ)
browserZoom = json_number_value(browserZoomJ); browserZoom = json_number_value(browserZoomJ);


// Delete previous pluginSettings object
if (pluginSettingsJ) {
json_decref(pluginSettingsJ);
pluginSettingsJ = NULL;
}
pluginSettingsJ = json_object_get(rootJ, "pluginSettings");
if (pluginSettingsJ)
json_incref(pluginSettingsJ);

moduleInfos.clear(); moduleInfos.clear();
json_t* moduleInfosJ = json_object_get(rootJ, "moduleInfos"); json_t* moduleInfosJ = json_object_get(rootJ, "moduleInfos");
if (moduleInfosJ) { if (moduleInfosJ) {


Loading…
Cancel
Save