ssb.js is now entirely in C. Usual disclaimers about it not being amazingly well tested.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4111 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2023-01-08 20:01:35 +00:00
parent 53e4f4341c
commit 69253432b8
9 changed files with 359 additions and 460 deletions

View File

@ -313,20 +313,7 @@ static JSValue _tf_ssb_sqlStream(JSContext* context, JSValueConst this_val, int
static JSValue _tf_ssb_storeMessage(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
char signature[crypto_sign_BYTES + 128];
char id[crypto_hash_sha256_BYTES * 2 + 1];
bool sequence_before_author = false;
if (tf_ssb_verify_and_strip_signature(context, argv[0], id, sizeof(id), signature, sizeof(signature), &sequence_before_author))
{
if (tf_ssb_db_store_message(ssb, context, id, argv[0], signature, sequence_before_author))
{
tf_ssb_notify_message_added(ssb, id);
}
}
else
{
printf("failed to verify message\n");
}
tf_ssb_verify_strip_and_store_message(ssb, argv[0]);
return JS_UNDEFINED;
}
@ -416,205 +403,12 @@ static JSValue _tf_ssb_connect(JSContext* context, JSValueConst this_val, int ar
return JS_UNDEFINED;
}
static JSValue _tf_ssb_rpc_send_json(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue connection_val = JS_GetPropertyStr(context, this_val, "connection");
tf_ssb_connection_t* connection = JS_GetOpaque(connection_val, tf_ssb_get_connection_class_id());
JSValue request_val = JS_GetPropertyStr(context, this_val, "request_number");
int32_t request_number;
JS_ToInt32(context, &request_number, request_val);
JS_FreeValue(context, request_val);
JSValue flags_val = JS_GetPropertyStr(context, this_val, "flags");
int32_t flags_number;
JS_ToInt32(context, &flags_number, flags_val);
JS_FreeValue(context, flags_val);
JSValue message_val = JS_JSONStringify(context, argv[0], JS_NULL, JS_NULL);
size_t size;
const char* message = JS_ToCStringLen(context, &size, message_val);
tf_ssb_connection_rpc_send(
connection,
k_ssb_rpc_flag_json | (flags_number & ~k_ssb_rpc_mask_type),
-request_number,
(const uint8_t*)message,
size,
NULL,
NULL,
NULL);
JS_FreeValue(context, connection_val);
JS_FreeCString(context, message);
JS_FreeValue(context, message_val);
return JS_NewInt32(context, -request_number);
}
static JSValue _tf_ssb_rpc_send_json_end(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue connection_val = JS_GetPropertyStr(context, this_val, "connection");
tf_ssb_connection_t* connection = JS_GetOpaque(connection_val, tf_ssb_get_connection_class_id());
JSValue request_val = JS_GetPropertyStr(context, this_val, "request_number");
int32_t request_number;
JS_ToInt32(context, &request_number, request_val);
JS_FreeValue(context, request_val);
JSValue flags_val = JS_GetPropertyStr(context, this_val, "flags");
int32_t flags_number;
JS_ToInt32(context, &flags_number, flags_val);
JS_FreeValue(context, flags_val);
JSValue message_val = JS_JSONStringify(context, argv[0], JS_NULL, JS_NULL);
size_t size;
const char* message = JS_ToCStringLen(context, &size, message_val);
tf_ssb_connection_rpc_send(
connection,
k_ssb_rpc_flag_json | (flags_number & ~k_ssb_rpc_mask_type) | k_ssb_rpc_flag_end_error,
-request_number,
(const uint8_t*)message,
size,
NULL,
NULL,
NULL);
JS_FreeValue(context, connection_val);
JS_FreeCString(context, message);
JS_FreeValue(context, message_val);
return JS_UNDEFINED;
}
static void _tf_ssb_cleanup_value(tf_ssb_t* ssb, void* user_data)
{
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
JS_FreeValue(tf_ssb_get_context(ssb), callback);
}
static JSValue _tf_ssb_rpc_more(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue connection_val = JS_GetPropertyStr(context, this_val, "connection");
tf_ssb_connection_t* connection = JS_GetOpaque(connection_val, tf_ssb_get_connection_class_id());
JSValue request_val = JS_GetPropertyStr(context, this_val, "request_number");
int32_t request_number;
JS_ToInt32(context, &request_number, request_val);
JS_FreeValue(context, request_val);
tf_ssb_connection_add_request(connection, -request_number, _tf_ssb_on_rpc, _tf_ssb_cleanup_value, JS_VALUE_GET_PTR(JS_DupValue(context, argv[0])), NULL);
JS_FreeValue(context, connection_val);
return JS_UNDEFINED;
}
static JSValue _tf_ssb_rpc_send_binary(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue connection_val = JS_GetPropertyStr(context, this_val, "connection");
tf_ssb_connection_t* connection = JS_GetOpaque(connection_val, tf_ssb_get_connection_class_id());
JSValue request_val = JS_GetPropertyStr(context, this_val, "request_number");
int32_t request_number;
JS_ToInt32(context, &request_number, request_val);
JS_FreeValue(context, request_val);
size_t size;
uint8_t* message = tf_util_try_get_array_buffer(context, &size, argv[0]);
if (message)
{
tf_ssb_connection_rpc_send(
connection,
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
-request_number,
(const uint8_t*)message,
size,
NULL,
NULL,
NULL);
}
else
{
size_t offset;
size_t element_size;
JSValue buffer = tf_util_try_get_typed_array_buffer(context, argv[0], &offset, &size, &element_size);
if (!JS_IsException(buffer))
{
size_t total_size;
message = tf_util_try_get_array_buffer(context, &total_size, buffer);
if (message)
{
tf_ssb_connection_rpc_send(
connection,
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
-request_number,
(const uint8_t*)message + offset,
size,
NULL,
NULL,
NULL);
}
}
JS_FreeValue(context, buffer);
}
JS_FreeValue(context, connection_val);
return JS_UNDEFINED;
}
void _tf_ssb_on_rpc(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
{
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
JSContext* context = tf_ssb_get_context(ssb);
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
JSValue object = JS_NewObject(context);
JSValue connection_object = JS_DupValue(context, tf_ssb_connection_get_object(connection));
JS_SetPropertyStr(context, object, "connection", connection_object);
JS_SetPropertyStr(context, object, "flags", JS_NewUint32(context, flags));
JS_SetPropertyStr(context, object, "request_number", JS_NewInt32(context, request_number));
JS_SetPropertyStr(context, object, "args", JS_GetPropertyStr(context, args, "args"));
JS_SetPropertyStr(context, object, "message", message && size ? JS_NewArrayBufferCopy(context, message, size) : JS_DupValue(context, args));
JS_SetPropertyStr(context, object, "send_json", JS_NewCFunction(context, _tf_ssb_rpc_send_json, "send_json", 1));
JS_SetPropertyStr(context, object, "send_binary", JS_NewCFunction(context, _tf_ssb_rpc_send_binary, "send_binary", 1));
JS_SetPropertyStr(context, object, "send_json_end", JS_NewCFunction(context, _tf_ssb_rpc_send_json_end, "send_json_end", 1));
JS_SetPropertyStr(context, object, "more", JS_NewCFunction(context, _tf_ssb_rpc_more, "more", 1));
JSValue result = JS_Call(context, callback, JS_UNDEFINED, 1, &object);
tf_util_report_error(context, result);
JS_FreeValue(context, result);
JS_FreeValue(context, object);
}
static JSValue _tf_ssb_add_rpc(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
if (!JS_IsArray(context, argv[0]))
{
return JS_ThrowTypeError(context, "Expected argument 1 to be an array of strings.");
}
if (!JS_IsFunction(context, argv[1]))
{
return JS_ThrowTypeError(context, "Expected argument 2 to be a function.");
}
enum { k_max_name_parts = 16 };
const char* name[k_max_name_parts + 1] = { 0 };
int length = tf_util_get_length(context, argv[0]);
if (length >= k_max_name_parts)
{
return JS_ThrowInternalError(context, "Too many parts to RPC name.");
}
for (int i = 0; i < length; i++)
{
JSValue value = JS_GetPropertyUint32(context, argv[0], i);
name[i] = JS_ToCString(context, value);
JS_FreeValue(context, value);
}
tf_ssb_add_rpc_callback(ssb, name, _tf_ssb_on_rpc, _tf_ssb_cleanup_value, JS_VALUE_GET_PTR(JS_DupValue(context, argv[1])));
for (int i = 0; i < length; i++)
{
JS_FreeCString(context, name[i]);
}
return JS_UNDEFINED;
}
static void _tf_ssb_on_message_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
{
JSContext* context = tf_ssb_get_context(ssb);
@ -1023,13 +817,8 @@ void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
JS_SetPropertyStr(context, object, "followingDeep", JS_NewCFunction(context, _tf_ssb_followingDeep, "followingDeep", 2));
/* Should be trusted only. */
JS_SetPropertyStr(context, object, "addRpc", JS_NewCFunction(context, _tf_ssb_add_rpc, "addRpc", 2));
JS_SetPropertyStr(context, object, "addEventListener", JS_NewCFunction(context, _tf_ssb_add_event_listener, "addEventListener", 2));
JS_SetPropertyStr(context, object, "removeEventListener", JS_NewCFunction(context, _tf_ssb_remove_event_listener, "removeEventListener", 2));
JS_FreeValue(context, global);
tf_util_register(context);
tf_database_register(context, tf_ssb_get_db(ssb));
tf_ssb_run_file(context, "core/ssb.js");
}