124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
/// SPDX-License-Identifier: GPL-3.0-or-later
|
|
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
|
|
|
import { Dataspace, Ref, Sturdy, AnyValue, Reader, Schemas, Embedded } from "@syndicate-lang/core";
|
|
import { boot as bootHtml, Anchor, template as html, HtmlFragments, GlobalEvent, UIAttribute, UIChangeableProperty } from "@syndicate-lang/html";
|
|
import { boot as bootWakeDetector, WakeEvent } from "./wake-detector";
|
|
import { boot as bootWsRelay, ForceRelayDisconnect, RelayAddress, Resolved } from "@syndicate-lang/ws-relay";
|
|
import { Present, Says } from './gen/simpleChatProtocol';
|
|
|
|
const Transport = Schemas.transportAddress;
|
|
|
|
export function main() {
|
|
document.getElementById('chat_form')!.onsubmit = e => { e.preventDefault(); return false; };
|
|
document.getElementById('nym_form')!.onsubmit = e => { e.preventDefault(); return false; };
|
|
setWsurl();
|
|
setUsernameIfUnset();
|
|
document.getElementById('chat_input')!.focus();
|
|
|
|
Dataspace.boot(ds => {
|
|
bootHtml(ds);
|
|
bootWakeDetector(ds);
|
|
bootWsRelay(ds, true);
|
|
bootChat(ds);
|
|
});
|
|
}
|
|
|
|
function bootChat(ds: Ref) {
|
|
spawn named 'chat' {
|
|
at ds {
|
|
field nym: string = '';
|
|
on asserted UIChangeableProperty('#nym', 'value', $v: string) => nym.value = v;
|
|
|
|
during UIChangeableProperty('#wsurl', 'value', $wsurl: string) =>
|
|
during UIChangeableProperty('#servercap', 'value', $servercapText: string) => {
|
|
let servercap: AnyValue | null = null;
|
|
try {
|
|
const a = new Reader<Ref>(servercapText).next();
|
|
Sturdy.asSturdyRef(a); // throws if invalid
|
|
servercap = a;
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
assert UIAttribute('#servercap', 'class', 'invalid') when (!servercap);
|
|
if (wsurl && servercap) {
|
|
contactRemote(wsurl, servercap);
|
|
}
|
|
}
|
|
|
|
function contactRemote(wsurl: string, servercap: AnyValue) {
|
|
during Resolved({
|
|
"addr": RelayAddress(Transport.WebSocket(wsurl)),
|
|
"sturdyref": servercap,
|
|
"resolved": $remoteDs_e: Embedded,
|
|
}) => {
|
|
const remoteDs = remoteDs_e.embeddedValue;
|
|
|
|
on message WakeEvent() =>
|
|
send message ForceRelayDisconnect(RelayAddress(Transport.WebSocket(wsurl)));
|
|
|
|
outputState('connected', 'connected to ' + wsurl);
|
|
on stop outputState('disconnected', 'disconnected from ' + wsurl);
|
|
|
|
on message GlobalEvent('#send_chat', 'click', _) => {
|
|
const inp = document.getElementById("chat_input") as HTMLInputElement;
|
|
var utterance = inp.value;
|
|
inp.value = '';
|
|
if (utterance) {
|
|
at remoteDs {
|
|
send message Says({ who: nym.value, what: utterance });
|
|
}
|
|
}
|
|
}
|
|
|
|
at remoteDs {
|
|
assert Present(nym.value);
|
|
|
|
const ui = new Anchor();
|
|
during Present($who: string) => at ds {
|
|
assert ui.context(who).html('#nymlist', html`<li>${who}</li>`);
|
|
}
|
|
|
|
on message Says({ "who": $who: string, "what": $what: string }) => {
|
|
outputUtterance(who, what);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setWsurl() {
|
|
const wsurl = document.getElementById('wsurl')! as HTMLInputElement;
|
|
if (wsurl.value === '') {
|
|
wsurl.value = `ws://${document.location.hostname}:9001/`;
|
|
}
|
|
}
|
|
|
|
function setUsernameIfUnset() {
|
|
const nym = document.getElementById('nym')! as HTMLInputElement;
|
|
if (nym.value === '') {
|
|
nym.value = "nym" + Math.floor(Math.random() * 65536);
|
|
}
|
|
}
|
|
|
|
function outputItem(cls: string, item0: HtmlFragments): ChildNode {
|
|
const stamp = html`<span class="timestamp">${(new Date()).toUTCString()}</span>`;
|
|
const item = html`<div class="${cls}">${stamp}${item0}</div>`;
|
|
const n = item.node();
|
|
const o = document.getElementById('chat_output')!;
|
|
o.appendChild(n);
|
|
o.scrollTop = o.scrollHeight;
|
|
return n;
|
|
}
|
|
|
|
function outputState(cls: string, state: string) {
|
|
outputItem(`state_${cls}`, html`<span class="state ${cls}">${state}</span>`)
|
|
}
|
|
|
|
function outputUtterance(who: string, what: string) {
|
|
outputItem('utterance',
|
|
html`<span class="nym">${who}</span><span class="utterance">${what}</span>`);
|
|
}
|