diff --git a/src/httpd.js.c b/src/httpd.js.c index c6fa670e..69379318 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -5,6 +5,7 @@ #include "log.h" #include "mem.h" #include "ssb.db.h" +#include "ssb.ebt.h" #include "ssb.h" #include "task.h" #include "tls.h" @@ -569,6 +570,50 @@ static void _httpd_endpoint_trace(tf_http_request_t* request) tf_free(json); } +static void _httpd_endpoint_ebt(tf_http_request_t* request) +{ + if (_httpd_redirect(request)) + { + return; + } + + tf_task_t* task = request->user_data; + tf_ssb_t* ssb = tf_task_get_ssb(task); + JSContext* context = tf_ssb_get_context(ssb); + + JSValue object = JS_NewObject(context); + + tf_ssb_connection_t* connections[256]; + int connection_count = tf_ssb_get_connections(ssb, connections, tf_countof(connections)); + for (int i = 0; i < connection_count; i++) + { + char id[k_id_base64_len]; + tf_ssb_connection_get_id(connections[i], id, sizeof(id)); + + char key[256]; + JSValue clock = JS_NewObject(context); + snprintf(key, sizeof(key), "%d:%s", i, id); + + tf_ssb_ebt_t* ebt = tf_ssb_connection_get_ebt(connections[i]); + tf_ssb_ebt_debug_clock(ebt, context, clock); + JS_SetPropertyStr(context, object, key, clock); + } + + JSValue json_value = JS_JSONStringify(context, object, JS_NULL, JS_NewInt32(context, 2)); + const char* json = JS_ToCString(context, json_value); + JS_FreeValue(context, json_value); + + const char* headers[] = { + "Content-Type", + "application/json; charset=utf-8", + "Access-Control-Allow-Origin", + "*", + }; + tf_http_respond(request, 200, headers, tf_countof(headers) / 2, json, json ? strlen(json) : 0); + JS_FreeCString(context, json); + JS_FreeValue(context, object); +} + static void _httpd_endpoint_mem(tf_http_request_t* request) { if (_httpd_redirect(request)) @@ -2387,6 +2432,7 @@ void tf_httpd_register(JSContext* context) tf_http_add_handler(http, "/hitches", _httpd_endpoint_hitches, NULL, task); tf_http_add_handler(http, "/mem", _httpd_endpoint_mem, NULL, task); tf_http_add_handler(http, "/trace", _httpd_endpoint_trace, NULL, task); + tf_http_add_handler(http, "/ebt", _httpd_endpoint_ebt, NULL, task); tf_http_add_handler(http, "/login/logout", _httpd_endpoint_logout, NULL, task); tf_http_add_handler(http, "/login/auto", _httpd_endpoint_login_auto, NULL, task); diff --git a/src/ssb.ebt.c b/src/ssb.ebt.c index d9cf06bf..3dc8948d 100644 --- a/src/ssb.ebt.c +++ b/src/ssb.ebt.c @@ -7,6 +7,7 @@ #include "uv.h" +#include #include typedef struct _ebt_entry_t @@ -57,6 +58,12 @@ static int _ebt_entry_compare(const void* a, const void* b) static ebt_entry_t* _ebt_get_entry(tf_ssb_ebt_t* ebt, const char* id) { + uint8_t bin[k_id_bin_len]; + if (!tf_ssb_id_str_to_bin(bin, id)) + { + return NULL; + } + int index = tf_util_insert_index(id, ebt->entries, ebt->entries_count, sizeof(ebt_entry_t), _ebt_entry_compare); if (index < ebt->entries_count && strcmp(id, ebt->entries[index].id) == 0) { @@ -104,21 +111,24 @@ void tf_ssb_ebt_receive_clock(tf_ssb_ebt_t* ebt, JSContext* context, JSValue clo JS_ToInt64(context, &sequence, in_clock); ebt_entry_t* entry = _ebt_get_entry(ebt, author); - if (sequence < 0) + if (entry) { - entry->in = -1; - entry->in_replicate = false; - entry->in_receive = false; - } - else - { - entry->in = sequence >> 1; - entry->in_replicate = true; - entry->in_receive = (sequence & 1) == 0; - } - if (!entry->in_receive) - { - tf_ssb_connection_remove_new_message_request(ebt->connection, author); + if (sequence < 0) + { + entry->in = -1; + entry->in_replicate = false; + entry->in_receive = false; + } + else + { + entry->in = sequence >> 1; + entry->in_replicate = true; + entry->in_receive = (sequence & 1) == 0; + } + if (!entry->in_receive) + { + tf_ssb_connection_remove_new_message_request(ebt->connection, author); + } } JS_FreeCString(context, author); JS_FreeValue(context, key); @@ -154,7 +164,8 @@ static void _ebt_add_to_clock(ebt_get_clock_t* work, const char* id, int64_t val { int count = work->clock ? work->clock->count : 0; ebt_entry_t* entry = _ebt_get_entry(work->ebt, id); - if ((replicate && !entry->out_replicate) || (receive && !entry->out_receive) || ((replicate || receive || entry->out_replicate || entry->out_receive) && entry->out != value)) + if (entry && + ((replicate && !entry->out_replicate) || (receive && !entry->out_receive) || ((replicate || receive || entry->out_replicate || entry->out_receive) && entry->out != value))) { entry->out = value; entry->out_replicate = entry->out_replicate || replicate; @@ -303,10 +314,13 @@ void tf_ssb_ebt_set_messages_sent(tf_ssb_ebt_t* ebt, const char* id, int64_t seq { uv_mutex_lock(&ebt->mutex); ebt_entry_t* entry = _ebt_get_entry(ebt, id); - entry->in = tf_max(entry->in, sequence); - if (entry->in == entry->out && (tf_ssb_connection_get_flags(ebt->connection) & k_tf_ssb_connect_flag_one_shot) == 0) + if (entry) { - tf_ssb_connection_add_new_message_request(ebt->connection, id, tf_ssb_connection_get_ebt_request_number(ebt->connection), false); + entry->in = tf_max(entry->in, sequence); + if (entry->in == entry->out && (tf_ssb_connection_get_flags(ebt->connection) & k_tf_ssb_connect_flag_one_shot) == 0) + { + tf_ssb_connection_add_new_message_request(ebt->connection, id, tf_ssb_connection_get_ebt_request_number(ebt->connection), false); + } } uv_mutex_unlock(&ebt->mutex); } @@ -320,3 +334,25 @@ void tf_ssb_ebt_set_send_clock_pending(tf_ssb_ebt_t* ebt, int pending) { ebt->send_clock_pending = pending; } + +void tf_ssb_ebt_debug_clock(tf_ssb_ebt_t* ebt, JSContext* context, JSValue debug) +{ + uv_mutex_lock(&ebt->mutex); + for (int i = 0; i < ebt->entries_count; i++) + { + ebt_entry_t* entry = &ebt->entries[i]; + JSValue clock = JS_NewObject(context); + JSValue out = JS_NewObject(context); + JSValue in = JS_NewObject(context); + JS_SetPropertyStr(context, out, "value", JS_NewInt64(context, entry->out)); + JS_SetPropertyStr(context, out, "replicate", JS_NewBool(context, entry->out_replicate)); + JS_SetPropertyStr(context, out, "receive", JS_NewBool(context, entry->out_receive)); + JS_SetPropertyStr(context, clock, "out", out); + JS_SetPropertyStr(context, in, "value", JS_NewInt64(context, entry->in)); + JS_SetPropertyStr(context, in, "replicate", JS_NewBool(context, entry->in_replicate)); + JS_SetPropertyStr(context, in, "receive", JS_NewBool(context, entry->in_receive)); + JS_SetPropertyStr(context, clock, "in", in); + JS_SetPropertyStr(context, debug, entry->id, clock); + } + uv_mutex_unlock(&ebt->mutex); +} diff --git a/src/ssb.ebt.h b/src/ssb.ebt.h index 91e76dfd..16e0038e 100644 --- a/src/ssb.ebt.h +++ b/src/ssb.ebt.h @@ -97,3 +97,12 @@ int tf_ssb_ebt_get_send_clock_pending(tf_ssb_ebt_t* ebt); ** @param pending A value representing the pending status. */ void tf_ssb_ebt_set_send_clock_pending(tf_ssb_ebt_t* ebt, int pending); + +/** +** Get a JSON representation of the clock state for +** debugging. +** @param ebt The EBT instance. +** @param context The JS context. +** @param debug A JS object populated with the information. +*/ +void tf_ssb_ebt_debug_clock(tf_ssb_ebt_t* ebt, JSContext* context, JSValue debug);