Make the relay acknowledge all received commands
To that effect, bump liberty and the xC relay protocol version. Relay events have been reordered to improve forward compatibility. Also prevent use-after-free when serialization fails. xP now slightly throttles activity notifications, and indicates when there are unacknowledged commands.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022 - 2024, Přemysl Eric Janouch <p@janouch.name>
|
||||
// Copyright (c) 2022 - 2025, Přemysl Eric Janouch <p@janouch.name>
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
import * as Relay from './proto.js'
|
||||
|
||||
@@ -67,18 +67,19 @@ class RelayRPC extends EventTarget {
|
||||
|
||||
_processOne(message) {
|
||||
let e = message.data
|
||||
let p
|
||||
switch (e.event) {
|
||||
case Relay.Event.Error:
|
||||
if (this.promised[e.commandSeq] !== undefined)
|
||||
this.promised[e.commandSeq].reject(e.error)
|
||||
else
|
||||
if ((p = this.promised[e.commandSeq]) === undefined)
|
||||
console.error(`Unawaited error: ${e.error}`)
|
||||
else if (p !== true)
|
||||
p.reject(e.error)
|
||||
break
|
||||
case Relay.Event.Response:
|
||||
if (this.promised[e.commandSeq] !== undefined)
|
||||
this.promised[e.commandSeq].resolve(e.data)
|
||||
else
|
||||
if ((p = this.promised[e.commandSeq]) === undefined)
|
||||
console.error("Unawaited response")
|
||||
else if (p !== true)
|
||||
p.resolve(e.data)
|
||||
break
|
||||
default:
|
||||
e.eventSeq = message.eventSeq
|
||||
@@ -95,6 +96,13 @@ class RelayRPC extends EventTarget {
|
||||
this.promised[seq].reject("No response")
|
||||
delete this.promised[seq]
|
||||
}
|
||||
m.redraw()
|
||||
}
|
||||
|
||||
get busy() {
|
||||
for (const seq in this.promised)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
send(params) {
|
||||
@@ -110,6 +118,9 @@ class RelayRPC extends EventTarget {
|
||||
|
||||
this.ws.send(JSON.stringify({commandSeq: seq, data: params}))
|
||||
|
||||
this.promised[seq] = true
|
||||
m.redraw()
|
||||
|
||||
// Automagically detect if we want a result.
|
||||
let data = undefined
|
||||
const promise = new Promise(
|
||||
@@ -191,6 +202,17 @@ let bufferAutoscroll = true
|
||||
|
||||
let servers = new Map()
|
||||
|
||||
let lastActive = undefined
|
||||
|
||||
function notifyActive() {
|
||||
// Reduce unnecessary traffic.
|
||||
const now = Date.now()
|
||||
if (lastActive === undefined || (now - lastActive >= 5000)) {
|
||||
lastActive = now
|
||||
rpc.send({command: 'Active'})
|
||||
}
|
||||
}
|
||||
|
||||
function bufferResetStats(b) {
|
||||
b.newMessages = 0
|
||||
b.newUnimportantMessages = 0
|
||||
@@ -998,7 +1020,7 @@ let Input = {
|
||||
|
||||
onKeyDown: event => {
|
||||
// TODO: And perhaps on other actions, too.
|
||||
rpc.send({command: 'Active'})
|
||||
notifyActive()
|
||||
|
||||
let b = buffers.get(bufferCurrent)
|
||||
if (b === undefined || event.isComposing)
|
||||
@@ -1103,7 +1125,13 @@ let Main = {
|
||||
|
||||
return m('.xP', {}, [
|
||||
overlay,
|
||||
m('.title', {}, [m('b', {}, `xP`), m(Topic)]),
|
||||
m('.title', {}, [
|
||||
m('span', [
|
||||
rpc.busy ? '⋯ ' : undefined,
|
||||
m('b', {}, `xP`),
|
||||
]),
|
||||
m(Topic),
|
||||
]),
|
||||
m('.middle', {}, [m(BufferList), m(BufferContainer)]),
|
||||
m(Status),
|
||||
m('.input', {}, [m(Prompt), m(Input)]),
|
||||
|
||||
Reference in New Issue
Block a user