diff --git a/core/core.js b/core/core.js index 10536451..c7dc2f9c 100644 --- a/core/core.js +++ b/core/core.js @@ -361,10 +361,6 @@ async function getProcessBlob(blobId, key, options) { } return settings; }; - imports.core.globalSettingsGet = async function (key) { - let settings = await loadSettings(); - return settings?.[key]; - }; imports.core.globalSettingsSet = async function (key, value) { await imports.core.permissionTest('set_global_setting'); print('Setting', key, value); diff --git a/src/api.js.c b/src/api.js.c index f434116a..94cf90db 100644 --- a/src/api.js.c +++ b/src/api.js.c @@ -555,6 +555,92 @@ static JSValue _tf_ssb_getOwnerIdentities(JSContext* context, JSValueConst this_ return result; } +typedef struct _settings_get_t +{ + const char* key; + tf_setting_kind_t kind; + void* value; + JSContext* context; + JSValue promise[2]; +} settings_get_t; + +static void _tf_ssb_settings_get_work(tf_ssb_t* ssb, void* user_data) +{ + settings_get_t* work = user_data; + work->kind = tf_util_get_global_setting_kind(work->key); + switch (work->kind) + { + case k_kind_unknown: + break; + case k_kind_bool: + { + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + bool value = false; + tf_ssb_db_get_global_setting_bool(db, work->key, &value); + work->value = (void*)(intptr_t)value; + tf_ssb_release_db_reader(ssb, db); + } + break; + case k_kind_int: + { + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + int64_t value = 0; + tf_ssb_db_get_global_setting_int64(db, work->key, &value); + work->value = (void*)(intptr_t)value; + tf_ssb_release_db_reader(ssb, db); + } + break; + case k_kind_string: + { + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + work->value = (void*)tf_ssb_db_get_global_setting_string_alloc(db, work->key); + tf_ssb_release_db_reader(ssb, db); + } + break; + } +} + +static void _tf_ssb_settings_get_after_work(tf_ssb_t* ssb, int status, void* user_data) +{ + settings_get_t* work = user_data; + JSContext* context = tf_ssb_get_context(ssb); + JSValue result = JS_UNDEFINED; + switch (work->kind) + { + case k_kind_unknown: + break; + case k_kind_bool: + result = work->value ? JS_TRUE : JS_FALSE; + break; + case k_kind_int: + result = JS_NewInt64(context, (int64_t)(intptr_t)work->value); + break; + case k_kind_string: + result = JS_NewString(context, (const char*)work->value); + tf_free(work->value); + break; + } + + JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result); + tf_util_report_error(context, error); + JS_FreeValue(context, error); + JS_FreeValue(context, result); + JS_FreeValue(context, work->promise[0]); + JS_FreeValue(context, work->promise[1]); + tf_free(work); +} + +static JSValue _tf_ssb_globalSettingsGet(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) +{ + tf_task_t* task = tf_task_get(context); + tf_ssb_t* ssb = tf_task_get_ssb(task); + settings_get_t* work = tf_malloc(sizeof(settings_get_t)); + *work = (settings_get_t) { .context = context, .key = JS_ToCString(context, argv[0]) }; + JSValue result = JS_NewPromiseCapability(context, work->promise); + tf_ssb_run_work(ssb, _tf_ssb_settings_get_work, _tf_ssb_settings_get_after_work, work); + return result; +} + static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue imports = argv[0]; @@ -582,6 +668,17 @@ static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_va JS_SetPropertyStr(context, ssb, "getOwnerIdentities", JS_NewCFunctionData(context, _tf_ssb_getOwnerIdentities, 0, 0, 1, &process)); JS_FreeValue(context, ssb); + JSValue credentials = JS_GetPropertyStr(context, process, "credentials"); + JSValue permissions = JS_IsObject(credentials) ? JS_GetPropertyStr(context, credentials, "permissions") : JS_UNDEFINED; + JSValue administration = JS_IsObject(permissions) ? JS_GetPropertyStr(context, permissions, "administration") : JS_UNDEFINED; + if (JS_ToBool(context, administration) > 0) + { + JS_SetPropertyStr(context, core, "globalSettingsGet", JS_NewCFunction(context, _tf_ssb_globalSettingsGet, "globalSettingsGet", 1)); + } + JS_FreeValue(context, administration); + JS_FreeValue(context, permissions); + JS_FreeValue(context, credentials); + JS_FreeValue(context, core); return JS_UNDEFINED; } diff --git a/src/ssb.db.c b/src/ssb.db.c index 9cee06f0..0cf4bc08 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -2465,6 +2465,32 @@ bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* ou return result; } +const char* tf_ssb_db_get_global_setting_string_alloc(sqlite3* db, const char* name) +{ + const char* result = NULL; + sqlite3_stmt* statement; + if (sqlite3_prepare_v2(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK) + { + if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK) + { + if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL) + { + result = tf_strdup((const char*)sqlite3_column_text(statement, 0)); + } + } + sqlite3_finalize(statement); + } + else + { + tf_printf("prepare failed: %s\n", sqlite3_errmsg(db)); + } + if (!result) + { + result = tf_strdup(tf_util_get_default_global_setting_string(name)); + } + return result; +} + bool tf_ssb_db_set_global_setting_from_string(sqlite3* db, const char* name, char* value) { tf_setting_kind_t kind = tf_util_get_global_setting_kind(name); diff --git a/src/ssb.db.h b/src/ssb.db.h index 477a3d6a..e6aacae7 100644 --- a/src/ssb.db.h +++ b/src/ssb.db.h @@ -500,6 +500,14 @@ bool tf_ssb_db_get_global_setting_int64(sqlite3* db, const char* name, int64_t* */ bool tf_ssb_db_get_global_setting_string(sqlite3* db, const char* name, char* out_value, size_t size); +/** +** Get a string global setting value. +** @param db The database. +** @param name The setting name. +** @return The setting if found. +*/ +const char* tf_ssb_db_get_global_setting_string_alloc(sqlite3* db, const char* name); + /** ** Set a global setting from a string representation of its value. ** @param db The database.