forked from cory/tildefriends
Work in progress moving SSB RPC handlers into javascript.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3657 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
172
src/ssb.c
172
src/ssb.c
@ -54,7 +54,7 @@ typedef enum {
|
||||
} tf_ssb_state_t;
|
||||
|
||||
enum {
|
||||
k_connections_changed_callbacks_max = 4,
|
||||
k_connections_changed_callbacks_max = 8,
|
||||
k_tf_ssb_rpc_message_body_length_max = 8192,
|
||||
};
|
||||
|
||||
@ -82,10 +82,19 @@ typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t;
|
||||
typedef struct _tf_ssb_rpc_callback_node_t {
|
||||
const char** name;
|
||||
tf_ssb_rpc_callback_t* callback;
|
||||
tf_ssb_rpc_cleanup_t* cleanup;
|
||||
void* user_data;
|
||||
tf_ssb_rpc_callback_node_t* next;
|
||||
} tf_ssb_rpc_callback_node_t;
|
||||
|
||||
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t;
|
||||
typedef struct _tf_ssb_blob_want_added_callback_node_t {
|
||||
void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data);
|
||||
void (*cleanup)(tf_ssb_t* ssb, void* user_data);
|
||||
void* user_data;
|
||||
tf_ssb_blob_want_added_callback_node_t* next;
|
||||
} tf_ssb_blob_want_added_callback_node_t;
|
||||
|
||||
typedef struct _tf_ssb_t {
|
||||
bool own_context;
|
||||
JSRuntime* runtime;
|
||||
@ -109,6 +118,7 @@ typedef struct _tf_ssb_t {
|
||||
uint8_t priv[crypto_sign_SECRETKEYBYTES];
|
||||
|
||||
tf_ssb_connections_changed_callback_t* connections_changed[k_connections_changed_callbacks_max];
|
||||
tf_ssb_rpc_cleanup_t* connections_changed_cleanup[k_connections_changed_callbacks_max];
|
||||
void* connections_changed_user_data[k_connections_changed_callbacks_max];
|
||||
int connections_changed_count;
|
||||
|
||||
@ -122,6 +132,8 @@ typedef struct _tf_ssb_t {
|
||||
tf_ssb_broadcast_t* broadcasts;
|
||||
|
||||
tf_ssb_rpc_callback_node_t* rpc;
|
||||
|
||||
tf_ssb_blob_want_added_callback_node_t* blob_want_added;
|
||||
} tf_ssb_t;
|
||||
|
||||
typedef struct _tf_ssb_connection_t {
|
||||
@ -129,6 +141,8 @@ typedef struct _tf_ssb_connection_t {
|
||||
uv_tcp_t tcp;
|
||||
uv_connect_t connect;
|
||||
|
||||
JSValue object;
|
||||
|
||||
char host[256];
|
||||
int port;
|
||||
|
||||
@ -164,11 +178,14 @@ typedef struct _tf_ssb_connection_t {
|
||||
tf_ssb_request_t* requests;
|
||||
} tf_ssb_connection_t;
|
||||
|
||||
static JSClassID _connection_class_id;
|
||||
|
||||
static void _tf_ssb_connection_client_send_hello(uv_stream_t* stream);
|
||||
static void _tf_ssb_connection_on_close(uv_handle_t* handle);
|
||||
static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char* reason);
|
||||
static void _tf_ssb_nonce_inc(uint8_t* nonce);
|
||||
static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t size);
|
||||
static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value);
|
||||
|
||||
static void _tf_ssb_connection_send_close(tf_ssb_connection_t* connection)
|
||||
{
|
||||
@ -362,6 +379,9 @@ void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t r
|
||||
for (tf_ssb_request_t** it = &connection->requests; *it; it = &(*it)->next) {
|
||||
if ((*it)->request_number == request_number) {
|
||||
tf_ssb_request_t* found = *it;
|
||||
if (found->user_data) {
|
||||
JS_FreeValue(tf_ssb_connection_get_context(connection), JS_MKPTR(JS_TAG_OBJECT, found->user_data));
|
||||
}
|
||||
*it = found->next;
|
||||
free(found);
|
||||
break;
|
||||
@ -821,7 +841,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
bool found = false;
|
||||
for (tf_ssb_rpc_callback_node_t* it = connection->ssb->rpc; it; it = it->next) {
|
||||
if (_tf_ssb_name_equals(context, val, it->name)) {
|
||||
it->callback(connection, flags, request_number, val, message, size, it->user_data);
|
||||
it->callback(connection, flags, request_number, JS_DupValue(context, val), NULL, 0, it->user_data);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -831,7 +851,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
||||
void* user_data = NULL;
|
||||
if (_tf_ssb_connection_get_request_callback(connection, -request_number, &callback, &user_data)) {
|
||||
if (callback) {
|
||||
callback(connection, flags, request_number, val, NULL, 0, user_data);
|
||||
callback(connection, flags, request_number, JS_DupValue(context, val), NULL, 0, user_data);
|
||||
}
|
||||
} else {
|
||||
const char* k_unsupported = "{\"message\": \"unsupported message\", \"name\": \"Error\", \"stack\": \"none\", \"args\": []}";
|
||||
@ -1011,6 +1031,14 @@ void tf_ssb_append_message(tf_ssb_t* ssb, JSValue message)
|
||||
|
||||
void tf_ssb_connection_destroy(tf_ssb_connection_t* connection)
|
||||
{
|
||||
free(connection);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_on_close(uv_handle_t* handle)
|
||||
{
|
||||
tf_ssb_connection_t* connection = handle->data;
|
||||
handle->data = NULL;
|
||||
|
||||
tf_ssb_t* ssb = connection->ssb;
|
||||
for (tf_ssb_connection_t** it = &connection->ssb->connections; *it; it = &(*it)->next) {
|
||||
if (*it == connection) {
|
||||
@ -1025,15 +1053,7 @@ void tf_ssb_connection_destroy(tf_ssb_connection_t* connection)
|
||||
for (int i = 0; i < ssb->connections_changed_count; i++) {
|
||||
ssb->connections_changed[i](ssb, k_tf_ssb_change_remove, connection, ssb->connections_changed_user_data[i]);
|
||||
}
|
||||
free(connection);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_on_close(uv_handle_t* handle)
|
||||
{
|
||||
printf("destroy connection\n");
|
||||
tf_ssb_connection_t* connection = handle->data;
|
||||
handle->data = NULL;
|
||||
tf_ssb_connection_destroy(connection);
|
||||
JS_FreeValue(connection->ssb->context, connection->object);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_on_tcp_recv(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
@ -1286,6 +1306,14 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, sqlite3* db, const
|
||||
ssb->context = JS_NewContext(ssb->runtime);
|
||||
}
|
||||
|
||||
JS_NewClassID(&_connection_class_id);
|
||||
JSClassDef def =
|
||||
{
|
||||
.class_name = "connection",
|
||||
.finalizer = _tf_ssb_connection_finalizer,
|
||||
};
|
||||
JS_NewClass(JS_GetRuntime(ssb->context), _connection_class_id, &def);
|
||||
|
||||
if (db) {
|
||||
ssb->db = db;
|
||||
} else {
|
||||
@ -1373,6 +1401,12 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
tf_ssb_connections_destroy(ssb->connections_tracker);
|
||||
ssb->connections_tracker = NULL;
|
||||
|
||||
for (int i = 0; i < ssb->connections_changed_count; i++) {
|
||||
if (ssb->connections_changed_cleanup[i]) {
|
||||
ssb->connections_changed_cleanup[i](ssb, ssb->connections_changed_user_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
tf_ssb_rpc_destroy(ssb->rpc_state);
|
||||
ssb->rpc_state = NULL;
|
||||
|
||||
@ -1402,6 +1436,23 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
if (ssb->loop == &ssb->own_loop) {
|
||||
uv_loop_close(ssb->loop);
|
||||
}
|
||||
while (ssb->rpc) {
|
||||
tf_ssb_rpc_callback_node_t* node = ssb->rpc;
|
||||
ssb->rpc = node->next;
|
||||
if (node->cleanup) {
|
||||
node->cleanup(ssb, node->user_data);
|
||||
node->cleanup = NULL;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
while (ssb->blob_want_added) {
|
||||
tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added;
|
||||
ssb->blob_want_added = node->next;
|
||||
if (node->cleanup) {
|
||||
node->cleanup(ssb, node->user_data);
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
if (ssb->own_context) {
|
||||
JS_FreeContext(ssb->context);
|
||||
JS_FreeRuntime(ssb->runtime);
|
||||
@ -1414,11 +1465,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
||||
ssb->broadcasts = broadcast->next;
|
||||
free(broadcast);
|
||||
}
|
||||
while (ssb->rpc) {
|
||||
tf_ssb_rpc_callback_node_t* node = ssb->rpc;
|
||||
ssb->rpc = node->next;
|
||||
free(node);
|
||||
}
|
||||
free(ssb);
|
||||
}
|
||||
|
||||
@ -1427,8 +1473,50 @@ void tf_ssb_run(tf_ssb_t* ssb)
|
||||
uv_run(ssb->loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_finalizer(JSRuntime* runtime, JSValue value)
|
||||
{
|
||||
tf_ssb_connection_t* connection = JS_GetOpaque(value, _connection_class_id);
|
||||
tf_ssb_connection_destroy(connection);
|
||||
}
|
||||
|
||||
static void _tf_ssb_connection_send_json_response(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||
{
|
||||
if (!user_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_on_rpc(connection, flags, request_number, args, message, size, user_data);
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_connection_send_json(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
tf_ssb_connection_t* connection = JS_GetOpaque(this_val, _connection_class_id);
|
||||
if (!connection) {
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
uint32_t request_number = tf_ssb_connection_next_request_number(connection);
|
||||
|
||||
JSValue message_val = JS_JSONStringify(context, argv[0], JS_NULL, JS_NULL);
|
||||
size_t size;
|
||||
const char* message = JS_ToCStringLen(context, &size, message_val);
|
||||
JS_FreeValue(context, message_val);
|
||||
|
||||
tf_ssb_connection_rpc_send(
|
||||
connection,
|
||||
k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream,
|
||||
request_number,
|
||||
(const uint8_t*)message,
|
||||
size,
|
||||
_tf_ssb_connection_send_json_response,
|
||||
JS_IsFunction(context, argv[1]) ? JS_VALUE_GET_PTR(JS_DupValue(context, argv[1])) : NULL);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, const struct sockaddr_in* addr, const uint8_t* public_key)
|
||||
{
|
||||
JSContext* context = ssb->context;
|
||||
tf_ssb_connection_t* connection = malloc(sizeof(tf_ssb_connection_t));
|
||||
memset(connection, 0, sizeof(*connection));
|
||||
connection->ssb = ssb;
|
||||
@ -1438,6 +1526,15 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
||||
snprintf(connection->host, sizeof(connection->host), "%s", host);
|
||||
connection->port = ntohs(addr->sin_port);
|
||||
|
||||
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||
JS_SetPropertyStr(context, connection->object, "send_json", JS_NewCFunction(context, _tf_ssb_connection_send_json, "send_json", 2));
|
||||
char public_key_str[k_id_base64_len] = { 0 };
|
||||
if (tf_ssb_id_bin_to_str(public_key_str, sizeof(public_key_str), public_key))
|
||||
{
|
||||
JS_SetPropertyStr(context, connection->object, "id", JS_NewString(context, public_key_str));
|
||||
}
|
||||
JS_SetOpaque(connection->object, connection);
|
||||
|
||||
memcpy(connection->serverpub, public_key, sizeof(connection->serverpub));
|
||||
|
||||
uv_tcp_init(ssb->loop, &connection->tcp);
|
||||
@ -1514,6 +1611,10 @@ static void _tf_ssb_on_connection(uv_stream_t* stream, int status) {
|
||||
connection->tcp.data = connection;
|
||||
connection->send_request_number = 1;
|
||||
|
||||
connection->object = JS_NewObjectClass(ssb->context, _connection_class_id);
|
||||
JS_SetPropertyStr(ssb->context, connection->object, "send_json", JS_NewCFunction(ssb->context, _tf_ssb_connection_send_json, "send_json", 2));
|
||||
JS_SetOpaque(connection->object, connection);
|
||||
|
||||
if (uv_tcp_init(ssb->loop, &connection->tcp) != 0) {
|
||||
printf("uv_tcp_init failed\n");
|
||||
free(connection);
|
||||
@ -1811,15 +1912,16 @@ void tf_ssb_set_broadcasts_changed_callback(tf_ssb_t* ssb, void (*callback)(tf_s
|
||||
ssb->broadcasts_changed_user_data = user_data;
|
||||
}
|
||||
|
||||
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, void* user_data)
|
||||
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, tf_ssb_rpc_cleanup_t* cleanup, void* user_data)
|
||||
{
|
||||
assert(ssb->connections_changed_count < k_connections_changed_callbacks_max);
|
||||
ssb->connections_changed[ssb->connections_changed_count] = callback;
|
||||
ssb->connections_changed_cleanup[ssb->connections_changed_count] = cleanup;
|
||||
ssb->connections_changed_user_data[ssb->connections_changed_count] = user_data;
|
||||
ssb->connections_changed_count++;
|
||||
}
|
||||
|
||||
void tf_ssb_register_rpc(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, void* user_data)
|
||||
void tf_ssb_register_rpc(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_rpc_cleanup_t* cleanup, void* user_data)
|
||||
{
|
||||
size_t name_len = 0;
|
||||
int name_count = 0;
|
||||
@ -1831,6 +1933,7 @@ void tf_ssb_register_rpc(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t
|
||||
*node = (tf_ssb_rpc_callback_node_t) {
|
||||
.name = (const char**)(node + 1),
|
||||
.callback = callback,
|
||||
.cleanup = cleanup,
|
||||
.user_data = user_data,
|
||||
.next = ssb->rpc,
|
||||
};
|
||||
@ -1864,3 +1967,34 @@ int32_t tf_ssb_connection_next_request_number(tf_ssb_connection_t* connection)
|
||||
{
|
||||
return connection->send_request_number++;
|
||||
}
|
||||
|
||||
JSClassID tf_ssb_get_connection_class_id()
|
||||
{
|
||||
return _connection_class_id;
|
||||
}
|
||||
|
||||
JSValue tf_ssb_connection_get_object(tf_ssb_connection_t* connection)
|
||||
{
|
||||
return connection ? connection->object : JS_UNDEFINED;
|
||||
}
|
||||
|
||||
void tf_ssb_register_blob_want_added(tf_ssb_t* ssb, void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data), void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
||||
{
|
||||
tf_ssb_blob_want_added_callback_node_t* node = malloc(sizeof(tf_ssb_blob_want_added_callback_node_t));
|
||||
*node = (tf_ssb_blob_want_added_callback_node_t)
|
||||
{
|
||||
.callback = callback,
|
||||
.cleanup = cleanup,
|
||||
.user_data = user_data,
|
||||
.next = ssb->blob_want_added,
|
||||
};
|
||||
ssb->blob_want_added = node;
|
||||
}
|
||||
|
||||
void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id)
|
||||
{
|
||||
for (tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added; node; node = node->next)
|
||||
{
|
||||
node->callback(ssb, id, node->user_data);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user