From 515999e570b36204fb479e371f9288e4b2e895ad Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Mon, 20 Jun 2022 01:34:32 +0000 Subject: [PATCH] Use tfrpc fairly thoroughly in the ssb app. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3912 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- apps/cory/ssb.json | 2 +- apps/cory/ssb/app.js | 57 ++++----- apps/cory/ssb/tf.js | 298 +++++++++++++++++++++---------------------- core/tfrpc.js | 8 +- 4 files changed, 173 insertions(+), 192 deletions(-) diff --git a/apps/cory/ssb.json b/apps/cory/ssb.json index 7ea8cc8a4..b455da1d0 100644 --- a/apps/cory/ssb.json +++ b/apps/cory/ssb.json @@ -1 +1 @@ -{"type":"tildefriends-app","files":{"app.js":"&7v8vYyzZmo/SFkcyrTPnlv/jZc9xt36zv7N9ZTdEt7s=.sha256","index.html":"&TGAqOmpnOigx4XQbFix82ugZEOfR1Gdc2zMWUQMSvwI=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&smJOHGgIsKwQXeEJD3VbHX4A+vhr1Se54WlSHUP/Km8=.sha256","tf-message.js":"&nf978NOZPz1i97/nYMA2kHOm0HTlF4pm5UgpqE8+JSE=.sha256","tf.js":"&ZXBUsG/ZZWxd1RtrdcPPvpH4Qa2XvUUgL0x9KNqqSe0=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&MPINm55jkpz2rrNbwsYl09PKGvbgL3nwgBy6CMQkSnw=.sha256","style.css":"&qegBNCrVUihxffRUxGFuG/6u+0Y6d18zHtfNHBZtZ04=.sha256"}} \ No newline at end of file +{"type":"tildefriends-app","files":{"app.js":"&IDS+f+x15uvrrvh7vC2h3FhrShS4OquL01vFZaugqC0=.sha256","index.html":"&TGAqOmpnOigx4XQbFix82ugZEOfR1Gdc2zMWUQMSvwI=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&smJOHGgIsKwQXeEJD3VbHX4A+vhr1Se54WlSHUP/Km8=.sha256","tf-message.js":"&nf978NOZPz1i97/nYMA2kHOm0HTlF4pm5UgpqE8+JSE=.sha256","tf.js":"&0+ub/dNZzf74GUWyVIzGZPb6pKJDx6y7I4Stsosh9Y0=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&MPINm55jkpz2rrNbwsYl09PKGvbgL3nwgBy6CMQkSnw=.sha256","style.css":"&qegBNCrVUihxffRUxGFuG/6u+0Y6d18zHtfNHBZtZ04=.sha256"}} \ No newline at end of file diff --git a/apps/cory/ssb/app.js b/apps/cory/ssb/app.js index 55f6d0a58..78d257a22 100644 --- a/apps/cory/ssb/app.js +++ b/apps/cory/ssb/app.js @@ -406,12 +406,12 @@ tfrpc.register(async function store_blob(blob) { }); ssb.addEventListener('broadcasts', async function() { - await app.postMessage({broadcasts: await ssb.getBroadcasts()}); + await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts()); }); core.register('onConnectionsChanged', async function() { var connections = await ssb.connections(); - await app.postMessage({connections: connections}); + await tfrpc.rpc.set('connections', connections); }); async function updateSequences(db) { @@ -443,7 +443,7 @@ async function refresh(selected) { timing.push({name: 'start', time: new Date()}); g_following_cache = {}; g_following_deep_cache = {}; - await app.postMessage({clear: true}); + await tfrpc.rpc.clear(); var whoami = await ssb.whoami(); var db = await database("ssb"); g_sequence = {}; @@ -463,11 +463,11 @@ async function refresh(selected) { g_selected = all_followed; } await Promise.all([ - app.postMessage({whoami: whoami}), - app.postMessage({hash: selected && selected.length == 1 ? selected[0] : null}), - ssb.getBroadcasts().then(broadcasts => app.postMessage({broadcasts: broadcasts})), - ssb.connections().then(connections => app.postMessage({connections: connections})), - core.apps().then(apps => app.postMessage({apps: apps})), + tfrpc.rpc.set('whoami', whoami),, + tfrpc.rpc.set_hash(selected && selected.length == 1 ? selected[0] : null), + tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts()), + tfrpc.rpc.set('connections', await ssb.connections()), + tfrpc.rpc.set('apps', await core.apps()), ]); timing.push({name: 'core', time: new Date()}); var ids; @@ -492,9 +492,15 @@ async function refresh(selected) { roots = [...new Set(roots)].filter(x => x && !have.has(x)); var all_posts = [].concat(posts, await getPosts(db, roots)); timing.push({name: 'get_root_posts', time: new Date()}); - await Promise.all(all_posts.map(x => app.postMessage({message: x}))); + await tfrpc.rpc.push_posts(all_posts); timing.push({name: 'send_posts', time: new Date()}); - await Promise.all(all_followed.map(id => getAbout(db, id).then(results => Object.keys(results).length ? app.postMessage({user: {user: id, about: results}}) : null))); + let all_users = {}; + await Promise.all(all_followed.map(id => getAbout(db, id).then(function(results) { + if (Object.keys(results).length) { + all_users[id] = results; + } + }))); + await tfrpc.rpc.push_users(all_users); timing.push({name: 'about', time: new Date()}); var all_votes = []; for (let id of all_followed) { @@ -504,11 +510,7 @@ async function refresh(selected) { } } all_votes = all_votes.flat(); - const k_votes_send_max = 2048; - for (var i = 0; i < all_votes.length; i += k_votes_send_max) { - var votes = all_votes.slice(i, Math.min(i + k_votes_send_max, all_votes.length)); - await app.postMessage({votes: votes}); - } + await tfrpc.rpc.push_votes(all_votes); timing.push({name: 'votes', time: new Date()}); if (selected && selected.length == 1 && selected[0].startsWith('@')) { let size = 0; @@ -518,20 +520,13 @@ async function refresh(selected) { function(row) { size = row.length; }); - await app.postMessage({user: {user: selected[0], about: {size: size}}}); + let users = {}; + users[selected[0]] = {size: size}; + await tfrpc.rpc.push_users(users); } - await all_followed.map( - id => app.postMessage( - { - following: { - id: id, - users: [...(g_following_cache[id] || [])], - } - } - ) - ); + await tfrpc.rpc.push_following(Object.fromEntries(all_followed.map(id => [id, [...(g_following_cache[id] || [])]]))); timing.push({name: 'following', time: new Date()}); - await app.postMessage({blocking: {id: whoami, users: [...(g_blocking_cache[whoami] || [])]}}); + await tfrpc.rpc.push_blocking(whoami, [...(g_blocking_cache[whoami] || [])]); timing.push({name: 'send_blocking', time: new Date()}); await db.set('sequence', JSON.stringify(g_sequence)); @@ -541,7 +536,7 @@ async function refresh(selected) { times[t.name] = (t.time - (previous || t).time) / 1000.0 + ' s'; previous = t; } - await app.postMessage({ready: true, times: times}); + await tfrpc.rpc.ready(times); } ssb.addEventListener('message', async function(id) { @@ -550,9 +545,9 @@ ssb.addEventListener('message', async function(id) { for (let post of posts) { if (post.author == await ssb.whoami() || JSON.parse(post.content).type != 'post') { - await app.postMessage({message: post}); + await tfrpc.rpc.push_posts([post]); } else { - await app.postMessage({unread: 1}); + await tfrpc.rpc.add_unread(1); } } }); @@ -593,8 +588,6 @@ core.register('message', async function(m) { if (g_ready) { await refresh(g_selected); } - } else if (m.event == 'storeBlobComplete') { - await app.postMessage({storeBlobComplete: m.path}); } else if (m.event == 'focus' || m.event == 'blur') { /* Shh. */ } else { diff --git a/apps/cory/ssb/tf.js b/apps/cory/ssb/tf.js index 5e78a2fb4..b3a265cb1 100644 --- a/apps/cory/ssb/tf.js +++ b/apps/cory/ssb/tf.js @@ -30,8 +30,6 @@ export var g_data = { var g_load_start = new Date(); var g_data_initial = JSON.parse(JSON.stringify(g_data)); -var g_message_queue = []; -var g_process_pending = false; function updateEditUser() { g_data.edit_profile_name = g_data.users[g_data.whoami] ? g_data.users[g_data.whoami].name : null; @@ -39,155 +37,140 @@ function updateEditUser() { g_data.edit_profile_image = g_data.users[g_data.whoami] ? g_data.users[g_data.whoami].image : null; } -function processMessages() { - for (let event of g_message_queue) { - var key = Object.keys(event.data)[0]; - if (key == 'message') { - var new_message = event.data.message; - new_message.children = []; - var found = false; - var root = JSON.parse(new_message.content).root; +tfrpc.register(function set_hash(hash) { + g_data.selected = hash; + if (g_data.selected == g_data.whoami) { + updateEditUser(); + } +}); - /* If we had inserted a fake root, replace it if we see the real message. */ - if (g_data.messages_by_id[new_message.id]) { - var old_message = g_data.messages_by_id[new_message.id]; - new_message.children = old_message.children; - for (let child of new_message.children) { - child.parent = new_message; - } - if (old_message.parent) { - old_message.parent.children = old_message.parent.children.filter(x => x != old_message); - } else { - g_data.messages = g_data.messages.filter(x => x != old_message); - } - } +tfrpc.register(function clear() { + g_load_start = new Date(); + g_data.loading = true; + Object.keys(g_data_initial).forEach(function(key) { + Vue.set(g_data, key, JSON.parse(JSON.stringify(g_data_initial[key]))); + }); +}); - Vue.set(g_data.messages_by_id, new_message.id, new_message); +tfrpc.register(function set(key, value) { + g_data[key] = value; +}); - if (root) { - /* If we don't know of the message's root, add it. */ - if (!g_data.messages_by_id[root]) { - var fake_root = { - id: root, - children: [], - timestamp: new_message.timestamp, - content: '{}', - }; - Vue.set(g_data.messages_by_id, root, fake_root); - g_data.messages.push(fake_root); - g_data.messages.sort((x, y) => y.timestamp - x.timestamp); - found = true; - } - var message = g_data.messages_by_id[root]; - new_message.parent = message; - message.children.push(new_message); - message.children.sort((x, y) => x.timestamp - y.timestamp); - } else { - /* This is just a new message with no root. Add it. */ - g_data.messages.push(new_message); - g_data.messages.sort((x, y) => y.timestamp - x.timestamp); - g_data.messages = g_data.messages.slice(0, 32); - } - } else if (key + 's' in g_data && Array.isArray(g_data[key + 's'])) { - g_data[key + 's'].push(event.data[key]); - } else if (key == 'user') { - Vue.set(g_data.users, event.data.user.user, Object.assign({}, g_data.users[event.data.user.user] || {}, event.data.user.about)); - if (event.data.user.user == g_data.whoami) { - updateEditUser(); - } - } else if (key == 'following') { - if (!g_data.users[event.data.following.id]) { - Vue.set(g_data.users, event.data.following.id, {}); - } - if (!g_data.users[event.data.following.id].following) { - Vue.set(g_data.users[event.data.following.id], 'following', {}); - } - for (let user of event.data.following.users) { - Vue.set(g_data.users[event.data.following.id].following, user, true); - if (!g_data.users[user]) { - Vue.set(g_data.users, user, {}); - } - if (!g_data.users[user].followers) { - Vue.set(g_data.users[user], 'followers', {}); - } - Vue.set(g_data.users[user].followers, event.data.following.id, true); - } - } else if (key == 'blocking') { - if (!g_data.users[event.data.blocking.id]) { - Vue.set(g_data.users, event.data.blocking.id, {}); - } - if (!g_data.users[event.data.blocking.id].blocking) { - Vue.set(g_data.users[event.data.blocking.id], 'blocking', {}); - } - for (let user of event.data.blocking.users) { - Vue.set(g_data.users[event.data.blocking.id].blocking, user, true); - } - } else if (key == 'broadcasts') { - g_data.broadcasts = event.data.broadcasts; - } else if (key == 'pubs') { - g_data.pubs = event.data.pubs; - } else if (key == 'apps') { - g_data.apps = event.data.apps; - } else if (key == 'votes') { - event.data.votes.forEach(function(vote) { - var content = JSON.parse(vote.content); - var link = content.vote.link; - if (!g_data.votes[link]) { - Vue.set(g_data.votes, link, {}); - } - if (!g_data.votes[link][content.vote.expression]) { - Vue.set(g_data.votes[link], content.vote.expression, []); - } - g_data.votes[link][content.vote.expression].push({author: vote.author, value: content.vote.value}); - }); - } else if (key == 'clear') { - g_load_start = new Date(); - g_data.loading = true; - Object.keys(g_data_initial).forEach(function(key) { - Vue.set(g_data, key, JSON.parse(JSON.stringify(g_data_initial[key]))); - }); - } else if (key == 'ready') { - g_data.load_time = (new Date() - g_load_start) / 1000; - g_data.loading = false; - g_data.times = event.data.times; - } else if (key == 'unread') { - g_data.unread += event.data.unread; - } else if (key == 'hash') { - g_data.selected = event.data.hash; - if (g_data.selected == g_data.whoami) { - updateEditUser(); - } - } else if (key == 'storeBlobComplete') { - var blob = event.data.storeBlobComplete; - if (blob.context == 'profile') { - g_data.edit_profile_image = blob.path.substring(1); - } else { - g_data.post_text = (g_data.post_text || '') + `\n![${blob.name}](${blob.path.substring(1)})`; - Vue.set(g_data.mentions, blob.path.substring(1), { - link: blob.path.substring(1), - name: blob.name, - type: blob.type, - }); - } - } else { - g_data[key] = event.data[key]; +tfrpc.register(function push_users(users) { + for (let [id, user] of Object.entries(users)) { + Vue.set(g_data.users, id, Object.assign({}, g_data.users[id] || {}, user)); + if (id == g_data.whoami) { + updateEditUser(); } } - g_message_queue = []; - g_process_pending = false; -} +}); -window.addEventListener('message', function(event) { - if (event.data.message === 'tfrpc') { - return; +tfrpc.register(function push_posts(posts) { + for (let new_message of posts) { + new_message.children = []; + var found = false; + var root = JSON.parse(new_message.content).root; + + /* If we had inserted a fake root, replace it if we see the real message. */ + if (g_data.messages_by_id[new_message.id]) { + var old_message = g_data.messages_by_id[new_message.id]; + new_message.children = old_message.children; + for (let child of new_message.children) { + child.parent = new_message; + } + if (old_message.parent) { + old_message.parent.children = old_message.parent.children.filter(x => x != old_message); + } else { + g_data.messages = g_data.messages.filter(x => x != old_message); + } + } + + Vue.set(g_data.messages_by_id, new_message.id, new_message); + + if (root) { + /* If we don't know of the message's root, add it. */ + if (!g_data.messages_by_id[root]) { + var fake_root = { + id: root, + children: [], + timestamp: new_message.timestamp, + content: '{}', + }; + Vue.set(g_data.messages_by_id, root, fake_root); + g_data.messages.push(fake_root); + g_data.messages.sort((x, y) => y.timestamp - x.timestamp); + found = true; + } + var message = g_data.messages_by_id[root]; + new_message.parent = message; + message.children.push(new_message); + message.children.sort((x, y) => x.timestamp - y.timestamp); + } else { + /* This is just a new message with no root. Add it. */ + g_data.messages.push(new_message); + g_data.messages.sort((x, y) => y.timestamp - x.timestamp); + g_data.messages = g_data.messages.slice(0, 32); + } } - g_message_queue.push(event); - if (!g_process_pending) { - g_process_pending = true; - setTimeout(processMessages, 250); +}); + +tfrpc.register(function push_votes(votes) { + votes.forEach(function(vote) { + var content = JSON.parse(vote.content); + var link = content.vote.link; + if (!g_data.votes[link]) { + Vue.set(g_data.votes, link, {}); + } + if (!g_data.votes[link][content.vote.expression]) { + Vue.set(g_data.votes[link], content.vote.expression, []); + } + g_data.votes[link][content.vote.expression].push({author: vote.author, value: content.vote.value}); + }); +}); + +tfrpc.register(function push_following(following) { + for (let [id, users] of Object.entries(following)) { + if (!g_data.users[id]) { + Vue.set(g_data.users, id, {}); + } + if (!g_data.users[id].following) { + Vue.set(g_data.users[id], 'following', {}); + } + for (let user of users) { + Vue.set(g_data.users[id].following, user, true); + if (!g_data.users[user]) { + Vue.set(g_data.users, user, {}); + } + if (!g_data.users[user].followers) { + Vue.set(g_data.users[user], 'followers', {}); + } + Vue.set(g_data.users[user].followers, id, true); + } } }); +tfrpc.register(function push_blocking(id, blocking) { + if (!g_data.users[id]) { + Vue.set(g_data.users, id, {}); + } + if (!g_data.users[id].blocking) { + Vue.set(g_data.users[id], 'blocking', {}); + } + for (let user of blocking) { + Vue.set(g_data.users[id].blocking, user, true); + } +}); + +tfrpc.register(function add_unread(unread) { + g_data.unread += unread; +}); + +tfrpc.register(function ready(times) { + g_data.load_time = (new Date() - g_load_start) / 1000; + g_data.loading = false; + g_data.times = times; +}); + window.addEventListener('load', function() { Vue.use(VueMaterial.default); var vue = new Vue({ @@ -280,12 +263,16 @@ window.addEventListener('load', function() { let bin = Array.from(new Uint8Array(buffer)); return tfrpc.rpc.store_blob(bin); }).then(function(id) { - g_data.post_text = `${g_data.post_text || ''}\n![${file.name}](${id})`; - Vue.set(g_data.mentions, id, { - link: id, - name: file.name, - type: file.type, - }); + if (context == 'profile') { + g_data.edit_profile_image = id; + } else { + g_data.post_text = `${g_data.post_text || ''}\n![${file.name}](${id})`; + Vue.set(g_data.mentions, id, { + link: id, + name: file.name, + type: file.type, + }); + } }).catch(function(e) { console.log('error', e); }); @@ -298,14 +285,15 @@ window.addEventListener('load', function() { var file = item.getAsFile(); if (file) { file.arrayBuffer().then(function(buffer) { - window.parent.postMessage({ - action: 'storeBlob', - blob: { - name: file.name, - type: file.type, - buffer: buffer, - }, - }, '*'); + let bin = Array.from(new Uint8Array(buffer)); + return tfrpc.rpc.store_blob(bin); + }).then(function(id) { + g_data.post_text = `${g_data.post_text || ''}\n![${file.name}](${id})`; + Vue.set(g_data.mentions, id, { + link: id, + name: file.name, + type: file.type, + }); }); event.preventDefault(); break; diff --git a/core/tfrpc.js b/core/tfrpc.js index 9b0f4f828..d422477cc 100644 --- a/core/tfrpc.js +++ b/core/tfrpc.js @@ -55,16 +55,16 @@ function call_rpc(message) { } else { throw new Error(message.method + ' not found.'); } - } else if (message.result !== undefined) { + } else if (message.error !== undefined) { if (g_calls[message.id]) { - g_calls[message.id].resolve(message.result); + g_calls[message.id].reject(message.error); delete g_calls[message.id]; } else { throw new Error(message.id + ' not found to reply.'); } - } else if (message.error !== undefined) { + } else { if (g_calls[message.id]) { - g_calls[message.id].reject(message.error); + g_calls[message.id].resolve(message.result); delete g_calls[message.id]; } else { throw new Error(message.id + ' not found to reply.');