Browse Source

Add systemOpenBrowser

tags/v0.6.0
Andrew Belt 6 years ago
parent
commit
ef64c13287
8 changed files with 165 additions and 149 deletions
  1. +20
    -14
      include/util/common.hpp
  2. +6
    -2
      src/app/PluginManagerWidget.cpp
  3. +0
    -1
      src/app/RackScene.cpp
  4. +0
    -24
      src/main.cpp
  5. +106
    -97
      src/plugin.cpp
  6. +7
    -7
      src/util/logger.cpp
  7. +4
    -0
      src/util/string.cpp
  8. +22
    -4
      src/util/system.cpp

+ 20
- 14
include/util/common.hpp View File

@@ -8,6 +8,7 @@
#include <assert.h> #include <assert.h>


#include <string> #include <string>
#include <vector>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>


@@ -15,23 +16,28 @@
// Handy macros // Handy macros
//////////////////// ////////////////////


/** Surrounds raw text with quotes
/** Concatenates two literals or two macros
Example: Example:
printf("Hello " STRINGIFY(world))
will expand to
printf("Hello " "world")
and of course the C++ lexer/parser will then concatenate the string literals
#define COUNT 42
CONCAT(myVariable, COUNT)
expands to
myVariable42
*/ */
#define STRINGIFY(x) #x
/** Converts a macro to a string literal
#define CONCAT_LITERAL(x, y) x ## y
#define CONCAT(x, y) CONCAT_LITERAL(x, y)

/** Surrounds raw text with quotes
Example: Example:
#define NAME "world" #define NAME "world"
printf("Hello " TOSTRING(NAME)) printf("Hello " TOSTRING(NAME))
will expand to
expands to
printf("Hello " "world") printf("Hello " "world")
and of course the C++ lexer/parser then concatenates the string literals.
*/ */
#define TOSTRING(x) STRINGIFY(x)
#define TOSTRING_LITERAL(x) #x
#define TOSTRING(x) TOSTRING_LITERAL(x)


/** Produces the length of a static array in number of elements */
#define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0])) #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))


/** Reserve space for `count` enums starting with `name`. /** Reserve space for `count` enums starting with `name`.
@@ -95,10 +101,7 @@ DeferWrapper<F> deferWrapper(F f) {
return DeferWrapper<F>(f); return DeferWrapper<F>(f);
} }


#define DEFER_1(x, y) x##y
#define DEFER_2(x, y) DEFER_1(x, y)
#define DEFER_3(x) DEFER_2(x, __COUNTER__)
#define defer(code) auto DEFER_3(_defer_) = deferWrapper([&]() code)
#define defer(code) auto CONCAT(x, __COUNTER__) = deferWrapper([&]() code)


//////////////////// ////////////////////
// Random number generator // Random number generator
@@ -129,6 +132,7 @@ std::string uppercase(std::string s);
/** Truncates and adds "..." to a string, not exceeding `len` characters */ /** Truncates and adds "..." to a string, not exceeding `len` characters */
std::string ellipsize(std::string s, size_t len); std::string ellipsize(std::string s, size_t len);
bool startsWith(std::string str, std::string prefix); bool startsWith(std::string str, std::string prefix);
bool endsWith(std::string str, std::string suffix);


std::string extractDirectory(std::string path); std::string extractDirectory(std::string path);
std::string extractFilename(std::string path); std::string extractFilename(std::string path);
@@ -139,11 +143,13 @@ std::string extractExtension(std::string path);
// system.cpp // system.cpp
//////////////////// ////////////////////


std::vector<std::string> systemListDirectory(std::string path);

/** Opens a URL, also happens to work with PDFs and folders. /** Opens a URL, also happens to work with PDFs and folders.
Shell injection is possible, so make sure the URL is trusted or hard coded. Shell injection is possible, so make sure the URL is trusted or hard coded.
May block, so open in a new thread. May block, so open in a new thread.
*/ */
void openBrowser(std::string url);
void systemOpenBrowser(std::string url);


//////////////////// ////////////////////
// Debug logger // Debug logger


+ 6
- 2
src/app/PluginManagerWidget.cpp View File

@@ -62,7 +62,9 @@ PluginManagerWidget::PluginManagerWidget() {


struct RegisterButton : Button { struct RegisterButton : Button {
void onAction(EventAction &e) override { void onAction(EventAction &e) override {
std::thread t(openBrowser, "https://vcvrack.com/");
std::thread t([&]() {
systemOpenBrowser("https://vcvrack.com/");
});
t.detach(); t.detach();
} }
}; };
@@ -126,7 +128,9 @@ PluginManagerWidget::PluginManagerWidget() {


struct ManageButton : Button { struct ManageButton : Button {
void onAction(EventAction &e) override { void onAction(EventAction &e) override {
std::thread t(openBrowser, "https://vcvrack.com/");
std::thread t([&]() {
systemOpenBrowser("https://vcvrack.com/");
});
t.detach(); t.detach();
} }
}; };


+ 0
- 1
src/app/RackScene.cpp View File

@@ -1,7 +1,6 @@
#include "app.hpp" #include "app.hpp"
#include "window.hpp" #include "window.hpp"
#include "util/request.hpp" #include "util/request.hpp"
#include "osdialog.h"
#include <string.h> #include <string.h>
#include <thread> #include <thread>




+ 0
- 24
src/main.cpp View File

@@ -10,35 +10,11 @@


#include <unistd.h> #include <unistd.h>


#include <dirent.h>



using namespace rack; using namespace rack;




std::vector<std::string> filesystemListDirectory(std::string path) {
std::vector<std::string> filenames;
DIR *dir = opendir(path.c_str());
if (dir) {
struct dirent *d;
while ((d = readdir(dir))) {
std::string filename = d->d_name;
if (filename == "." || filename == "..")
continue;
filenames.push_back(path + "/" + filename);
}
closedir(dir);
}
return filenames;
}

int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {

for (std::string filename : filesystemListDirectory("plugins")) {
debug("%s", filename.c_str());
}
return 0;

randomInit(); randomInit();
loggerInit(); loggerInit();




+ 106
- 97
src/plugin.cpp View File

@@ -1,5 +1,10 @@
#include <stdio.h>
#include "plugin.hpp"
#include "app.hpp"
#include "asset.hpp"
#include "util/request.hpp"
#include "osdialog.h"


#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -13,7 +18,7 @@
#include <zip.h> #include <zip.h>
#include <jansson.h> #include <jansson.h>


#if defined(ARCH_WIN)
#if ARCH_WIN
#include <windows.h> #include <windows.h>
#include <direct.h> #include <direct.h>
#define mkdir(_dir, _perms) _mkdir(_dir) #define mkdir(_dir, _perms) _mkdir(_dir)
@@ -22,14 +27,10 @@
#endif #endif
#include <dirent.h> #include <dirent.h>


#include "plugin.hpp"
#include "app.hpp"
#include "asset.hpp"
#include "util/request.hpp"



namespace rack { namespace rack {



std::list<Plugin*> gPlugins; std::list<Plugin*> gPlugins;
std::string gToken; std::string gToken;


@@ -73,7 +74,7 @@ static int loadPlugin(std::string path) {
warn("Failed to load library %s: %d", libraryFilename.c_str(), error); warn("Failed to load library %s: %d", libraryFilename.c_str(), error);
return -1; return -1;
} }
#elif ARCH_LIN || ARCH_MAC
#else
void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW); void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW);
if (!handle) { if (!handle) {
warn("Failed to load library %s: %s", libraryFilename.c_str(), dlerror()); warn("Failed to load library %s: %s", libraryFilename.c_str(), dlerror());
@@ -86,7 +87,7 @@ static int loadPlugin(std::string path) {
InitCallback initCallback; InitCallback initCallback;
#if ARCH_WIN #if ARCH_WIN
initCallback = (InitCallback) GetProcAddress(handle, "init"); initCallback = (InitCallback) GetProcAddress(handle, "init");
#elif ARCH_LIN || ARCH_MAC
#else
initCallback = (InitCallback) dlsym(handle, "init"); initCallback = (InitCallback) dlsym(handle, "init");
#endif #endif
if (!initCallback) { if (!initCallback) {
@@ -117,80 +118,6 @@ static int loadPlugin(std::string path) {
return 0; return 0;
} }


static void loadPlugins(std::string path) {
DIR *dir = opendir(path.c_str());
if (dir) {
struct dirent *d;
while ((d = readdir(dir))) {
if (d->d_name[0] == '.')
continue;
loadPlugin(path + "/" + d->d_name);
}
closedir(dir);
}
}

////////////////////
// plugin helpers
////////////////////

static int extractZipHandle(zip_t *za, const char *dir) {
int err = 0;
for (int i = 0; i < zip_get_num_entries(za, 0); i++) {
zip_stat_t zs;
err = zip_stat_index(za, i, 0, &zs);
if (err)
return err;
int nameLen = strlen(zs.name);

char path[MAXPATHLEN];
snprintf(path, sizeof(path), "%s/%s", dir, zs.name);

if (zs.name[nameLen - 1] == '/') {
err = mkdir(path, 0755);
if (err && errno != EEXIST)
return err;
}
else {
zip_file_t *zf = zip_fopen_index(za, i, 0);
if (!zf)
return 1;

FILE *outFile = fopen(path, "wb");
if (!outFile)
continue;

while (1) {
char buffer[4096];
int len = zip_fread(zf, buffer, sizeof(buffer));
if (len <= 0)
break;
fwrite(buffer, 1, len, outFile);
}

err = zip_fclose(zf);
if (err)
return err;
fclose(outFile);
}
}
return 0;
}

static int extractZip(const char *filename, const char *dir) {
int err = 0;
zip_t *za = zip_open(filename, 0, &err);
if (!za)
return 1;

if (!err) {
err = extractZipHandle(za, dir);
}

zip_close(za);
return err;
}

static bool syncPlugin(json_t *pluginJ, bool dryRun) { static bool syncPlugin(json_t *pluginJ, bool dryRun) {
json_t *slugJ = json_object_get(pluginJ, "slug"); json_t *slugJ = json_object_get(pluginJ, "slug");
if (!slugJ) if (!slugJ)
@@ -223,11 +150,11 @@ static bool syncPlugin(json_t *pluginJ, bool dryRun) {


json_t *downloadsJ = json_object_get(pluginJ, "downloads"); json_t *downloadsJ = json_object_get(pluginJ, "downloads");
if (downloadsJ) { if (downloadsJ) {
#if defined(ARCH_WIN)
#if ARCH_WIN
#define DOWNLOADS_ARCH "win" #define DOWNLOADS_ARCH "win"
#elif defined(ARCH_MAC)
#elif ARCH_MAC
#define DOWNLOADS_ARCH "mac" #define DOWNLOADS_ARCH "mac"
#elif defined(ARCH_LIN)
#elif ARCH_LIN
#define DOWNLOADS_ARCH "lin" #define DOWNLOADS_ARCH "lin"
#endif #endif
json_t *archJ = json_object_get(downloadsJ, DOWNLOADS_ARCH); json_t *archJ = json_object_get(downloadsJ, DOWNLOADS_ARCH);
@@ -281,15 +208,6 @@ static bool syncPlugin(json_t *pluginJ, bool dryRun) {
} }
} }


// Unzip file
int err = extractZip(zipPath.c_str(), pluginsDir.c_str());
if (!err) {
// Delete zip
remove(zipPath.c_str());
// Load plugin
// loadPlugin(pluginPath);
}

downloadName = ""; downloadName = "";
return true; return true;
} }
@@ -378,6 +296,95 @@ bool pluginSync(bool dryRun) {
return available; return available;
} }


static void loadPlugins(std::string path) {
DIR *dir = opendir(path.c_str());
if (dir) {
struct dirent *d;
while ((d = readdir(dir))) {
if (d->d_name[0] == '.')
continue;
loadPlugin(path + "/" + d->d_name);
}
closedir(dir);
}
}

static int extractZipHandle(zip_t *za, const char *dir) {
int err = 0;
for (int i = 0; i < zip_get_num_entries(za, 0); i++) {
zip_stat_t zs;
err = zip_stat_index(za, i, 0, &zs);
if (err)
return err;
int nameLen = strlen(zs.name);

char path[MAXPATHLEN];
snprintf(path, sizeof(path), "%s/%s", dir, zs.name);

if (zs.name[nameLen - 1] == '/') {
err = mkdir(path, 0755);
if (err && errno != EEXIST)
return err;
}
else {
zip_file_t *zf = zip_fopen_index(za, i, 0);
if (!zf)
return 1;

FILE *outFile = fopen(path, "wb");
if (!outFile)
continue;

while (1) {
char buffer[4096];
int len = zip_fread(zf, buffer, sizeof(buffer));
if (len <= 0)
break;
fwrite(buffer, 1, len, outFile);
}

err = zip_fclose(zf);
if (err)
return err;
fclose(outFile);
}
}
return 0;
}

static int extractZip(const char *filename, const char *dir) {
int err = 0;
zip_t *za = zip_open(filename, 0, &err);
if (!za)
return 1;

if (!err) {
err = extractZipHandle(za, dir);
}

zip_close(za);
return err;
}

static void extractPackages(std::string path) {
std::string message;

for (std::string packagePath : systemListDirectory(path)) {
if (endsWith(packagePath, ".zip")) {
// Extract package
if (!extractZip(packagePath.c_str(), path.c_str())) {
message += stringf("Could not extract package %s\n", path);
continue;
}
// Remove package
remove(packagePath.c_str());
}
}
if (!message.empty()) {
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
}
}

//////////////////// ////////////////////
// plugin API // plugin API
//////////////////// ////////////////////
@@ -401,6 +408,8 @@ void pluginInit() {
// Load plugins from local directory // Load plugins from local directory
std::string localPlugins = assetLocal("plugins"); std::string localPlugins = assetLocal("plugins");
mkdir(localPlugins.c_str(), 0755); mkdir(localPlugins.c_str(), 0755);
info("Unzipping plugins from %s", localPlugins.c_str());
extractPackages(localPlugins);
info("Loading plugins from %s", localPlugins.c_str()); info("Loading plugins from %s", localPlugins.c_str());
loadPlugins(localPlugins); loadPlugins(localPlugins);
} }
@@ -408,10 +417,10 @@ void pluginInit() {
void pluginDestroy() { void pluginDestroy() {
for (Plugin *plugin : gPlugins) { for (Plugin *plugin : gPlugins) {
// Free library handle // Free library handle
#if defined(ARCH_WIN)
#if ARCH_WIN
if (plugin->handle) if (plugin->handle)
FreeLibrary((HINSTANCE)plugin->handle); FreeLibrary((HINSTANCE)plugin->handle);
#elif defined(ARCH_LIN) || defined(ARCH_MAC)
#else
if (plugin->handle) if (plugin->handle)
dlclose(plugin->handle); dlclose(plugin->handle);
#endif #endif


+ 7
- 7
src/util/logger.cpp View File

@@ -11,16 +11,16 @@ static auto startTime = std::chrono::high_resolution_clock::now();




void loggerInit() { void loggerInit() {
#ifdef RELEASE
std::string logFilename = assetLocal("log.txt");
gLogFile = fopen(logFilename.c_str(), "w");
#endif
#ifdef RELEASE
std::string logFilename = assetLocal("log.txt");
logFile = fopen(logFilename.c_str(), "w");
#endif
} }


void loggerDestroy() { void loggerDestroy() {
#ifdef RELEASE
fclose(gLogFile);
#endif
#ifdef RELEASE
fclose(logFile);
#endif
} }


static void printTimestamp() { static void printTimestamp() {


+ 4
- 0
src/util/string.cpp View File

@@ -45,6 +45,10 @@ bool startsWith(std::string str, std::string prefix) {
return str.substr(0, prefix.size()) == prefix; return str.substr(0, prefix.size()) == prefix;
} }


bool endsWith(std::string str, std::string suffix) {
return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
}

std::string extractDirectory(std::string path) { std::string extractDirectory(std::string path) {
char *pathDup = strdup(path.c_str()); char *pathDup = strdup(path.c_str());
std::string directory = dirname(pathDup); std::string directory = dirname(pathDup);


+ 22
- 4
src/util/system.cpp View File

@@ -1,18 +1,36 @@
#include "util/common.hpp" #include "util/common.hpp"


#include <dirent.h>

#if ARCH_WIN #if ARCH_WIN
#include <windows.h>
#include <shellapi.h>
#include <windows.h>
#include <shellapi.h>
#endif #endif




namespace rack { namespace rack {




void openBrowser(std::string url) {
std::vector<std::string> systemListDirectory(std::string path) {
std::vector<std::string> filenames;
DIR *dir = opendir(path.c_str());
if (dir) {
struct dirent *d;
while ((d = readdir(dir))) {
std::string filename = d->d_name;
if (filename == "." || filename == "..")
continue;
filenames.push_back(path + "/" + filename);
}
closedir(dir);
}
return filenames;
}

void systemOpenBrowser(std::string url) {
#if ARCH_LIN #if ARCH_LIN
std::string command = "xdg-open " + url; std::string command = "xdg-open " + url;
(void)system(command.c_str());
(void) system(command.c_str());
#endif #endif
#if ARCH_MAC #if ARCH_MAC
std::string command = "open " + url; std::string command = "open " + url;


Loading…
Cancel
Save