From 9e1bab03ebfb3053398ca68ab6536d61ae092707 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sun, 14 Nov 2021 22:55:21 +0000 Subject: [PATCH] Made it easier to run multiple instances. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3687 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- src/database.js.c | 3 +- src/main.c | 127 ++++++++++++++++++++++++++++++++++------------ src/task.c | 33 ++++++------ 3 files changed, 113 insertions(+), 50 deletions(-) diff --git a/src/database.js.c b/src/database.js.c index fdb9144f..5bb3d85e 100644 --- a/src/database.js.c +++ b/src/database.js.c @@ -30,7 +30,8 @@ static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int void tf_database_register(JSContext* context, sqlite3* sqlite) { JS_NewClassID(&_database_class_id); - JSClassDef def = { + JSClassDef def = + { .class_name = "Database", .finalizer = &_database_finalizer, }; diff --git a/src/main.c b/src/main.c index 1ed80ae6..6d10b562 100644 --- a/src/main.c +++ b/src/main.c @@ -298,34 +298,83 @@ xopt_help: return 1; } +typedef struct tf_run_args_t { + const char* script; + int ssb_port; + int http_port; + int https_port; + const char* db_path; + const char* secrets_path; + int count; + bool help; +} tf_run_args_t; + +typedef struct _tf_run_thread_data_t +{ + tf_run_args_t args; + int index; + int result; +} tf_run_thread_data_t; + +static int _tf_run_task(const tf_run_args_t* args, int index) +{ + int result = -1; + tf_task_t* task = tf_task_create(); + tf_task_set_trusted(task, true); + tf_task_set_ssb_port(task, args->ssb_port ? args->ssb_port + index : 0); + tf_task_set_http_port(task, args->http_port ? args->http_port + index : 0); + tf_task_set_https_port(task, args->https_port ? args->https_port + index : 0); + const char* db_path = args->db_path; + const char* secrets_path = args->secrets_path; + char db_path_buffer[256]; + char secrets_path_buffer[256]; + if (index) + { + snprintf(db_path_buffer, sizeof(db_path_buffer), "%s.%d", args->db_path, index); + db_path = db_path_buffer; + snprintf(secrets_path_buffer, sizeof(secrets_path_buffer), "%s.%d", args->secrets_path, index); + secrets_path = secrets_path_buffer; + } + tf_task_set_db_path(task, db_path); + tf_task_set_secrets_path(task, secrets_path); + tf_task_activate(task); + if (tf_task_execute(task, args->script)) + { + tf_task_run(task); + result = 0; + } + tf_task_destroy(task); + return result; +} + +static void _tf_run_task_thread(void* data) +{ + tf_run_thread_data_t* info = data; + info->result = _tf_run_task(&info->args, info->index); +} + static int _tf_command_run(const char* file, int argc, char* argv[]) { - typedef struct args_t { - const char* script; - int ssb_port; - int http_port; - int https_port; - const char* db_path; - const char* secrets_path; - bool help; - } args_t; - xoptOption options[] = { - { "script", 's', offsetof(args_t, script), NULL, XOPT_TYPE_STRING, NULL, "Script to run (default: core/core.js)." }, - { "ssb-port", 'b', offsetof(args_t, ssb_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run SSB (default: 8009)." }, - { "http-port", 'p', offsetof(args_t, http_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run Tilde Friends web server (default: 12345)." }, - { "https-port", 'q', offsetof(args_t, https_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run secure Tilde Friends web server (default: 12346)." }, - { "db-path", 'd', offsetof(args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." }, - { "secrets-path", 'i', offsetof(args_t, secrets_path), NULL, XOPT_TYPE_STRING, NULL, "Secrets/identity path." }, - { "help", 'h', offsetof(args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, + { "script", 's', offsetof(tf_run_args_t, script), NULL, XOPT_TYPE_STRING, NULL, "Script to run (default: core/core.js)." }, + { "ssb-port", 'b', offsetof(tf_run_args_t, ssb_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run SSB (default: 8009)." }, + { "http-port", 'p', offsetof(tf_run_args_t, http_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run Tilde Friends web server (default: 12345)." }, + { "https-port", 'q', offsetof(tf_run_args_t, https_port), NULL, XOPT_TYPE_INT, NULL, "Port on which to run secure Tilde Friends web server (default: 12346)." }, + { "db-path", 'd', offsetof(tf_run_args_t, db_path), NULL, XOPT_TYPE_STRING, NULL, "Sqlite database path (default: db.sqlite)." }, + { "secrets-path", 'i', offsetof(tf_run_args_t, secrets_path), NULL, XOPT_TYPE_STRING, NULL, "Secrets/identity path." }, + { "count", 'n', offsetof(tf_run_args_t, count), NULL, XOPT_TYPE_INT, NULL, "Number of instances to run." }, + { "help", 'h', offsetof(tf_run_args_t, help), NULL, XOPT_TYPE_BOOL, NULL, "Shows this help message." }, XOPT_NULLOPTION, }; - args_t args = { + tf_run_args_t args = + { + .count = 1, .script = "core/core.js", .http_port = 12345, .ssb_port = 8009, .db_path = "db.sqlite", + .secrets_path = "/.config/tildefriends/secret", }; const char** extras = NULL; int extra_count = 0; @@ -350,24 +399,36 @@ static int _tf_command_run(const char* file, int argc, char* argv[]) #if !defined (_WIN32) && !defined (__MACH__) setpgid(0, 0); #endif - tf_task_t* task = tf_task_create(); - tf_task_set_trusted(task, true); - tf_task_set_ssb_port(task, args.ssb_port); - tf_task_set_http_port(task, args.http_port); - tf_task_set_https_port(task, args.https_port); - tf_task_set_db_path(task, args.db_path); - tf_task_set_secrets_path(task, args.secrets_path); - tf_task_activate(task); - if (!tf_task_execute(task, args.script)) + + if (args.count == 1) { - result = -1; + _tf_run_task(&args, 0); + } + if (args.count > 1) + { + uv_thread_t* threads = malloc(sizeof(uv_thread_t) * args.count); + tf_run_thread_data_t* data = malloc(sizeof(tf_run_thread_data_t) * args.count); + for (int i = 0 ; i < args.count; i++) + { + data[i] = (tf_run_thread_data_t) + { + .args = args, + .index = i, + }; + uv_thread_create(&threads[i], _tf_run_task_thread, &data[i]); + } + for (int i = 0; i < args.count; i++) + { + uv_thread_join(&threads[i]); + if (data[i].result != 0) + { + result = data[i].result; + } + } + free(data); + free(threads); } - if (result == 0) - { - tf_task_run(task); - } - tf_task_destroy(task); return result; xopt_help: diff --git a/src/task.c b/src/task.c index 52ae23f4..97107d2b 100644 --- a/src/task.c +++ b/src/task.c @@ -91,7 +91,7 @@ typedef struct _tf_task_t { promise_t* _promises; int _promise_count; promiseid_t _nextPromise; - uv_loop_t* _loop; + uv_loop_t _loop; export_record_t* _exports; int _export_count; @@ -105,8 +105,8 @@ typedef struct _tf_task_t { int _ssb_port; int _http_port; int _https_port; - const char* _db_path; - const char* _secrets_path; + char _db_path[256]; + char _secrets_path[256]; } tf_task_t; typedef struct _export_record_t { @@ -294,7 +294,7 @@ static JSValue _task_setTimeout(JSContext* context, JSValueConst this_val, int a uv_timer_t* timer = malloc(sizeof(uv_timer_t)); memset(timer, 0, sizeof(uv_timer_t)); - uv_timer_init(task->_loop, timer); + uv_timer_init(&task->_loop, timer); timer->data = timeout; int64_t duration; @@ -882,7 +882,7 @@ static const char* _tf_task_resolveRequire(tf_task_t* task, const char* require) snprintf(test, sizeof(test), "%s/%s%s", task->_path, require, strstr(require, ".js") ? "" : ".js"); printf("Testing %s\n", test); uv_fs_t request; - if (uv_fs_access(task->_loop, &request, test, R_OK, 0) == 0) + if (uv_fs_access(&task->_loop, &request, test, R_OK, 0) == 0) { return strdup(test); } @@ -1049,7 +1049,7 @@ JSValue _tf_task_sandbox_require(JSContext* context, JSValueConst this_val, int uv_loop_t* tf_task_get_loop(tf_task_t* task) { - return task->_loop; + return &task->_loop; } static promise_t* _tf_task_find_promise(tf_task_t* task, promiseid_t id) @@ -1219,8 +1219,6 @@ tf_task_t* tf_task_create() { tf_task_t* task = malloc(sizeof(tf_task_t)); *task = (tf_task_t) { 0 }; - task->_loop = uv_loop_new(); - task->_loop->data = task; ++_count; task->_runtime = JS_NewRuntime(); task->_context = JS_NewContext(task->_runtime); @@ -1229,7 +1227,8 @@ tf_task_t* tf_task_create() JS_SetHostPromiseRejectionTracker(task->_runtime, _tf_task_promise_rejection_tracker, task); JS_NewClassID(&_import_class_id); - JSClassDef def = { + JSClassDef def = + { .class_name = "imported_function", .finalizer = _import_finalizer, .gc_mark = _import_mark_func, @@ -1237,6 +1236,8 @@ tf_task_t* tf_task_create() }; JS_NewClass(task->_runtime, _import_class_id, &def); task->_loadedFiles = JS_NewObject(task->_context); + uv_loop_init(&task->_loop); + task->_loop.data = task; return task; } @@ -1263,7 +1264,7 @@ void tf_task_activate(tf_task_t* task) if (task->_trusted) { - sqlite3_open(task->_db_path ? task->_db_path : "db.sqlite", &task->_db); + sqlite3_open(*task->_db_path ? task->_db_path : "db.sqlite", &task->_db); JS_SetPropertyStr(context, global, "require", JS_NewCFunction(context, _tf_task_require, "require", 1)); JS_SetPropertyStr(context, global, "Task", tf_taskstub_register(context)); @@ -1274,7 +1275,7 @@ void tf_task_activate(tf_task_t* task) task->_trace = tf_trace_create(); - task->_ssb = tf_ssb_create(task->_loop, task->_context, task->_db, task->_secrets_path); + task->_ssb = tf_ssb_create(&task->_loop, task->_context, task->_db, *task->_secrets_path ? task->_secrets_path : NULL); tf_ssb_set_trace(task->_ssb, task->_trace); tf_ssb_register(context, task->_ssb); @@ -1302,7 +1303,7 @@ void tf_task_activate(tf_task_t* task) void tf_task_run(tf_task_t* task) { - uv_run(task->_loop, UV_RUN_DEFAULT); + uv_run(&task->_loop, UV_RUN_DEFAULT); } void tf_task_set_trusted(tf_task_t* task, bool trusted) @@ -1377,8 +1378,8 @@ void tf_task_destroy(tf_task_t* task) sqlite3_close(task->_db); } - uv_print_all_handles(task->_loop, stdout); - uv_loop_delete(task->_loop); + uv_print_all_handles(&task->_loop, stdout); + uv_loop_close(&task->_loop); --_count; free((void*)task->_path); free(task); @@ -1454,12 +1455,12 @@ void tf_task_set_https_port(tf_task_t* task, int port) void tf_task_set_db_path(tf_task_t* task, const char* db_path) { - task->_db_path = db_path; + snprintf(task->_db_path, sizeof(task->_db_path), "%s", db_path); } void tf_task_set_secrets_path(tf_task_t* task, const char* secrets_path) { - task->_secrets_path = secrets_path; + snprintf(task->_secrets_path, sizeof(task->_secrets_path), "%s", secrets_path); } const char* tf_task_get_name(tf_task_t* task)