import { $joinedUser, $says, $user, asJoin, asSays, asUserInfo, fromNickClaim, fromSays, NickClaim, Says, UserId } from "../gen/secure-chat-protocol.js"; import { during, observe } from "../runtime/dataspace.js"; import { Assertion, Ref, Turn } from "../runtime/actor.js"; import { attachReadline } from './readline.js'; import { Embedded } from "@preserves/core"; export default function (t: Turn, ds_ptr: Embedded) { const ds = ds_ptr.embeddedValue; observe(t, ds, $joinedUser, during(async (t, j0) => { const j = asJoin(j0); const facet = t.facet(t => runSession(t, j.uid, j.handle)); return t => t.stop(facet); })); } function runSession(t: Turn, uid: UserId, session: Ref) { let username: string | undefined; let cleanShutdown = false; t.activeFacet.onStop(_t => { if (!cleanShutdown) { console.log('Moderator retracted room permission.'); } }); function updateUsername(t: Turn, name: string) { const q = t.assert(session, fromNickClaim(NickClaim({ uid, name, k: t.ref({ message(t, reply0) { if (reply0 === true) { username = name; console.log(`Nick changed to ${username}`); } else { console.log(`Nick conflict: name is still ${username ?? ''}`); } t.retract(q); } })}))); } updateUsername(t, 'user' + process.pid); const users = new Map(); observe(t, session, $user, during(async (_t, ui0) => { const ui = asUserInfo(ui0); const oldName = users.get(ui.uid); console.log(oldName === void 0 ? `${ui.name} arrived` : `${oldName} changed name to ${ui.name}`); users.set(ui.uid, ui.name); return (_t) => { if (users.get(ui.uid) === ui.name) { console.log(`${ui.name} departed`); users.delete(ui.uid); } }; })); observe(t, session, $says, { message(_t: Turn, u0: Assertion): void { const u = asSays(u0); console.log(`${users.get(u.who) ?? ``}: ${u.what}`); }, }); attachReadline(t, { retract(t) { cleanShutdown = true; t.stopActor(); }, message(t, line: string) { if (line.toLowerCase().startsWith('/nick ')) { updateUsername(t, line.slice(5).trimLeft()); } else { t.message(session, fromSays(Says({ who: uid, what: line }))); } }, }); }