diff --git a/src/ssb.js.c b/src/ssb.js.c index f5e7da9a..9ba320ab 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -255,7 +255,7 @@ static JSValue _tf_ssb_deleteIdentity(JSContext* context, JSValueConst this_val, return result; } -static JSValue _set_server_following_internal(tf_ssb_t* ssb, JSValueConst this_val, JSValue id, JSValue following) +static JSValue _set_server_following_internal(tf_ssb_t* ssb, JSValueConst this_val, const char* id, bool follow) { JSContext* context = tf_ssb_get_context(ssb); JSValue message = JS_NewObject(context); @@ -264,8 +264,8 @@ static JSValue _set_server_following_internal(tf_ssb_t* ssb, JSValueConst this_v tf_ssb_whoami(ssb, server_id_buffer, sizeof(server_id_buffer)); JSValue server_id = JS_NewString(context, server_id_buffer); JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact")); - JS_SetPropertyStr(context, message, "contact", JS_DupValue(context, id)); - JS_SetPropertyStr(context, message, "following", JS_DupValue(context, following)); + JS_SetPropertyStr(context, message, "contact", JS_NewString(context, id)); + JS_SetPropertyStr(context, message, "following", JS_NewBool(context, follow)); JSValue args[] = { server_user, server_id, @@ -278,43 +278,85 @@ static JSValue _set_server_following_internal(tf_ssb_t* ssb, JSValueConst this_v return result; } +typedef struct _set_server_following_me_t +{ + const char* user; + const char* key; + bool follow; + JSValue this_val; + JSValue promise[2]; + bool error_does_not_own_key; + bool append_message; +} set_server_following_me_t; + +static void _tf_ssb_set_server_following_me_work(tf_ssb_t* ssb, void* user_data) +{ + set_server_following_me_t* work = user_data; + if (!tf_ssb_db_identity_get_private_key(ssb, work->user, work->key, NULL, 0)) + { + work->error_does_not_own_key = true; + } + else + { + char server_id[k_id_base64_len] = { 0 }; + tf_ssb_whoami(ssb, server_id, sizeof(server_id)); + const char* server_id_ptr = server_id; + const char** current_following = tf_ssb_db_following_deep_ids(ssb, &server_id_ptr, 1, 1); + bool is_following = false; + for (const char** it = current_following; *it; it++) + { + if (strcmp(work->key, *it) == 0) + { + is_following = true; + break; + } + } + tf_free(current_following); + work->append_message = (work->follow && !is_following) || (!work->follow && is_following); + } +} + +static void _tf_ssb_set_server_following_me_after_work(tf_ssb_t* ssb, int status, void* user_data) +{ + set_server_following_me_t* work = user_data; + JSContext* context = tf_ssb_get_context(ssb); + JSValue result = JS_UNDEFINED; + if (work->error_does_not_own_key) + { + result = JS_ThrowInternalError(context, "User %s does not own key %s.", work->user, work->key); + } + else if (work->append_message) + { + result = _set_server_following_internal(ssb, work->this_val, work->key, work->follow); + } + JS_FreeCString(context, work->key); + JS_FreeCString(context, work->user); + 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]); + JS_FreeValue(context, work->this_val); + tf_free(work); +} + static JSValue _tf_ssb_set_server_following_me(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); JSValue result = JS_UNDEFINED; if (ssb) { - char server_id[k_id_base64_len]; - tf_ssb_whoami(ssb, server_id, sizeof(server_id)); - const char* user = JS_ToCString(context, argv[0]); - const char* key = JS_ToCString(context, argv[1]); - if (!tf_ssb_db_identity_get_private_key(ssb, user, key, NULL, 0)) + set_server_following_me_t* work = tf_malloc(sizeof(set_server_following_me_t)); + *work = (set_server_following_me_t) { - result = JS_ThrowInternalError(context, "User %s does not own key %s.", user, key); - } - else - { - const char* server_id_ptr = server_id; - const char** current_following = tf_ssb_db_following_deep_ids(ssb, &server_id_ptr, 1, 1); - bool is_following = false; - for (const char** it = current_following; *it; it++) - { - if (strcmp(key, *it) == 0) - { - is_following = true; - break; - } - } - tf_free(current_following); - - bool want_following = JS_ToBool(context, argv[2]); - if ((want_following && !is_following) || (!want_following && is_following)) - { - result = _set_server_following_internal(ssb, this_val, argv[1], argv[2]); - } - } - JS_FreeCString(context, key); - JS_FreeCString(context, user); + .user = JS_ToCString(context, argv[0]), + .key = JS_ToCString(context, argv[1]), + .follow = JS_ToBool(context, argv[2]), + .this_val = JS_DupValue(context, this_val), + }; + result = JS_NewPromiseCapability(context, work->promise); + tf_ssb_run_work(ssb, _tf_ssb_set_server_following_me_work, _tf_ssb_set_server_following_me_after_work, work); } return result; }