core: Move invoking the permission test to C, at least for adding/removing blocks.
All checks were successful
Build Tilde Friends / Build-Docs (push) Successful in 2m56s
Build Tilde Friends / Build-All (push) Successful in 10m15s

This commit is contained in:
2025-12-08 21:51:10 -05:00
parent c29ab66073
commit 3c6eeb9cd3
6 changed files with 239 additions and 139 deletions

View File

@@ -796,6 +796,231 @@ static JSValue _tf_ssb_globalSettingsGet(JSContext* context, JSValueConst this_v
return result;
}
typedef struct _modify_block_t
{
const char* user;
char id[k_id_base64_len];
bool add;
bool completed;
JSValue result;
JSValue promise[2];
} modify_block_t;
static void _tf_ssb_modify_block_work(tf_ssb_t* ssb, void* user_data)
{
modify_block_t* work = user_data;
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
if (work->add)
{
tf_ssb_db_add_block(db, work->id);
}
else
{
tf_ssb_db_remove_block(db, work->id);
}
tf_ssb_release_db_writer(ssb, db);
work->completed = true;
}
static void _tf_ssb_modify_block_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
modify_block_t* request = user_data;
JSContext* context = tf_ssb_get_context(ssb);
JSValue error = JS_Call(context, request->completed ? request->promise[0] : request->promise[1], JS_UNDEFINED, 1, &request->result);
tf_util_report_error(context, error);
JS_FreeValue(context, error);
JS_FreeValue(context, request->promise[0]);
JS_FreeValue(context, request->promise[1]);
JS_FreeValue(context, request->result);
tf_free((void*)request->user);
tf_free(request);
}
typedef void(permission_test_callback_t)(JSContext* context, bool granted, JSValue value, void* user_data);
typedef struct _permission_test_t
{
permission_test_callback_t* callback;
void* user_data;
} permission_test_t;
static JSValue _tf_ssb_permission_test_resolve(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
{
JSClassID class_id = 0;
permission_test_t* work = JS_GetAnyOpaque(data[0], &class_id);
JS_FreeValue(context, data[0]);
work->callback(context, true, argv[0], work->user_data);
tf_free(work);
return JS_UNDEFINED;
}
static JSValue _tf_ssb_permission_test_reject(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
{
JSClassID class_id = 0;
permission_test_t* work = JS_GetAnyOpaque(data[0], &class_id);
JS_FreeValue(context, data[0]);
work->callback(context, false, argv[0], work->user_data);
tf_free(work);
return JS_UNDEFINED;
}
static void _tf_ssb_permission_test(JSContext* context, JSValue process, const char* permission, const char* description, permission_test_callback_t* callback, void* user_data)
{
permission_test_t* payload = tf_malloc(sizeof(permission_test_t));
*payload = (permission_test_t) {
.callback = callback,
.user_data = user_data,
};
JSValue opaque = JS_NewObject(context);
JS_SetOpaque(opaque, payload);
JSValue imports = JS_GetPropertyStr(context, process, "imports");
JSValue core = JS_GetPropertyStr(context, imports, "core");
JSValue permission_test = JS_GetPropertyStr(context, core, "permissionTest");
JSValue args[] = {
JS_NewString(context, permission),
JS_NewString(context, description),
};
JSValue promise = JS_Call(context, permission_test, imports, tf_countof(args), args);
JSValue then = JS_GetPropertyStr(context, promise, "then");
JSValue catch = JS_GetPropertyStr(context, promise, "catch");
JSValue resolve = JS_NewCFunctionData(context, _tf_ssb_permission_test_resolve, 1, 0, 1, &opaque);
JSValue reject = JS_NewCFunctionData(context, _tf_ssb_permission_test_reject, 1, 0, 1, &opaque);
JSValue result = JS_Call(context, then, promise, 1, &resolve);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
result = JS_Call(context, catch, promise, 1, &reject);
tf_util_report_error(context, result);
JS_FreeValue(context, promise);
JS_FreeValue(context, resolve);
JS_FreeValue(context, reject);
JS_FreeValue(context, result);
JS_FreeValue(context, then);
JS_FreeValue(context, catch);
for (int i = 0; i < tf_countof(args); i++)
{
JS_FreeValue(context, args[i]);
}
JS_FreeValue(context, permission_test);
JS_FreeValue(context, core);
JS_FreeValue(context, imports);
}
static void _tf_ssb_modify_block_start_work(JSContext* context, bool granted, JSValue value, void* user_data)
{
tf_task_t* task = tf_task_get(context);
tf_ssb_t* ssb = tf_task_get_ssb(task);
modify_block_t* work = user_data;
work->result = JS_DupValue(context, value);
if (granted)
{
tf_ssb_run_work(ssb, _tf_ssb_modify_block_work, _tf_ssb_modify_block_after_work, work);
}
else
{
_tf_ssb_modify_block_after_work(ssb, 0, work);
}
}
static JSValue _tf_ssb_add_block(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
{
const char* id = JS_ToCString(context, argv[0]);
modify_block_t* work = tf_malloc(sizeof(modify_block_t));
*work = (modify_block_t) {
.user = _tf_ssb_get_process_credentials_session_name(context, data[0]),
.add = true,
};
tf_string_set(work->id, sizeof(work->id), id);
JSValue result = JS_NewPromiseCapability(context, work->promise);
JS_FreeCString(context, id);
char description[256] = "";
snprintf(description, sizeof(description), "Block %s.", work->id);
_tf_ssb_permission_test(context, data[0], "modify_blocks", description, _tf_ssb_modify_block_start_work, work);
return result;
}
static JSValue _tf_ssb_remove_block(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
{
const char* id = JS_ToCString(context, argv[0]);
modify_block_t* work = tf_malloc(sizeof(modify_block_t));
*work = (modify_block_t) {
.user = _tf_ssb_get_process_credentials_session_name(context, data[0]),
.add = false,
};
tf_string_set(work->id, sizeof(work->id), id);
JSValue result = JS_NewPromiseCapability(context, work->promise);
JS_FreeCString(context, id);
char description[256] = "";
snprintf(description, sizeof(description), "Unblock %s.", work->id);
_tf_ssb_permission_test(context, data[0], "modify_blocks", description, _tf_ssb_modify_block_start_work, work);
return result;
}
typedef struct _block_t
{
char id[k_id_base64_len];
double timestamp;
} block_t;
typedef struct _get_blocks_t
{
block_t* blocks;
int count;
JSValue promise[2];
} get_blocks_t;
static void _get_blocks_callback(const char* id, double timestamp, void* user_data)
{
get_blocks_t* work = user_data;
work->blocks = tf_resize_vec(work->blocks, sizeof(block_t) * (work->count + 1));
work->blocks[work->count] = (block_t) { .timestamp = timestamp };
tf_string_set(work->blocks[work->count].id, sizeof(work->blocks[work->count].id), id);
work->count++;
}
static void _tf_ssb_get_blocks_work(tf_ssb_t* ssb, void* user_data)
{
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
tf_ssb_db_get_blocks(db, _get_blocks_callback, user_data);
tf_ssb_release_db_reader(ssb, db);
}
static void _tf_ssb_get_blocks_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
get_blocks_t* work = user_data;
JSContext* context = tf_ssb_get_context(ssb);
JSValue result = JS_NewArray(context);
for (int i = 0; i < work->count; i++)
{
JSValue entry = JS_NewObject(context);
JS_SetPropertyStr(context, entry, "id", JS_NewString(context, work->blocks[i].id));
JS_SetPropertyStr(context, entry, "timestamp", JS_NewFloat64(context, work->blocks[i].timestamp));
JS_SetPropertyUint32(context, result, i, entry);
}
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
JS_FreeValue(context, result);
tf_util_report_error(context, error);
JS_FreeValue(context, error);
JS_FreeValue(context, work->promise[0]);
JS_FreeValue(context, work->promise[1]);
tf_free(work->blocks);
tf_free(work);
}
static JSValue _tf_ssb_get_blocks(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
{
tf_task_t* task = tf_task_get(context);
tf_ssb_t* ssb = tf_task_get_ssb(task);
get_blocks_t* work = tf_malloc(sizeof(get_blocks_t));
*work = (get_blocks_t) { 0 };
JSValue result = JS_NewPromiseCapability(context, work->promise);
tf_ssb_run_work(ssb, _tf_ssb_get_blocks_work, _tf_ssb_get_blocks_after_work, work);
return result;
}
static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue imports = argv[0];
@@ -831,6 +1056,10 @@ static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_va
{
JS_SetPropertyStr(context, core, "globalSettingsDescriptions", JS_NewCFunction(context, _tf_ssb_globalSettingsDescriptions, "globalSettingsDescriptions", 0));
JS_SetPropertyStr(context, core, "globalSettingsGet", JS_NewCFunction(context, _tf_ssb_globalSettingsGet, "globalSettingsGet", 1));
JS_SetPropertyStr(context, ssb, "addBlock", JS_NewCFunctionData(context, _tf_ssb_add_block, 1, 0, 1, &process));
JS_SetPropertyStr(context, ssb, "removeBlock", JS_NewCFunctionData(context, _tf_ssb_remove_block, 1, 0, 1, &process));
JS_SetPropertyStr(context, ssb, "getBlocks", JS_NewCFunctionData(context, _tf_ssb_get_blocks, 0, 0, 1, &process));
}
JS_FreeValue(context, administration);
JS_FreeValue(context, permissions);