diff --git a/nobilis b/nobilis index 3acf5be..ce6bc94 160000 --- a/nobilis +++ b/nobilis @@ -1 +1 @@ -Subproject commit 3acf5be36687bc611fdd743e739d8bac84cd33af +Subproject commit ce6bc943155d09da8017081166078c704b8f2380 diff --git a/src/renderer/src/components/AccountsPanel.tsx b/src/renderer/src/components/AccountsPanel.tsx index 6ff7618..97ec38e 100644 --- a/src/renderer/src/components/AccountsPanel.tsx +++ b/src/renderer/src/components/AccountsPanel.tsx @@ -513,19 +513,64 @@ function SneedchatRooms({ call: (method: string, params: Record) => void }): JSX.Element { const enabled = account.sockchatRooms ?? [] + /** + * The catalogue, from the site. + * + * It used to be six rooms written into this client, which is how #lolcows + * came to be unreachable without editing the source. The daemon reads the + * room switcher off the chat page - the same list a person sees down the + * side of the site - and this asks for it when the account's settings are + * opened. + * + * The built-in list is the fallback rather than the source: the site is + * behind a proof-of-work gate over Tor and the fetch can fail, and six + * rooms somebody can still tick is a better answer than none. + */ + const [rooms, setRooms] = useState(KNOWN_SOCKCHAT_ROOMS) + const [asking, setAsking] = useState(true) + const [error, setError] = useState('') + + useEffect(() => { + let live = true + setAsking(true) + // The answer to this is whatever the daemon read last, which may be + // nothing on a fresh start; the live read happens behind it and arrives + // as an event, because it takes about fifteen seconds through Tor and the + // site's gate and the daemon answers one request at a time. + void window.moho + .rpc<{ rooms: { id: number; name: string }[] }>('listSockChatRooms', { accountId: account.id }) + .then((r) => live && r.rooms?.length && setRooms(r.rooms)) + .catch((e: Error) => live && setError(e.message)) + + const stop = window.moho.onEvent((frame) => { + if (frame.event !== 'sockchatRooms') return + const data = frame.data as { accountId: string; rooms: { id: number; name: string }[] } + if (!live || data.accountId !== account.id || !data.rooms.length) return + setRooms(data.rooms) + setAsking(false) + setError('') + }) + return () => { + live = false + stop() + } + }, [account.id]) + const toggle = (id: number, on: boolean): void => { const next = on ? enabled.some((r) => r.id === id) ? enabled - : [...enabled, KNOWN_SOCKCHAT_ROOMS.find((r) => r.id === id)!] + : [...enabled, rooms.find((r) => r.id === id)!] : enabled.filter((r) => r.id !== id) call('setSockChatRooms', { accountId: account.id, rooms: next }) } return (
- Channels - {KNOWN_SOCKCHAT_ROOMS.map((room) => ( + + Channels{asking ? ' — asking the site…' : ''} + + {rooms.map((room) => ( ))} + {/* Said rather than hidden: this list is the one this client shipped + with, and the site may well have rooms that are not in it. */} + {error && ( + + Could not read the site's room list ({error}) — showing the rooms this client knows. + + )} {/* An account with none ticked still connects to #general - the daemon falls back to it so a freshly added account is usable before anybody has been here. Worth saying, or an empty list reads as "connected to diff --git a/src/renderer/src/lib/sockchat.ts b/src/renderer/src/lib/sockchat.ts index 2da84ef..0127590 100644 --- a/src/renderer/src/lib/sockchat.ts +++ b/src/renderer/src/lib/sockchat.ts @@ -1,9 +1,12 @@ /** - * The Sneedchat rooms an account can be connected to. + * The Sneedchat rooms this client knows about without asking. * - * No server-side "list every room" endpoint exists, so this is the fixed - * catalogue the account was originally configured against. Adding a room the - * site actually has just means it can be toggled on too. + * No longer the catalogue: the daemon reads the real one off the site's own + * chat page (see listSockChatRooms), which is how #lolcows was reachable to + * everybody using the site and to nobody using this. This is what shows while + * that is being fetched, and what remains if it cannot be - the site sits + * behind a proof-of-work gate over Tor, and rooms somebody can still tick beat + * an empty list. * * Shared rather than owned by whichever pane happens to draw it: the rooms are * a property of an account, and two places disagreeing about which rooms exist @@ -15,5 +18,6 @@ export const KNOWN_SOCKCHAT_ROOMS: { id: number; name: string }[] = [ { id: 15, name: 'keno-kasino' }, { id: 16, name: 'fishtank' }, { id: 18, name: 'beauty-parlor' }, - { id: 19, name: 'sports' } + { id: 19, name: 'sports' }, + { id: 20, name: 'lolcows' } ]