import * as tfrpc from '/tfrpc.js'; let g_hash; let g_collection_notifies = {}; tfrpc.register(async function getOwnerIdentities() { return ssb.getOwnerIdentities(); }); tfrpc.register(async function getIdentities() { return ssb.getIdentities(); }); tfrpc.register(async function query(sql, args) { let result = []; await ssb.sqlAsync(sql, args, function callback(row) { result.push(row); }); return result; }); tfrpc.register(async function localStorageGet(key) { return app.localStorageGet(key); }); tfrpc.register(async function localStorageSet(key, value) { return app.localStorageSet(key, value); }); tfrpc.register(async function following(ids, depth) { return ssb.following(ids, depth); }); tfrpc.register(async function appendMessage(id, message) { return ssb.appendMessageWithIdentity(id, message); }); tfrpc.register(async function store_blob(blob) { if (Array.isArray(blob)) { blob = Uint8Array.from(blob); } return await ssb.blobStore(blob); }); tfrpc.register(async function get_blob(id) { return utf8Decode(await ssb.blobGet(id)); }); let g_new_message_resolve; let g_new_message_promise = new Promise(function (resolve, reject) { g_new_message_resolve = resolve; }); function new_message() { return g_new_message_promise; } core.register('onMessage', function (id) { let resolve = g_new_message_resolve; g_new_message_promise = new Promise(function (resolve, reject) { g_new_message_resolve = resolve; }); if (resolve) { resolve(); } }); core.register('message', async function message_handler(message) { if (message.event == 'hashChange') { print('hash change', message.hash); g_hash = message.hash; await tfrpc.rpc.hash_changed(message.hash); } }); tfrpc.register(function set_hash(hash) { if (g_hash != hash) { return app.setHash(hash); } }); tfrpc.register(function get_hash(id, message) { return g_hash; }); tfrpc.register(async function try_decrypt(id, content) { return await ssb.privateMessageDecrypt(id, content); }); tfrpc.register(async function encrypt(id, recipients, content) { return await ssb.privateMessageEncrypt(id, recipients, content); }); async function process_message(whoami, collection, message, kind, parent) { let content = JSON.parse(message.content); if (typeof content == 'string') { let x; for (let id of whoami) { x = await ssb.privateMessageDecrypt(id, content); if (x) { content = JSON.parse(x); break; } } if (!x) { return; } if (content.type !== kind || (parent && content.parent !== parent)) { return; } } if (content?.key) { if (content?.tombstone) { delete collection[content.key]; } else { collection[content.key] = Object.assign( collection[content.key] || {}, content ); } } else { collection[message.id] = Object.assign(content, {id: message.id}); } return true; } tfrpc.register(async function collection(ids, kind, parent, max_rowid, data) { let whoami = await ssb.getIdentities(); data = data ?? {}; let rowid = 0; await ssb.sqlAsync( 'SELECT MAX(rowid) AS rowid FROM messages', [], function (row) { rowid = row.rowid; } ); while (true) { if (rowid == max_rowid) { await new_message(); await ssb.sqlAsync( 'SELECT MAX(rowid) AS rowid FROM messages', [], function (row) { rowid = row.rowid; } ); } let modified = false; let rows = []; await ssb.sqlAsync( ` SELECT messages.id, author, content, timestamp FROM messages JOIN json_each(?1) AS id ON messages.author = id.value WHERE messages.rowid > ?2 AND messages.rowid <= ?3 AND ((json_extract(messages.content, '$.type') = ?4 AND (?5 IS NULL OR json_extract(messages.content, '$.parent') = ?5)) OR content LIKE '"%') `, [JSON.stringify(ids), max_rowid ?? -1, rowid, kind, parent], function (row) { rows.push(row); } ); max_rowid = rowid; for (let row of rows) { if (await process_message(whoami, data, row, kind, parent)) { modified = true; } } if (modified) { break; } } return [rowid, data]; }); async function main() { await app.setDocument(utf8Decode(await getFile('index.html'))); } main();