diff --git a/core/ssb.js b/core/ssb.js index 34edc6f0..6147d30f 100644 --- a/core/ssb.js +++ b/core/ssb.js @@ -1,5 +1,67 @@ var g_wants_requests = {}; +async function following(db, id) { + var o = await db.get(id + ":following"); + const k_version = 5; + var f = o ? JSON.parse(o) : o; + if (!f || f.version != k_version) { + f = {users: [], sequence: 0, version: k_version}; + } + f.users = new Set(f.users); + await ssb.sqlStream( + "SELECT "+ + " sequence, "+ + " json_extract(content, '$.contact') AS contact, "+ + " json_extract(content, '$.following') AS following "+ + "FROM messages "+ + "WHERE "+ + " author = ?1 AND "+ + " sequence > ?2 AND "+ + " json_extract(content, '$.type') = 'contact' "+ + "UNION SELECT MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ?1 "+ + "ORDER BY sequence", + [id, f.sequence], + function(row) { + if (row.following) { + f.users.add(row.contact); + } else { + f.users.delete(row.contact); + } + f.sequence = row.sequence; + }); + f.users = Array.from(f.users); + var j = JSON.stringify(f); + if (o != j) { + await db.set(id + ":following", j); + } + return f.users; +} + +async function followingDeep(db, seed_ids, depth) { + if (depth <= 0) { + return seed_ids; + } + var f = await Promise.all(seed_ids.map(x => following(db, x))); + var ids = [].concat(...f); + var x = await followingDeep(db, [...new Set(ids)].sort(), depth - 1); + x = [].concat(...x, ...seed_ids); + return x; +} + +var g_database = new Database('core'); + +async function test_following() { + try { + debug_print("I AM", await ssb.whoami()); + var result = await followingDeep(g_database, [await ssb.whoami()], 1); + debug_print("following ", JSON.stringify(result)); + } catch (e) { + debug_print("DOH", e, e.stack); + } +} + +test_following(); + ssb.registerConnectionsChanged(function(change, connection) { if (change == 'add') { connection.send_json({'name': ['createHistoryStream'], 'type': 'source', 'args': [{'id': connection.id, 'seq': 0}]}, function(message) { diff --git a/src/ssb.qjs.c b/src/ssb.qjs.c index 0157c609..e2fcc157 100644 --- a/src/ssb.qjs.c +++ b/src/ssb.qjs.c @@ -1,5 +1,6 @@ #include "ssb.qjs.h" +#include "database.h" #include "ssb.db.h" #include "ssb.h" #include "task.h" @@ -17,6 +18,7 @@ static JSClassID _tf_ssb_classId; static JSValue _tf_ssb_whoami(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); + printf("WHOAMI on %p\n", ssb); if (ssb) { char id[512]; if (tf_ssb_whoami(ssb, id, sizeof(id))) { @@ -564,6 +566,18 @@ void tf_ssb_run_file(JSContext* context, const char* file_name) JS_FreeCString(context, value); JS_FreeValue(context, error); } + + JSRuntime* runtime = JS_GetRuntime(context); + while (JS_IsJobPending(runtime)) { + JSContext* context2 = NULL; + int r = JS_ExecutePendingJob(runtime, &context2); + JSValue result = JS_GetException(context2); + _check_call(context, result); + if (r == 0) { + break; + } + } + JS_FreeValue(context, result); free(source); } @@ -650,5 +664,6 @@ void tf_ssb_init(JSContext* context, tf_ssb_t* ssb) JS_FreeValue(context, global); + tf_database_init(context, tf_ssb_get_db(ssb)); tf_ssb_run_file(context, "core/ssb.js"); } diff --git a/src/ssb.tests.c b/src/ssb.tests.c index 621477ce..53d6ff73 100644 --- a/src/ssb.tests.c +++ b/src/ssb.tests.c @@ -98,7 +98,7 @@ void tf_ssb_test_ssb(const tf_test_options_t* options) bool b = tf_ssb_whoami(ssb0, id0, sizeof(id0)); (void)b; assert(b); - b = tf_ssb_whoami(ssb0, id0, sizeof(id0)); + b = tf_ssb_whoami(ssb1, id1, sizeof(id1)); assert(b); printf("ID %s and %s\n", id0, id1); diff --git a/src/tests.c b/src/tests.c index 7c6c9005..33cbd24b 100644 --- a/src/tests.c +++ b/src/tests.c @@ -497,7 +497,7 @@ static void _tf_test_run(const tf_test_options_t* options, const char* name, voi } if (!options->tests || specified) { - printf("Running test %s.", name); + printf("Running test %s.\n", name); test(options); } }