Browse Source

Rewrite moduleWhitelist data structure and merge algorithm.

tags/v2.0.0
Andrew Belt 2 years ago
parent
commit
23334f32a8
3 changed files with 72 additions and 55 deletions
  1. +10
    -2
      include/settings.hpp
  2. +34
    -43
      src/library.cpp
  3. +28
    -10
      src/settings.cpp

+ 10
- 2
include/settings.hpp View File

@@ -96,8 +96,16 @@ extern std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos;
*/
ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug);

/** pluginSlug -> {moduleSlug} */
extern std::map<std::string, std::set<std::string>> moduleWhitelist;
/** The VCV JSON API returns the data structure
{pluginSlug: [moduleSlugs] or true}
where "true" represents that the user is subscribed to the plugin (all modules and future modules).
C++ isn't weakly typed, so we need the PluginWhitelist data structure to store this information.
*/
struct PluginWhitelist {
bool subscribed = false;
std::set<std::string> moduleSlugs;
};
extern std::map<std::string, PluginWhitelist> moduleWhitelist;

bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug);



+ 34
- 43
src/library.cpp View File

@@ -187,40 +187,33 @@ void checkUpdates() {
}
DEFER({json_decref(manifestsResJ);});

// Get user's plugins list
std::string pluginsUrl = API_URL + "/plugins";
json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, getTokenCookies());
if (!pluginsResJ) {
WARN("Request for user's plugins failed");
updateStatus = "Could not query user's plugins";
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 plugins";
// Get user's modules
std::string modulesUrl = API_URL + "/modules";
json_t* modulesResJ = network::requestJson(network::METHOD_GET, modulesUrl, NULL, getTokenCookies());
if (!modulesResJ) {
WARN("Request for user's modules failed");
updateStatus = "Could not query user's modules";
return;
}
DEFER({json_decref(modulesResJ);});

json_t* manifestsJ = json_object_get(manifestsResJ, "manifests");
json_t* pluginsJ = json_object_get(pluginsResJ, "plugins");
json_t* pluginsJ = json_object_get(modulesResJ, "modules");

size_t pluginIndex;
json_t* pluginJ;
json_array_foreach(pluginsJ, pluginIndex, pluginJ) {
const char* modulesKey;
json_t* modulesJ;
json_object_foreach(pluginsJ, modulesKey, modulesJ) {
std::string pluginSlug = modulesKey;
// Get plugin manifest
std::string slug = json_string_value(pluginJ);
json_t* manifestJ = json_object_get(manifestsJ, slug.c_str());
json_t* manifestJ = json_object_get(manifestsJ, pluginSlug.c_str());
if (!manifestJ) {
WARN("VCV account has plugin %s but no manifest was found", slug.c_str());
WARN("VCV account has plugin %s but no manifest was found", pluginSlug.c_str());
continue;
}

// Don't replace existing UpdateInfo, even if version is newer.
// This keeps things sane and ensures that only one version of each plugin is downloaded to `plugins/` at a time.
auto it = updateInfos.find(slug);
auto it = updateInfos.find(pluginSlug);
if (it != updateInfos.end()) {
continue;
}
@@ -234,7 +227,7 @@ void checkUpdates() {
// Get version
json_t* versionJ = json_object_get(manifestJ, "version");
if (!versionJ) {
// WARN("Plugin %s has no version in manifest", slug.c_str());
// WARN("Plugin %s has no version in manifest", pluginSlug.c_str());
continue;
}
update.version = json_string_value(versionJ);
@@ -244,7 +237,7 @@ void checkUpdates() {
}

// Check if update is needed
plugin::Plugin* p = plugin::getPlugin(slug);
plugin::Plugin* p = plugin::getPlugin(pluginSlug);
if (p && p->version == update.version)
continue;

@@ -259,41 +252,39 @@ void checkUpdates() {
update.changelogUrl = json_string_value(changelogUrlJ);

// Add update to updates map
updateInfos[slug] = update;
updateInfos[pluginSlug] = update;
}

// Get module whitelist
// Merge module whitelist
{
std::string whitelistUrl = API_URL + "/modules";
json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, getTokenCookies());
if (!whitelistResJ) {
WARN("Request for module whitelist failed");
updateStatus = "Could not query user's modules";
return;
}
DEFER({json_decref(whitelistResJ);});

// Clone plugin slugs from settings to temporary whitelist.
// This makes plugins entirely hidden if removed.
std::map<std::string, std::set<std::string>> moduleWhitelist;
// This makes existing plugins entirely hidden if removed from user's VCV account.
std::map<std::string, settings::PluginWhitelist> moduleWhitelist;
for (const auto& pluginPair : settings::moduleWhitelist) {
// Create an empty set
std::string pluginSlug = pluginPair.first;
moduleWhitelist[pluginSlug];
moduleWhitelist[pluginSlug] = settings::PluginWhitelist();
}

// Iterate plugins
json_t* pluginsJ = json_object_get(whitelistResJ, "plugins");
const char* pluginSlug;
const char* modulesKey;
json_t* modulesJ;
json_object_foreach(pluginsJ, pluginSlug, modulesJ) {
json_object_foreach(pluginsJ, modulesKey, modulesJ) {
std::string pluginSlug = modulesKey;
settings::PluginWhitelist& pw = moduleWhitelist[pluginSlug];

// If value is "true", plugin is subscribed
if (json_is_true(modulesJ)) {
pw.subscribed = true;
continue;
}

// 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);
pw.moduleSlugs.insert(moduleSlug);
}
}



+ 28
- 10
src/settings.cpp View File

@@ -62,7 +62,7 @@ bool discordUpdateActivity = true;
BrowserSort browserSort = BROWSER_SORT_UPDATED;
float browserZoom = -1.f;
std::map<std::string, std::map<std::string, ModuleInfo>> moduleInfos;
std::map<std::string, std::set<std::string>> moduleWhitelist;
std::map<std::string, PluginWhitelist> moduleWhitelist;


ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug) {
@@ -81,8 +81,13 @@ bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& modul
// All modules in a plugin are visible if plugin set is empty.
if (pluginIt == moduleWhitelist.end())
return true;
auto moduleIt = pluginIt->second.find(moduleSlug);
if (moduleIt == pluginIt->second.end())
// All modules in a plugin are visible if plugin set is subscribed.
const PluginWhitelist& plugin = pluginIt->second;
if (plugin.subscribed)
return true;
// Check if plugin whitelist contains module
auto moduleIt = plugin.moduleSlugs.find(moduleSlug);
if (moduleIt == plugin.moduleSlugs.end())
return false;
return true;
}
@@ -204,10 +209,20 @@ json_t* toJson() {
// moduleWhitelist
json_t* moduleWhitelistJ = json_object();
for (const auto& pluginPair : moduleWhitelist) {
json_t* pluginJ = json_array();
for (const std::string& moduleSlug : pluginPair.second) {
json_array_append_new(pluginJ, json_stringn(moduleSlug.c_str(), moduleSlug.size()));
const PluginWhitelist& plugin = pluginPair.second;
json_t* pluginJ;

// If plugin is subscribed, set to true, otherwise an array of module slugs.
if (plugin.subscribed) {
pluginJ = json_true();
}
else {
pluginJ = json_array();
for (const std::string& moduleSlug : plugin.moduleSlugs) {
json_array_append_new(pluginJ, json_stringn(moduleSlug.c_str(), moduleSlug.size()));
}
}

json_object_set_new(moduleWhitelistJ, pluginPair.first.c_str(), pluginJ);
}
json_object_set_new(rootJ, "moduleWhitelist", moduleWhitelistJ);
@@ -398,15 +413,18 @@ void fromJson(json_t* rootJ) {
const char* pluginSlug;
json_t* pluginJ;
json_object_foreach(moduleWhitelistJ, pluginSlug, pluginJ) {
// Create an empty modules set, even if there are no modules in the whitelist.
// An empty set means no modules will be displayed in the Browser.
auto& modules = moduleWhitelist[pluginSlug];
auto& plugin = moduleWhitelist[pluginSlug];

if (json_is_true(pluginJ)) {
plugin.subscribed = true;
continue;
}

size_t moduleIndex;
json_t* moduleJ;
json_array_foreach(pluginJ, moduleIndex, moduleJ) {
std::string moduleSlug = json_string_value(moduleJ);
modules.insert(moduleSlug);
plugin.moduleSlugs.insert(moduleSlug);
}
}
}


Loading…
Cancel
Save