kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
removed broken scripting interface
rodzic
a487c0aaea
commit
1f3dcc1beb
|
@ -16,8 +16,6 @@
|
|||
#include <core.h>
|
||||
#include <glfw_window.h>
|
||||
#include <options.h>
|
||||
#include <duktape/duktape.h>
|
||||
#include <duktape/duk_console.h>
|
||||
#include <filesystem>
|
||||
#include <gui/menus/theme.h>
|
||||
#include <server.h>
|
||||
|
@ -41,7 +39,6 @@
|
|||
|
||||
namespace core {
|
||||
ConfigManager configManager;
|
||||
ScriptManager scriptManager;
|
||||
ModuleManager moduleManager;
|
||||
ModuleComManager modComManager;
|
||||
GLFWwindow* window;
|
||||
|
@ -75,11 +72,6 @@ static void maximized_callback(GLFWwindow* window, int n) {
|
|||
}
|
||||
}
|
||||
|
||||
duk_ret_t test_func(duk_context *ctx) {
|
||||
printf("Hello from C++\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// main
|
||||
int sdrpp_main(int argc, char *argv[]) {
|
||||
spdlog::info("SDR++ v" VERSION_STR);
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#pragma once
|
||||
#include <config.h>
|
||||
#include <module.h>
|
||||
#include <scripting.h>
|
||||
#include <module.h>
|
||||
#include <module_com.h>
|
||||
|
||||
namespace core {
|
||||
SDRPP_EXPORT ConfigManager configManager;
|
||||
SDRPP_EXPORT ScriptManager scriptManager;
|
||||
SDRPP_EXPORT ModuleManager moduleManager;
|
||||
SDRPP_EXPORT ModuleComManager modComManager;
|
||||
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
* Minimal 'console' binding.
|
||||
*
|
||||
* https://github.com/DeveloperToolsWG/console-object/blob/master/api.md
|
||||
* https://developers.google.com/web/tools/chrome-devtools/debug/console/console-reference
|
||||
* https://developer.mozilla.org/en/docs/Web/API/console
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "duktape.h"
|
||||
#include "duk_console.h"
|
||||
|
||||
/* XXX: Add some form of log level filtering. */
|
||||
|
||||
/* XXX: Should all output be written via e.g. console.write(formattedMsg)?
|
||||
* This would make it easier for user code to redirect all console output
|
||||
* to a custom backend.
|
||||
*/
|
||||
|
||||
/* XXX: Init console object using duk_def_prop() when that call is available. */
|
||||
|
||||
static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) {
|
||||
duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx);
|
||||
FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr;
|
||||
duk_idx_t n = duk_get_top(ctx);
|
||||
duk_idx_t i;
|
||||
|
||||
duk_get_global_string(ctx, "console");
|
||||
duk_get_prop_string(ctx, -1, "format");
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) {
|
||||
/* Slow path formatting. */
|
||||
duk_dup(ctx, -1); /* console.format */
|
||||
duk_dup(ctx, i);
|
||||
duk_call(ctx, 1);
|
||||
duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */
|
||||
}
|
||||
}
|
||||
|
||||
duk_pop_2(ctx);
|
||||
|
||||
duk_push_string(ctx, " ");
|
||||
duk_insert(ctx, 0);
|
||||
duk_join(ctx, n);
|
||||
|
||||
if (error_name) {
|
||||
duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1));
|
||||
duk_push_string(ctx, "name");
|
||||
duk_push_string(ctx, error_name);
|
||||
duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */
|
||||
duk_get_prop_string(ctx, -1, "stack");
|
||||
}
|
||||
|
||||
fprintf(output, "%s\n", duk_to_string(ctx, -1));
|
||||
if (flags & DUK_CONSOLE_FLUSH) {
|
||||
fflush(output);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_assert(duk_context *ctx) {
|
||||
if (duk_to_boolean(ctx, 0)) {
|
||||
return 0;
|
||||
}
|
||||
duk_remove(ctx, 0);
|
||||
|
||||
return duk__console_log_helper(ctx, "AssertionError");
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_log(duk_context *ctx) {
|
||||
return duk__console_log_helper(ctx, NULL);
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_trace(duk_context *ctx) {
|
||||
return duk__console_log_helper(ctx, "Trace");
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_info(duk_context *ctx) {
|
||||
return duk__console_log_helper(ctx, NULL);
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_warn(duk_context *ctx) {
|
||||
return duk__console_log_helper(ctx, NULL);
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_error(duk_context *ctx) {
|
||||
return duk__console_log_helper(ctx, "Error");
|
||||
}
|
||||
|
||||
static duk_ret_t duk__console_dir(duk_context *ctx) {
|
||||
/* For now, just share the formatting of .log() */
|
||||
return duk__console_log_helper(ctx, 0);
|
||||
}
|
||||
|
||||
static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, const char *name, duk_uint_t flags) {
|
||||
duk_push_c_function(ctx, func, DUK_VARARGS);
|
||||
duk_push_string(ctx, "name");
|
||||
duk_push_string(ctx, name);
|
||||
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); /* Improve stacktraces by displaying function name */
|
||||
duk_set_magic(ctx, -1, (duk_int_t) flags);
|
||||
duk_put_prop_string(ctx, -2, name);
|
||||
}
|
||||
|
||||
void duk_console_init(duk_context *ctx, duk_uint_t flags) {
|
||||
duk_uint_t flags_orig;
|
||||
|
||||
/* If both DUK_CONSOLE_STDOUT_ONLY and DUK_CONSOLE_STDERR_ONLY where specified,
|
||||
* just turn off DUK_CONSOLE_STDOUT_ONLY and keep DUK_CONSOLE_STDERR_ONLY.
|
||||
*/
|
||||
if ((flags & DUK_CONSOLE_STDOUT_ONLY) && (flags & DUK_CONSOLE_STDERR_ONLY)) {
|
||||
flags &= ~DUK_CONSOLE_STDOUT_ONLY;
|
||||
}
|
||||
/* Remember the (possibly corrected) flags we received. */
|
||||
flags_orig = flags;
|
||||
|
||||
duk_push_object(ctx);
|
||||
|
||||
/* Custom function to format objects; user can replace.
|
||||
* For now, try JX-formatting and if that fails, fall back
|
||||
* to ToString(v).
|
||||
*/
|
||||
duk_eval_string(ctx,
|
||||
"(function (E) {"
|
||||
"return function format(v){"
|
||||
"try{"
|
||||
"return E('jx',v);"
|
||||
"}catch(e){"
|
||||
"return String(v);" /* String() allows symbols, ToString() internal algorithm doesn't. */
|
||||
"}"
|
||||
"};"
|
||||
"})(Duktape.enc)");
|
||||
duk_put_prop_string(ctx, -2, "format");
|
||||
|
||||
flags = flags_orig;
|
||||
if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) {
|
||||
/* No output indicators were specified; these levels go to stdout. */
|
||||
flags |= DUK_CONSOLE_STDOUT_ONLY;
|
||||
}
|
||||
duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags);
|
||||
duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags);
|
||||
duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */
|
||||
duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags);
|
||||
duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags);
|
||||
|
||||
flags = flags_orig;
|
||||
if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) {
|
||||
/* No output indicators were specified; these levels go to stderr. */
|
||||
flags |= DUK_CONSOLE_STDERR_ONLY;
|
||||
}
|
||||
duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags);
|
||||
duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags);
|
||||
duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */
|
||||
duk__console_reg_vararg_func(ctx, duk__console_dir, "dir", flags);
|
||||
|
||||
duk_put_global_string(ctx, "console");
|
||||
|
||||
/* Proxy wrapping: ensures any undefined console method calls are
|
||||
* ignored silently. This was required specifically by the
|
||||
* DeveloperToolsWG proposal (and was implemented also by Firefox:
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=629607). This is
|
||||
* apparently no longer the preferred way of implementing console.
|
||||
* When Proxy is enabled, whitelist at least .toJSON() to avoid
|
||||
* confusing JX serialization of the console object.
|
||||
*/
|
||||
|
||||
if (flags & DUK_CONSOLE_PROXY_WRAPPER) {
|
||||
/* Tolerate failure to initialize Proxy wrapper in case
|
||||
* Proxy support is disabled.
|
||||
*/
|
||||
(void) duk_peval_string_noresult(ctx,
|
||||
"(function(){"
|
||||
"var D=function(){};"
|
||||
"var W={toJSON:true};" /* whitelisted */
|
||||
"console=new Proxy(console,{"
|
||||
"get:function(t,k){"
|
||||
"var v=t[k];"
|
||||
"return typeof v==='function'||W[k]?v:D;"
|
||||
"}"
|
||||
"});"
|
||||
"})();"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#if !defined(DUK_CONSOLE_H_INCLUDED)
|
||||
#define DUK_CONSOLE_H_INCLUDED
|
||||
|
||||
#include "duktape.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Use a proxy wrapper to make undefined methods (console.foo()) no-ops. */
|
||||
#define DUK_CONSOLE_PROXY_WRAPPER (1U << 0)
|
||||
|
||||
/* Flush output after every call. */
|
||||
#define DUK_CONSOLE_FLUSH (1U << 1)
|
||||
|
||||
/* Send output to stdout only (default is mixed stdout/stderr). */
|
||||
#define DUK_CONSOLE_STDOUT_ONLY (1U << 2)
|
||||
|
||||
/* Send output to stderr only (default is mixed stdout/stderr). */
|
||||
#define DUK_CONSOLE_STDERR_ONLY (1U << 3)
|
||||
|
||||
/* Initialize the console system */
|
||||
extern void duk_console_init(duk_context *ctx, duk_uint_t flags);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* end 'extern "C"' wrapper */
|
||||
|
||||
#endif /* DUK_CONSOLE_H_INCLUDED */
|
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -21,7 +21,6 @@
|
|||
#include <gui/menus/display.h>
|
||||
#include <gui/menus/bandplan.h>
|
||||
#include <gui/menus/sink.h>
|
||||
#include <gui/menus/scripting.h>
|
||||
#include <gui/menus/vfo_color.h>
|
||||
#include <gui/menus/module_manager.h>
|
||||
#include <gui/menus/theme.h>
|
||||
|
@ -65,7 +64,6 @@ void MainWindow::init() {
|
|||
|
||||
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Scripting", scriptingmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Display", displaymenu::draw, NULL);
|
||||
gui::menu.registerEntry("Theme", thememenu::draw, NULL);
|
||||
|
@ -154,7 +152,6 @@ void MainWindow::init() {
|
|||
|
||||
sourecmenu::init();
|
||||
sinkmenu::init();
|
||||
scriptingmenu::init();
|
||||
bandplanmenu::init();
|
||||
displaymenu::init();
|
||||
vfo_color_menu::init();
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#include <gui/menus/scripting.h>
|
||||
#include <core.h>
|
||||
#include <gui/style.h>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
namespace scriptingmenu {
|
||||
void init() {
|
||||
|
||||
}
|
||||
|
||||
void draw(void* ctx) {
|
||||
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||
for (const auto& [name, script] : core::scriptManager.scripts) {
|
||||
bool running = script->running;
|
||||
if (running) { style::beginDisabled(); }
|
||||
if (ImGui::Button(name.c_str(), ImVec2(menuWidth, 0))) {
|
||||
script->run();
|
||||
}
|
||||
if (running) { style::endDisabled(); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace scriptingmenu {
|
||||
void init();
|
||||
void draw(void* ctx);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
#include <scripting.h>
|
||||
#include <duktape/duk_console.h>
|
||||
#include <version.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
ScriptManager::ScriptManager() {
|
||||
|
||||
}
|
||||
|
||||
ScriptManager::Script* ScriptManager::createScript(std::string name, std::string path) {
|
||||
ScriptManager::Script* script = new ScriptManager::Script(this, name, path);
|
||||
scripts[name] = script;
|
||||
return script;
|
||||
}
|
||||
|
||||
ScriptManager::Script::Script(ScriptManager* man, std::string name, std::string path) {
|
||||
this->name = name;
|
||||
manager = man;
|
||||
std::ifstream file(path, std::ios::in);
|
||||
std::stringstream ss;
|
||||
ss << file.rdbuf();
|
||||
code = ss.str();
|
||||
}
|
||||
|
||||
void ScriptManager::Script::run() {
|
||||
ctx = ScriptManager::createContext(manager, name);
|
||||
running = true;
|
||||
if (worker.joinable()) {
|
||||
worker.join();
|
||||
}
|
||||
worker = std::thread(scriptWorker, this);
|
||||
}
|
||||
|
||||
duk_context* ScriptManager::createContext(ScriptManager* _this, std::string name) {
|
||||
duk_context* ctx = duk_create_heap_default();
|
||||
|
||||
duk_console_init(ctx, DUK_CONSOLE_PROXY_WRAPPER);
|
||||
|
||||
duk_push_string(ctx, name.c_str());
|
||||
duk_put_global_string(ctx, "SCRIPT_NAME");
|
||||
|
||||
duk_idx_t sdrppBase = duk_push_object(ctx);
|
||||
|
||||
// API
|
||||
|
||||
duk_push_string(ctx, VERSION_STR);
|
||||
duk_put_prop_string(ctx, sdrppBase, "version");
|
||||
|
||||
duk_push_c_function(ctx, ScriptManager::duk_setSource, 1);
|
||||
duk_put_prop_string(ctx, sdrppBase, "selectSource");
|
||||
|
||||
// Modules
|
||||
|
||||
duk_idx_t modObjId = duk_push_object(ctx);
|
||||
for (const auto& [name, handler] : _this->handlers) {
|
||||
duk_idx_t objId = duk_push_object(ctx);
|
||||
handler.handler(handler.ctx, ctx, objId);
|
||||
duk_put_prop_string(ctx, modObjId, name.c_str());
|
||||
}
|
||||
duk_put_prop_string(ctx, sdrppBase, "modules");
|
||||
|
||||
duk_put_global_string(ctx, "sdrpp");
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// TODO: Switch to spdlog
|
||||
|
||||
void ScriptManager::Script::scriptWorker(Script* script) {
|
||||
if (duk_peval_string(script->ctx, script->code.c_str()) != 0) {
|
||||
printf("Error: %s\n", duk_safe_to_string(script->ctx, -1));
|
||||
//return;
|
||||
}
|
||||
duk_destroy_heap(script->ctx);
|
||||
script->running = false;
|
||||
}
|
||||
|
||||
void ScriptManager::bindScriptRunHandler(std::string name, ScriptManager::ScriptRunHandler_t handler) {
|
||||
// TODO: check if it exists and add a "unbind" function
|
||||
handlers[name] = handler;
|
||||
}
|
||||
|
||||
duk_ret_t ScriptManager::duk_setSource(duk_context* dukCtx) {
|
||||
const char* name = duk_require_string(dukCtx, -1);
|
||||
sigpath::sourceManager.selectSource(name);
|
||||
|
||||
duk_pop_n(dukCtx, 1); // Pop demod name, this and context
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <duktape/duktape.h>
|
||||
|
||||
class ScriptManager {
|
||||
public:
|
||||
ScriptManager();
|
||||
|
||||
friend class Script;
|
||||
|
||||
class Script {
|
||||
public:
|
||||
Script(ScriptManager* man, std::string name, std::string path);
|
||||
void run();
|
||||
bool running = false;
|
||||
|
||||
private:
|
||||
static void scriptWorker(Script* _this);
|
||||
|
||||
duk_context* ctx;
|
||||
std::thread worker;
|
||||
std::string code;
|
||||
std::string name;
|
||||
|
||||
|
||||
ScriptManager* manager;
|
||||
|
||||
};
|
||||
|
||||
struct ScriptRunHandler_t {
|
||||
void (*handler)(void* ctx, duk_context* dukCtx, duk_idx_t objId);
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
void bindScriptRunHandler(std::string name, ScriptManager::ScriptRunHandler_t handler);
|
||||
ScriptManager::Script* createScript(std::string name, std::string path);
|
||||
|
||||
std::map<std::string, ScriptManager::Script*> scripts;
|
||||
|
||||
private:
|
||||
static duk_context* createContext(ScriptManager* _this, std::string name);
|
||||
|
||||
// API
|
||||
static duk_ret_t duk_setSource(duk_context* ctx);
|
||||
|
||||
std::map<std::string, ScriptManager::ScriptRunHandler_t> handlers;
|
||||
|
||||
};
|
Ładowanie…
Reference in New Issue