import {LitElement, html, css, guard, until} from './lit-all.min.js'; import * as tfrpc from '/static/tfrpc.js'; import {styles} from './tf-styles.js'; class TfElement extends LitElement { static get properties() { return { whoami: {type: String}, hash: {type: String}, unread: {type: Array}, tab: {type: String}, broadcasts: {type: Array}, connections: {type: Array}, loading: {type: Boolean}, loaded: {type: Boolean}, following: {type: Array}, users: {type: Object}, ids: {type: Array}, tags: {type: Array}, }; } static styles = styles; constructor() { super(); let self = this; this.hash = '#'; this.unread = []; this.tab = 'news'; this.broadcasts = []; this.connections = []; this.following = []; this.users = {}; this.loaded = false; this.tags = []; tfrpc.rpc.getBroadcasts().then((b) => { self.broadcasts = b || []; }); tfrpc.rpc.getConnections().then((c) => { self.connections = c || []; }); tfrpc.rpc.getHash().then((hash) => self.set_hash(hash)); tfrpc.register(function hashChanged(hash) { self.set_hash(hash); }); tfrpc.register(async function notifyNewMessage(id) { await self.fetch_new_message(id); }); tfrpc.register(function set(name, value) { if (name === 'broadcasts') { self.broadcasts = value; } else if (name === 'connections') { self.connections = value; } }); this.initial_load(); } async initial_load() { let whoami = await tfrpc.rpc.localStorageGet('whoami'); let ids = (await tfrpc.rpc.getIdentities()) || []; this.whoami = whoami ?? (ids.length ? ids[0] : undefined); this.ids = ids; } set_hash(hash) { this.hash = hash || '#'; if (this.hash.startsWith('#q=')) { this.tab = 'search'; } else if (this.hash === '#connections') { this.tab = 'connections'; } else if (this.hash === '#mentions') { this.tab = 'mentions'; } else if (this.hash.startsWith('#sql=')) { this.tab = 'query'; } else { this.tab = 'news'; } } async fetch_about(ids, users) { const k_cache_version = 1; let cache = await tfrpc.rpc.databaseGet('about'); cache = cache ? JSON.parse(cache) : {}; if (cache.version !== k_cache_version) { cache = { version: k_cache_version, about: {}, last_row_id: 0, }; } let max_row_id = ( await tfrpc.rpc.query( ` SELECT MAX(rowid) AS max_row_id FROM messages `, [] ) )[0].max_row_id; for (let id of Object.keys(cache.about)) { if (ids.indexOf(id) == -1) { delete cache.about[id]; } } let abouts = await tfrpc.rpc.query( ` SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature FROM messages, json_each(?1) AS following WHERE messages.author = following.value AND messages.rowid > ?3 AND messages.rowid <= ?4 AND json_extract(messages.content, '$.type') = 'about' UNION SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature FROM messages, json_each(?2) AS following WHERE messages.author = following.value AND messages.rowid <= ?4 AND json_extract(messages.content, '$.type') = 'about' ORDER BY messages.author, messages.sequence `, [ JSON.stringify(ids.filter((id) => cache.about[id])), JSON.stringify(ids.filter((id) => !cache.about[id])), cache.last_row_id, max_row_id, ] ); for (let about of abouts) { let content = JSON.parse(about.content); if (content.about === about.author) { delete content.type; delete content.about; cache.about[about.author] = Object.assign( cache.about[about.author] || {}, content ); } } cache.last_row_id = max_row_id; await tfrpc.rpc.databaseSet('about', JSON.stringify(cache)); users = users || {}; for (let id of Object.keys(cache.about)) { users[id] = Object.assign(users[id] || {}, cache.about[id]); } return Object.assign({}, users); } async fetch_new_message(id) { let messages = await tfrpc.rpc.query( ` SELECT messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature FROM messages JOIN json_each(?) AS following ON messages.author = following.value WHERE messages.id = ? `, [JSON.stringify(this.following), id] ); if (messages && messages.length) { this.unread = [...this.unread, ...messages]; this.unread = this.unread.slice(this.unread.length - 1024); } } async _handle_whoami_changed(event) { let old_id = this.whoami; let new_id = event.srcElement.selected; console.log('received', new_id); if (this.whoami !== new_id) { console.log(event); this.whoami = new_id; console.log(`whoami ${old_id} => ${new_id}`); await tfrpc.rpc.localStorageSet('whoami', new_id); } } async create_identity() { if (confirm('Are you sure you want to create a new identity?')) { await tfrpc.rpc.createIdentity(); this.ids = (await tfrpc.rpc.getIdentities()) || []; if (this.ids && !this.whoami) { this.whoami = this.ids[0]; } } } render_id_picker() { return html`