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 <string>
#include <vector>
#include <condition_variable>
#include <mutex>

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

/** Surrounds raw text with quotes
/** Concatenates two literals or two macros
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:
#define NAME "world"
printf("Hello " TOSTRING(NAME))
will expand to
expands to
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]))

/** Reserve space for `count` enums starting with `name`.
@@ -95,10 +101,7 @@ DeferWrapper<F> 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
@@ -129,6 +132,7 @@ std::string uppercase(std::string s);
/** Truncates and adds "..." to a string, not exceeding `len` characters */
std::string ellipsize(std::string s, size_t len);
bool startsWith(std::string str, std::string prefix);
bool endsWith(std::string str, std::string suffix);

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

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

/** 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.
May block, so open in a new thread.
*/
void openBrowser(std::string url);
void systemOpenBrowser(std::string url);

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


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

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

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

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


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

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



+ 0
- 24
src/main.cpp View File

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

#include <unistd.h>

#include <dirent.h>


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[]) {

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

randomInit();
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 <string.h>
#include <unistd.h>
@@ -13,7 +18,7 @@
#include <zip.h>
#include <jansson.h>

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

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


namespace rack {


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

@@ -73,7 +74,7 @@ static int loadPlugin(std::string path) {
warn("Failed to load library %s: %d", libraryFilename.c_str(), error);
return -1;
}
#elif ARCH_LIN || ARCH_MAC
#else
void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW);
if (!handle) {
warn("Failed to load library %s: %s", libraryFilename.c_str(), dlerror());
@@ -86,7 +87,7 @@ static int loadPlugin(std::string path) {
InitCallback initCallback;
#if ARCH_WIN
initCallback = (InitCallback) GetProcAddress(handle, "init");
#elif ARCH_LIN || ARCH_MAC
#else
initCallback = (InitCallback) dlsym(handle, "init");
#endif
if (!initCallback) {
@@ -117,80 +118,6 @@ static int loadPlugin(std::string path) {
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) {
json_t *slugJ = json_object_get(pluginJ, "slug");
if (!slugJ)
@@ -223,11 +150,11 @@ static bool syncPlugin(json_t *pluginJ, bool dryRun) {

json_t *downloadsJ = json_object_get(pluginJ, "downloads");
if (downloadsJ) {
#if defined(ARCH_WIN)
#if ARCH_WIN
#define DOWNLOADS_ARCH "win"
#elif defined(ARCH_MAC)
#elif ARCH_MAC
#define DOWNLOADS_ARCH "mac"
#elif defined(ARCH_LIN)
#elif ARCH_LIN
#define DOWNLOADS_ARCH "lin"
#endif
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 = "";
return true;
}
@@ -378,6 +296,95 @@ bool pluginSync(bool dryRun) {
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
////////////////////
@@ -401,6 +408,8 @@ void pluginInit() {
// Load plugins from local directory
std::string localPlugins = assetLocal("plugins");
mkdir(localPlugins.c_str(), 0755);
info("Unzipping plugins from %s", localPlugins.c_str());
extractPackages(localPlugins);
info("Loading plugins from %s", localPlugins.c_str());
loadPlugins(localPlugins);
}
@@ -408,10 +417,10 @@ void pluginInit() {
void pluginDestroy() {
for (Plugin *plugin : gPlugins) {
// Free library handle
#if defined(ARCH_WIN)
#if ARCH_WIN
if (plugin->handle)
FreeLibrary((HINSTANCE)plugin->handle);
#elif defined(ARCH_LIN) || defined(ARCH_MAC)
#else
if (plugin->handle)
dlclose(plugin->handle);
#endif


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

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


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() {
#ifdef RELEASE
fclose(gLogFile);
#endif
#ifdef RELEASE
fclose(logFile);
#endif
}

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;
}

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

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


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

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

#include <dirent.h>

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


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
std::string command = "xdg-open " + url;
(void)system(command.c_str());
(void) system(command.c_str());
#endif
#if ARCH_MAC
std::string command = "open " + url;


Loading…
Cancel
Save