diff --git a/cmd/vail/message.go b/cmd/vail/message.go index ef036e4..eb98270 100644 --- a/cmd/vail/message.go +++ b/cmd/vail/message.go @@ -3,7 +3,6 @@ package main import ( "bytes" "encoding/binary" - "fmt" "time" ) diff --git a/static/index.html b/static/index.html index 970e203..43e6987 100644 --- a/static/index.html +++ b/static/index.html @@ -72,7 +72,7 @@
- + diff --git a/static/outputs.mjs b/static/outputs.mjs index 6cfa56d..f4f251c 100644 --- a/static/outputs.mjs +++ b/static/outputs.mjs @@ -137,6 +137,10 @@ class Sample { * A (mostly) virtual class defining a buzzer. */ class Buzzer { + constructor() { + this.connected = true + } + /** * Signal an error */ @@ -175,6 +179,15 @@ class Buzzer { this.Buzz(tx, when) this.Silence(tx, when + duration) } + + /** + * Set the "connectedness" indicator. + * + * @param {boolean} connected True if connected + */ + SetConnected(connected) { + this.connected = connected + } } class AudioBuzzer extends Buzzer { @@ -297,6 +310,17 @@ class LampBuzzer extends Buzzer { ms, ) } + + SetConnected(connected) { + console.log(connected) + for (let e of this.elements) { + if (connected) { + e.classList.add("connected") + } else { + e.classList.remove("connected") + } + } + } } class MIDIBuzzer extends Buzzer { @@ -415,7 +439,7 @@ class Collection { * * @param tx True if transmitting */ - Silence(tx=False) { + Silence(tx=false) { for (let b of this.collection) { b.Silence(tx) } @@ -433,6 +457,19 @@ class Collection { b.BuzzDuration(tx, when, duration) } } + + /** + * Update the "connected" status display. + * + * For example, turn the receive light to black if the repeater is not connected. + * + * @param {boolean} connected True if we are "connected" + */ + SetConnected(connected) { + for (let b of this.collection) { + b.SetConnected(connected) + } + } } export {AudioReady, Collection} diff --git a/static/repeaters.mjs b/static/repeaters.mjs index c943801..a2469ef 100644 --- a/static/repeaters.mjs +++ b/static/repeaters.mjs @@ -30,6 +30,7 @@ export class Vail { this.lagDurations = [] this.sent = [] this.wantConnected = true + this.connected = false this.wsUrl = new URL("chat", window.location) this.wsUrl.protocol = this.wsUrl.protocol.replace("http", "ws") @@ -43,10 +44,18 @@ export class Vail { if (!this.wantConnected) { return } + this.rx(0, 0, {connected: false}) console.info("Attempting to reconnect", this.wsUrl.href) this.clockOffset = 0 this.socket = new WebSocket(this.wsUrl, ["json.vail.woozle.org"]) this.socket.addEventListener("message", e => this.wsMessage(e)) + this.socket.addEventListener( + "open", + msg => { + this.connected = true + this.rx(0, 0, {connected: true}) + } + ) this.socket.addEventListener( "close", msg => { @@ -71,6 +80,7 @@ export class Vail { averageLag: this.lagDurations.reduce((a,b) => (a+b), 0) / this.lagDurations.length, clockOffset: this.clockOffset, clients: msg.Clients, + connected: this.connected, } console.log(msg) if (typeof(msg) == "string") { @@ -152,13 +162,14 @@ export class Vail { } export class Null { - constructor(rx) { + constructor(rx, interval=3*Second) { this.rx = rx - this.interval = setInterval(() => this.pulse(), 3 * Second) + this.interval = setInterval(() => this.pulse(), interval) + this.pulse() } pulse() { - this.rx(0, 0, {note: "local"}) + this.rx(0, 0, {note: "local", connected: false}) } Transmit(time, duration, squelch=true) { @@ -169,51 +180,41 @@ export class Null { } } -export class Echo { +export class Echo extends Null { constructor(rx, delay=0) { - this.rx = rx + super(rx) this.delay = delay - this.Transmit(0, 0) } Transmit(time, duration, squelch=true) { this.rx(time + this.delay, duration, {note: "local"}) } - - Close() { - } } -export class Fortune { +export class Fortune extends Null { /** * * @param rx Receive callback * @param {Keyer} keyer Keyer object */ constructor(rx, keyer) { - this.rx = rx + super(rx, 1*Minute) this.keyer = keyer - - this.interval = setInterval(() => this.pulse(), 1 * Minute) this.pulse() } pulse() { - this.rx(0, 0, {note: "local"}) - if (this.keyer.Busy()) { + super.pulse() + if (!this.keyer || this.keyer.Busy()) { return } let fortune = GetFortune() - this.keyer.EnqueueAsciiString(`${fortune}\x04 `) - } - - Transmit(time, duration, squelch=true) { - // Do nothing. + this.keyer.EnqueueAsciiString(`${fortune} \x04 `) } Close() { this.keyer.Flush() - clearInterval(this.interval) + super.Close() } } \ No newline at end of file diff --git a/static/vail.css b/static/vail.css index f35723b..1d81081 100644 --- a/static/vail.css +++ b/static/vail.css @@ -16,7 +16,15 @@ -webkit-user-select: none; /* 2022-04-26 Safari still needs this */ } -.recv-lamp.rx { +.tag.recv-lamp { + background-color: #444; + color: white; +} +.tag.recv-lamp.connected { + background-color: #fec; +} +.tag.recv-lamp.rx, +.tag.recv-lamp.connected.rx { background-color: orange; } diff --git a/static/vail.mjs b/static/vail.mjs index 508ed80..938b7da 100644 --- a/static/vail.mjs +++ b/static/vail.mjs @@ -375,6 +375,9 @@ class VailClient { let longestRxDuration = this.rxDurations.reduce((a,b) => Math.max(a,b)) let suggestedDelay = ((averageLag + longestRxDuration) * 1.2).toFixed(0) + if (stats.connected !== undefined) { + this.outputs.SetConnected(stats.connected) + } this.updateReading("#note", stats.note || "☁") this.updateReading("#lag-value", averageLag) this.updateReading("#longest-rx-value", longestRxDuration)