Compare commits
5 Commits
v0.0.27.1
...
f1a2c5ae8e
Author | SHA1 | Date | |
---|---|---|---|
f1a2c5ae8e | |||
192a81ede7 | |||
916aa5abbd | |||
d4a5cc6eee | |||
d19605cc8d |
@ -16,8 +16,8 @@ MAKEFLAGS += --no-builtin-rules
|
|||||||
## LD := Linker.
|
## LD := Linker.
|
||||||
## ANDROID_SDK := Path to the Android SDK.
|
## ANDROID_SDK := Path to the Android SDK.
|
||||||
|
|
||||||
VERSION_CODE := 32
|
VERSION_CODE := 33
|
||||||
VERSION_NUMBER := 0.0.27
|
VERSION_NUMBER := 0.0.28-wip
|
||||||
VERSION_NAME := This program kills fascists.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3480000.zip
|
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3480000.zip
|
||||||
|
@ -21,14 +21,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.27";
|
version = "0.0.27.1";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitea {
|
src = pkgs.fetchFromGitea {
|
||||||
domain = "dev.tildefriends.net";
|
domain = "dev.tildefriends.net";
|
||||||
owner = "cory";
|
owner = "cory";
|
||||||
repo = "tildefriends";
|
repo = "tildefriends";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
hash = "sha256-NhoTBWYsWc206f1+M9haxHSJU6ZSGoP5nPStymAIyRk=";
|
hash = "sha256-3t1m9ZomQF3DteWyALJWrnCq0EAROEK8shKXh6Ao38c=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="32"
|
android:versionCode="33"
|
||||||
android:versionName="0.0.27">
|
android:versionName="0.0.28-wip">
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
105
src/file.js.c
105
src/file.js.c
@ -18,21 +18,8 @@
|
|||||||
|
|
||||||
static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static JSValue _file_read_file_zip(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _file_read_file_zip(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
|
||||||
static JSValue _file_stat_zip(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
|
||||||
static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
|
|
||||||
static double _time_spec_to_double(const uv_timespec_t* time_spec);
|
|
||||||
static void _file_on_stat_complete(uv_fs_t* request);
|
|
||||||
|
|
||||||
typedef struct file_stat_t
|
|
||||||
{
|
|
||||||
void* _task;
|
|
||||||
JSContext* _context;
|
|
||||||
promiseid_t _promise;
|
|
||||||
uv_fs_t _request;
|
|
||||||
} file_stat_t;
|
|
||||||
|
|
||||||
typedef struct fs_req_t
|
typedef struct fs_req_t
|
||||||
{
|
{
|
||||||
uv_fs_t fs;
|
uv_fs_t fs;
|
||||||
@ -45,12 +32,11 @@ void tf_file_register(JSContext* context)
|
|||||||
{
|
{
|
||||||
JSValue global = JS_GetGlobalObject(context);
|
JSValue global = JS_GetGlobalObject(context);
|
||||||
JSValue file = JS_NewObject(context);
|
JSValue file = JS_NewObject(context);
|
||||||
void* task = JS_GetContextOpaque(context);
|
tf_task_t* task = JS_GetContextOpaque(context);
|
||||||
const char* zip = tf_task_get_zip_path(task);
|
const char* zip = tf_task_get_zip_path(task);
|
||||||
JS_SetPropertyStr(context, global, "File", file);
|
JS_SetPropertyStr(context, global, "File", file);
|
||||||
JS_SetPropertyStr(context, file, "readFile", JS_NewCFunction(context, zip ? _file_read_file_zip : _file_read_file, "readFile", 1));
|
JS_SetPropertyStr(context, file, "readFile", JS_NewCFunction(context, zip ? _file_read_file_zip : _file_read_file, "readFile", 1));
|
||||||
JS_SetPropertyStr(context, file, "writeFile", JS_NewCFunction(context, _file_write_file, "writeFile", 2));
|
JS_SetPropertyStr(context, file, "writeFile", JS_NewCFunction(context, _file_write_file, "writeFile", 2));
|
||||||
JS_SetPropertyStr(context, file, "stat", JS_NewCFunction(context, zip ? _file_stat_zip : _file_stat, "stat", 1));
|
|
||||||
JS_FreeValue(context, global);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +109,7 @@ static void _file_write_open_callback(uv_fs_t* req)
|
|||||||
|
|
||||||
static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
void* task = JS_GetContextOpaque(context);
|
tf_task_t* task = JS_GetContextOpaque(context);
|
||||||
const char* file_name = JS_ToCString(context, argv[0]);
|
const char* file_name = JS_ToCString(context, argv[0]);
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -224,8 +210,16 @@ static void _file_read_open_callback(uv_fs_t* req)
|
|||||||
|
|
||||||
static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
void* task = JS_GetContextOpaque(context);
|
tf_task_t* task = JS_GetContextOpaque(context);
|
||||||
const char* file_name = JS_ToCString(context, argv[0]);
|
const char* file_name = JS_ToCString(context, argv[0]);
|
||||||
|
const char* actual = file_name;
|
||||||
|
if (tf_task_get_root_path(task))
|
||||||
|
{
|
||||||
|
size_t size = strlen(tf_task_get_root_path(task)) + strlen(file_name) + 2;
|
||||||
|
char* buffer = alloca(size);
|
||||||
|
snprintf(buffer, size, "%s/%s", tf_task_get_root_path(task), file_name);
|
||||||
|
actual = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
promiseid_t promise = -1;
|
promiseid_t promise = -1;
|
||||||
JSValue promise_value = tf_task_allocate_promise(task, &promise);
|
JSValue promise_value = tf_task_allocate_promise(task, &promise);
|
||||||
@ -239,7 +233,7 @@ static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int ar
|
|||||||
.size = k_file_read_max,
|
.size = k_file_read_max,
|
||||||
};
|
};
|
||||||
memset(req + 1, 0, k_file_read_max);
|
memset(req + 1, 0, k_file_read_max);
|
||||||
int result = uv_fs_open(tf_task_get_loop(task), &req->fs, file_name, UV_FS_O_RDONLY, 0, _file_read_open_callback);
|
int result = uv_fs_open(tf_task_get_loop(task), &req->fs, actual, UV_FS_O_RDONLY, 0, _file_read_open_callback);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", file_name, uv_strerror(result)));
|
tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, "Failed to open %s for read: %s", file_name, uv_strerror(result)));
|
||||||
@ -365,81 +359,6 @@ static JSValue _file_read_file_zip(JSContext* context, JSValueConst this_val, in
|
|||||||
return promise_value;
|
return promise_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
|
||||||
{
|
|
||||||
void* task = JS_GetContextOpaque(context);
|
|
||||||
const char* path = JS_ToCString(context, argv[0]);
|
|
||||||
promiseid_t promise = -1;
|
|
||||||
JSValue promise_value = tf_task_allocate_promise(task, &promise);
|
|
||||||
|
|
||||||
file_stat_t* data = tf_malloc(sizeof(file_stat_t));
|
|
||||||
data->_task = task;
|
|
||||||
data->_promise = promise;
|
|
||||||
data->_request.data = data;
|
|
||||||
data->_context = context;
|
|
||||||
|
|
||||||
int result = uv_fs_stat(tf_task_get_loop(task), &data->_request, path, _file_on_stat_complete);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
tf_task_reject_promise(task, promise, JS_NewInt32(context, result));
|
|
||||||
uv_fs_req_cleanup(&data->_request);
|
|
||||||
tf_free(data);
|
|
||||||
}
|
|
||||||
JS_FreeCString(context, path);
|
|
||||||
return promise_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue _file_stat_zip(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
|
||||||
{
|
|
||||||
void* task = JS_GetContextOpaque(context);
|
|
||||||
promiseid_t promise = -1;
|
|
||||||
JSValue promise_value = tf_task_allocate_promise(task, &promise);
|
|
||||||
|
|
||||||
file_stat_t* data = tf_malloc(sizeof(file_stat_t));
|
|
||||||
data->_task = task;
|
|
||||||
data->_promise = promise;
|
|
||||||
data->_request.data = data;
|
|
||||||
data->_context = context;
|
|
||||||
|
|
||||||
/* Ignore the requested path and stat the zip itself. */
|
|
||||||
int result = uv_fs_stat(tf_task_get_loop(task), &data->_request, tf_task_get_zip_path(task), _file_on_stat_complete);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
tf_task_reject_promise(task, promise, JS_NewInt32(context, result));
|
|
||||||
uv_fs_req_cleanup(&data->_request);
|
|
||||||
tf_free(data);
|
|
||||||
}
|
|
||||||
return promise_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double _time_spec_to_double(const uv_timespec_t* time_spec)
|
|
||||||
{
|
|
||||||
return time_spec->tv_sec + (double)(time_spec->tv_nsec) / 1e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _file_on_stat_complete(uv_fs_t* request)
|
|
||||||
{
|
|
||||||
file_stat_t* data = (file_stat_t*)(request->data);
|
|
||||||
JSContext* context = data->_context;
|
|
||||||
|
|
||||||
if (request->result)
|
|
||||||
{
|
|
||||||
tf_task_reject_promise(data->_task, data->_promise, JS_NewInt32(context, request->result));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JSValue result = JS_NewObject(context);
|
|
||||||
JS_SetPropertyStr(context, result, "mtime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_mtim)));
|
|
||||||
JS_SetPropertyStr(context, result, "ctime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_ctim)));
|
|
||||||
JS_SetPropertyStr(context, result, "atime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_atim)));
|
|
||||||
JS_SetPropertyStr(context, result, "size", JS_NewFloat64(context, request->statbuf.st_size));
|
|
||||||
tf_task_resolve_promise(data->_task, data->_promise, result);
|
|
||||||
JS_FreeValue(context, result);
|
|
||||||
}
|
|
||||||
uv_fs_req_cleanup(request);
|
|
||||||
tf_free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _stat_t
|
typedef struct _stat_t
|
||||||
{
|
{
|
||||||
uv_fs_t request;
|
uv_fs_t request;
|
||||||
|
@ -783,13 +783,24 @@ typedef struct _http_file_t
|
|||||||
char etag[512];
|
char etag[512];
|
||||||
} http_file_t;
|
} http_file_t;
|
||||||
|
|
||||||
|
static bool _ends_with(const char* a, const char* suffix)
|
||||||
|
{
|
||||||
|
if (!a || !suffix)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t alen = strlen(a);
|
||||||
|
size_t suffixlen = strlen(suffix);
|
||||||
|
return alen >= suffixlen && strcmp(a + alen - suffixlen, suffix) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void _httpd_endpoint_static_read(tf_task_t* task, const char* path, int result, const void* data, void* user_data)
|
static void _httpd_endpoint_static_read(tf_task_t* task, const char* path, int result, const void* data, void* user_data)
|
||||||
{
|
{
|
||||||
http_file_t* file = user_data;
|
http_file_t* file = user_data;
|
||||||
tf_http_request_t* request = file->request;
|
tf_http_request_t* request = file->request;
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
if (strcmp(path, "core/tfrpc.js") == 0)
|
if (strcmp(path, "core/tfrpc.js") == 0 || _ends_with(path, "core/tfrpc.js"))
|
||||||
{
|
{
|
||||||
const char* content_type = _ext_to_content_type(strrchr(path, '.'), true);
|
const char* content_type = _ext_to_content_type(strrchr(path, '.'), true);
|
||||||
const char* headers[] = {
|
const char* headers[] = {
|
||||||
@ -931,9 +942,10 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tf_task_t* task = request->user_data;
|
tf_task_t* task = request->user_data;
|
||||||
size_t size = strlen(file_path) + strlen(after) + 1;
|
const char* root_path = tf_task_get_root_path(task);
|
||||||
|
size_t size = (root_path ? strlen(root_path) + 1 : 0) + strlen(file_path) + strlen(after) + 1;
|
||||||
char* path = alloca(size);
|
char* path = alloca(size);
|
||||||
snprintf(path, size, "%s%s", file_path, after);
|
snprintf(path, size, "%s%s%s%s", root_path ? root_path : "", root_path ? "/" : "", file_path, after);
|
||||||
tf_http_request_ref(request);
|
tf_http_request_ref(request);
|
||||||
tf_file_stat(task, path, _httpd_endpoint_static_stat, request);
|
tf_file_stat(task, path, _httpd_endpoint_static_stat, request);
|
||||||
}
|
}
|
||||||
|
73
src/main.c
73
src/main.c
@ -808,8 +808,8 @@ static int _tf_command_create_invite(const char* file, int argc, char* argv[])
|
|||||||
const char* default_db_path = _get_db_path();
|
const char* default_db_path = _get_db_path();
|
||||||
const char* db_path = default_db_path;
|
const char* db_path = default_db_path;
|
||||||
const char* identity = NULL;
|
const char* identity = NULL;
|
||||||
int use_count = 0;
|
int use_count = 1;
|
||||||
int expires = 0;
|
int expires = 3600;
|
||||||
bool show_usage = false;
|
bool show_usage = false;
|
||||||
const char* host = NULL;
|
const char* host = NULL;
|
||||||
int port = 0;
|
int port = 0;
|
||||||
@ -868,8 +868,8 @@ static int _tf_command_create_invite(const char* file, int argc, char* argv[])
|
|||||||
tf_printf(" -i, --identity identity Account from which to get latest sequence number.\n");
|
tf_printf(" -i, --identity identity Account from which to get latest sequence number.\n");
|
||||||
tf_printf(" -a, --address address Address to which the recipient will connect.\n");
|
tf_printf(" -a, --address address Address to which the recipient will connect.\n");
|
||||||
tf_printf(" -p, --port port Port to which the recipient will connect.\n");
|
tf_printf(" -p, --port port Port to which the recipient will connect.\n");
|
||||||
tf_printf(" -u, --use_count count Number of times this invite may be used.\n");
|
tf_printf(" -u, --use_count count Number of times this invite may be used (default: 1).\n");
|
||||||
tf_printf(" -e, --expires seconds How long this invite is valid in seconds (-1 for indefinitely).\n");
|
tf_printf(" -e, --expires seconds How long this invite is valid in seconds (-1 for indefinitely, default: 1 hour).\n");
|
||||||
tf_printf(" -h, --help Show this usage information.\n");
|
tf_printf(" -h, --help Show this usage information.\n");
|
||||||
tf_free((void*)default_db_path);
|
tf_free((void*)default_db_path);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -1256,6 +1256,47 @@ static int _tf_run_task(const tf_run_args_t* args, int index)
|
|||||||
snprintf(db_path_buffer, sizeof(db_path_buffer), "%s.%d", args->db_path, index);
|
snprintf(db_path_buffer, sizeof(db_path_buffer), "%s.%d", args->db_path, index);
|
||||||
db_path = db_path_buffer;
|
db_path = db_path_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* cwd = NULL;
|
||||||
|
if (!args->zip)
|
||||||
|
{
|
||||||
|
size_t cwd_size = 1;
|
||||||
|
uv_cwd((char[1]) { 0 }, &cwd_size);
|
||||||
|
cwd = alloca(cwd_size);
|
||||||
|
if (uv_cwd(cwd, &cwd_size) == 0)
|
||||||
|
{
|
||||||
|
size_t test_path_size = cwd_size + strlen("/core/core.js");
|
||||||
|
char* test_path = alloca(test_path_size);
|
||||||
|
|
||||||
|
uv_loop_t* loop = tf_task_get_loop(task);
|
||||||
|
uv_fs_t req = { 0 };
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
snprintf(test_path, test_path_size, "%s/core/core.js", cwd);
|
||||||
|
int r = uv_fs_access(loop, &req, test_path, 0000, NULL);
|
||||||
|
uv_fs_req_cleanup(&req);
|
||||||
|
if (r != UV_ENOENT)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char* slash = strrchr(cwd, '/');
|
||||||
|
if (slash)
|
||||||
|
{
|
||||||
|
*slash = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tf_printf("Using %s as the working directory.\n", cwd);
|
||||||
|
}
|
||||||
|
if (!*cwd)
|
||||||
|
{
|
||||||
|
cwd = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tf_task_set_db_path(task, db_path);
|
tf_task_set_db_path(task, db_path);
|
||||||
tf_task_activate(task);
|
tf_task_activate(task);
|
||||||
tf_ssb_set_verbose(tf_task_get_ssb(task), args->verbose);
|
tf_ssb_set_verbose(tf_task_get_ssb(task), args->verbose);
|
||||||
@ -1266,13 +1307,33 @@ static int _tf_run_task(const tf_run_args_t* args, int index)
|
|||||||
{
|
{
|
||||||
tf_ssb_import_from_zip(tf_task_get_ssb(task), args->zip, "core", "apps");
|
tf_ssb_import_from_zip(tf_task_get_ssb(task), args->zip, "core", "apps");
|
||||||
}
|
}
|
||||||
|
else if (cwd)
|
||||||
|
{
|
||||||
|
size_t apps_path_size = strlen(cwd) + strlen("/apps") + 1;
|
||||||
|
char* apps_path = alloca(apps_path_size);
|
||||||
|
snprintf(apps_path, apps_path_size, "%s/apps", cwd);
|
||||||
|
tf_ssb_import(tf_task_get_ssb(task), "core", apps_path);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_ssb_import(tf_task_get_ssb(task), "core", "apps");
|
tf_ssb_import(tf_task_get_ssb(task), "core", "apps");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tf_ssb_set_main_thread(tf_task_get_ssb(task), true);
|
tf_ssb_set_main_thread(tf_task_get_ssb(task), true);
|
||||||
if (tf_task_execute(task, args->script))
|
const char* script = args->script;
|
||||||
|
if (!script && cwd)
|
||||||
|
{
|
||||||
|
size_t script_size = strlen(cwd) + strlen("/core/core.js") + 1;
|
||||||
|
char* script_buffer = alloca(script_size);
|
||||||
|
snprintf(script_buffer, script_size, "%s/core/core.js", cwd);
|
||||||
|
script = script_buffer;
|
||||||
|
}
|
||||||
|
else if (!script)
|
||||||
|
{
|
||||||
|
script = "core/core.js";
|
||||||
|
}
|
||||||
|
tf_task_set_root_path(task, cwd);
|
||||||
|
if (tf_task_execute(task, script))
|
||||||
{
|
{
|
||||||
tf_task_run(task);
|
tf_task_run(task);
|
||||||
result = 0;
|
result = 0;
|
||||||
@ -1356,7 +1417,6 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
const char* default_db_path = _get_db_path();
|
const char* default_db_path = _get_db_path();
|
||||||
tf_run_args_t args = {
|
tf_run_args_t args = {
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.script = "core/core.js",
|
|
||||||
.http_port = 12345,
|
.http_port = 12345,
|
||||||
.https_port = 12346,
|
.https_port = 12346,
|
||||||
.ssb_port = 8008,
|
.ssb_port = 8008,
|
||||||
@ -1787,7 +1847,6 @@ void tf_run_thread_start(const char* zip_path)
|
|||||||
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t));
|
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t));
|
||||||
tf_run_args_t args = {
|
tf_run_args_t args = {
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.script = "core/core.js",
|
|
||||||
.http_port = 12345,
|
.http_port = 12345,
|
||||||
.https_port = 12346,
|
.https_port = 12346,
|
||||||
.ssb_port = 8008,
|
.ssb_port = 8008,
|
||||||
|
14
src/ssb.c
14
src/ssb.c
@ -372,7 +372,7 @@ static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
|
|||||||
static void _tf_ssb_connection_on_close(uv_handle_t* handle);
|
static void _tf_ssb_connection_on_close(uv_handle_t* handle);
|
||||||
static void _tf_ssb_nonce_inc(uint8_t* nonce);
|
static void _tf_ssb_nonce_inc(uint8_t* nonce);
|
||||||
static void _tf_ssb_notify_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection);
|
static void _tf_ssb_notify_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection);
|
||||||
static bool _tf_ssb_parse_connect_string(const char* in_broadcast, tf_ssb_broadcast_t* out_broadcast);
|
static bool _tf_ssb_parse_connect_string(tf_ssb_t* ssb, const char* in_broadcast, tf_ssb_broadcast_t* out_broadcast);
|
||||||
static void _tf_ssb_start_update_settings(tf_ssb_t* ssb);
|
static void _tf_ssb_start_update_settings(tf_ssb_t* ssb);
|
||||||
static void _tf_ssb_update_settings(tf_ssb_t* ssb);
|
static void _tf_ssb_update_settings(tf_ssb_t* ssb);
|
||||||
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
|
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
|
||||||
@ -3322,7 +3322,7 @@ static void _tf_ssb_update_seeds_after_work(tf_ssb_t* ssb, int status, void* use
|
|||||||
for (int i = 0; i < seeds->seeds_count; i++)
|
for (int i = 0; i < seeds->seeds_count; i++)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_peer_exchange };
|
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_peer_exchange };
|
||||||
if (_tf_ssb_parse_connect_string(seeds->seeds[i], &broadcast))
|
if (_tf_ssb_parse_connect_string(ssb, seeds->seeds[i], &broadcast))
|
||||||
{
|
{
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, k_seed_expire_seconds);
|
_tf_ssb_add_broadcast(ssb, &broadcast, k_seed_expire_seconds);
|
||||||
}
|
}
|
||||||
@ -3431,7 +3431,7 @@ bool tf_ssb_whoami(tf_ssb_t* ssb, char* out_id, size_t out_id_size)
|
|||||||
return tf_ssb_id_bin_to_str(out_id, out_id_size, ssb->pub);
|
return tf_ssb_id_bin_to_str(out_id, out_id_size, ssb->pub);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _tf_ssb_parse_connect_string(const char* in_broadcast, tf_ssb_broadcast_t* out_broadcast)
|
static bool _tf_ssb_parse_connect_string(tf_ssb_t* ssb, const char* in_broadcast, tf_ssb_broadcast_t* out_broadcast)
|
||||||
{
|
{
|
||||||
char public_key_str[54] = { 0 };
|
char public_key_str[54] = { 0 };
|
||||||
char secret_key_str[45] = { 0 };
|
char secret_key_str[45] = { 0 };
|
||||||
@ -3450,7 +3450,7 @@ static bool _tf_ssb_parse_connect_string(const char* in_broadcast, tf_ssb_broadc
|
|||||||
return tf_ssb_id_str_to_bin(out_broadcast->pub, public_key_str) &&
|
return tf_ssb_id_str_to_bin(out_broadcast->pub, public_key_str) &&
|
||||||
tf_base64_decode(secret_key_str, strlen(secret_key_str), out_broadcast->invite, sizeof(out_broadcast->invite));
|
tf_base64_decode(secret_key_str, strlen(secret_key_str), out_broadcast->invite, sizeof(out_broadcast->invite));
|
||||||
}
|
}
|
||||||
else if (strncmp(in_broadcast, "ws:", 3) == 0)
|
else if (ssb->verbose && strncmp(in_broadcast, "ws:", 3) == 0)
|
||||||
{
|
{
|
||||||
tf_printf("Unsupported broadcast: %s\n", in_broadcast);
|
tf_printf("Unsupported broadcast: %s\n", in_broadcast);
|
||||||
}
|
}
|
||||||
@ -3460,7 +3460,7 @@ static bool _tf_ssb_parse_connect_string(const char* in_broadcast, tf_ssb_broadc
|
|||||||
void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address, int connect_flags, tf_ssb_connect_callback_t* callback, void* user_data)
|
void tf_ssb_connect_str(tf_ssb_t* ssb, const char* address, int connect_flags, tf_ssb_connect_callback_t* callback, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { 0 };
|
tf_ssb_broadcast_t broadcast = { 0 };
|
||||||
if (_tf_ssb_parse_connect_string(address, &broadcast))
|
if (_tf_ssb_parse_connect_string(ssb, address, &broadcast))
|
||||||
{
|
{
|
||||||
if (memcmp(broadcast.invite, (uint8_t[crypto_sign_ed25519_SEEDBYTES]) { 0 }, crypto_sign_ed25519_SEEDBYTES) == 0)
|
if (memcmp(broadcast.invite, (uint8_t[crypto_sign_ed25519_SEEDBYTES]) { 0 }, crypto_sign_ed25519_SEEDBYTES) == 0)
|
||||||
{
|
{
|
||||||
@ -3556,7 +3556,7 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcast_origin_t origin, int64_t expires_seconds)
|
void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcast_origin_t origin, int64_t expires_seconds)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = origin };
|
tf_ssb_broadcast_t broadcast = { .origin = origin };
|
||||||
if (_tf_ssb_parse_connect_string(connection, &broadcast))
|
if (_tf_ssb_parse_connect_string(ssb, connection, &broadcast))
|
||||||
{
|
{
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, expires_seconds);
|
_tf_ssb_add_broadcast(ssb, &broadcast, expires_seconds);
|
||||||
}
|
}
|
||||||
@ -3579,7 +3579,7 @@ static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread,
|
|||||||
while (entry)
|
while (entry)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_discovery };
|
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_discovery };
|
||||||
if (_tf_ssb_parse_connect_string(entry, &broadcast))
|
if (_tf_ssb_parse_connect_string(ssb, entry, &broadcast))
|
||||||
{
|
{
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, k_udp_discovery_expires_seconds);
|
_tf_ssb_add_broadcast(ssb, &broadcast, k_udp_discovery_expires_seconds);
|
||||||
}
|
}
|
||||||
|
13
src/ssb.db.c
13
src/ssb.db.c
@ -2182,7 +2182,7 @@ const char* tf_ssb_db_get_profile_name(sqlite3* db, const char* id)
|
|||||||
static void _tf_ssb_db_invite_cleanup(sqlite3* db)
|
static void _tf_ssb_db_invite_cleanup(sqlite3* db)
|
||||||
{
|
{
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "DELETE FROM invites WHERE use_count = 0 OR expires < ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "DELETE FROM invites WHERE use_count = 0 OR (expires > 0 AND expires < ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_int64(statement, 1, (int64_t)time(NULL)) == SQLITE_OK)
|
if (sqlite3_bind_int64(statement, 1, (int64_t)time(NULL)) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
@ -2190,7 +2190,13 @@ static void _tf_ssb_db_invite_cleanup(sqlite3* db)
|
|||||||
{
|
{
|
||||||
if (sqlite3_changes(db))
|
if (sqlite3_changes(db))
|
||||||
{
|
{
|
||||||
tf_printf("Cleaned up %d used/expired invites.\n", sqlite3_changes(db));
|
char buffer[2] = { 0 };
|
||||||
|
size_t buffer_size = sizeof(buffer);
|
||||||
|
bool verbose = uv_os_getenv("TF_SSB_VERBOSE", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
tf_printf("Cleaned up %d used/expired invites.\n", sqlite3_changes(db));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2231,7 +2237,8 @@ bool tf_ssb_db_generate_invite(sqlite3* db, const char* id, const char* host, in
|
|||||||
if (sqlite3_prepare(db, "INSERT INTO invites (invite_public_key, account, use_count, expires) VALUES (?, ?, ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT INTO invites (invite_public_key, account, use_count, expires) VALUES (?, ?, ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, public, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, public, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, id, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_int(statement, 3, use_count) == SQLITE_OK && sqlite3_bind_int64(statement, 4, (int64_t)time(NULL) + expires_seconds) == SQLITE_OK)
|
sqlite3_bind_int(statement, 3, use_count) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_int64(statement, 4, (expires_seconds > 0 ? (int64_t)time(NULL) : 0) + expires_seconds) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
inserted = sqlite3_step(statement) == SQLITE_DONE;
|
inserted = sqlite3_step(statement) == SQLITE_DONE;
|
||||||
}
|
}
|
||||||
|
22
src/task.c
22
src/task.c
@ -155,6 +155,7 @@ typedef struct _tf_task_t
|
|||||||
int _https_port;
|
int _https_port;
|
||||||
char _db_path[256];
|
char _db_path[256];
|
||||||
char _zip_path[256];
|
char _zip_path[256];
|
||||||
|
char _root_path[256];
|
||||||
unzFile _zip;
|
unzFile _zip;
|
||||||
const char* _args;
|
const char* _args;
|
||||||
|
|
||||||
@ -363,7 +364,16 @@ static const char* _task_loadFile(tf_task_t* task, const char* fileName, size_t*
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FILE* file = fopen(fileName, "rb");
|
const char* actual = fileName;
|
||||||
|
if (*task->_root_path)
|
||||||
|
{
|
||||||
|
size_t size = strlen(task->_root_path) + strlen(fileName) + 2;
|
||||||
|
char* buffer = alloca(size);
|
||||||
|
snprintf(buffer, size, "%s/%s", task->_root_path, fileName);
|
||||||
|
actual = fileName;
|
||||||
|
}
|
||||||
|
tf_printf("opening %s\n", actual);
|
||||||
|
FILE* file = fopen(actual, "rb");
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
@ -2015,11 +2025,21 @@ void tf_task_set_zip_path(tf_task_t* task, const char* zip_path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tf_task_set_root_path(tf_task_t* task, const char* path)
|
||||||
|
{
|
||||||
|
snprintf(task->_root_path, sizeof(task->_root_path), "%s", path ? path : "");
|
||||||
|
}
|
||||||
|
|
||||||
const char* tf_task_get_zip_path(tf_task_t* task)
|
const char* tf_task_get_zip_path(tf_task_t* task)
|
||||||
{
|
{
|
||||||
return task->_zip ? task->_zip_path : NULL;
|
return task->_zip ? task->_zip_path : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* tf_task_get_root_path(tf_task_t* task)
|
||||||
|
{
|
||||||
|
return *task->_root_path ? task->_root_path : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void tf_task_set_args(tf_task_t* task, const char* args)
|
void tf_task_set_args(tf_task_t* task, const char* args)
|
||||||
{
|
{
|
||||||
task->_args = args;
|
task->_args = args;
|
||||||
|
16
src/task.h
16
src/task.h
@ -112,12 +112,26 @@ void tf_task_set_db_path(tf_task_t* task, const char* path);
|
|||||||
void tf_task_set_zip_path(tf_task_t* task, const char* path);
|
void tf_task_set_zip_path(tf_task_t* task, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get the path to the zipp file being used for static data.
|
** Set the path to the root of the project directory for data.
|
||||||
|
** @param task The task.
|
||||||
|
** @param path The file path or NULL.
|
||||||
|
*/
|
||||||
|
void tf_task_set_root_path(tf_task_t* task, const char* path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get the path to the zip file being used for static data.
|
||||||
** @param task The task.
|
** @param task The task.
|
||||||
** @return The zip file path or NULL.
|
** @return The zip file path or NULL.
|
||||||
*/
|
*/
|
||||||
const char* tf_task_get_zip_path(tf_task_t* task);
|
const char* tf_task_get_zip_path(tf_task_t* task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get the path to use for reading loose files.
|
||||||
|
** @param task The task.
|
||||||
|
** @return The path or NULL.
|
||||||
|
*/
|
||||||
|
const char* tf_task_get_root_path(tf_task_t* task);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Set arbitrary named arguments that will be made available to the task.
|
** Set arbitrary named arguments that will be made available to the task.
|
||||||
** @param task The task.
|
** @param task The task.
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.27"
|
#define VERSION_NUMBER "0.0.28-wip"
|
||||||
#define VERSION_NAME "This program kills fascists."
|
#define VERSION_NAME "This program kills fascists."
|
||||||
|
Reference in New Issue
Block a user