nose-pluto/src/js/websocket.ts

69 lines
1.7 KiB
TypeScript

////
// The terminal communicates with the shell via websockets.
import type { Message } from "../shared/types"
import { sessionId } from "./session"
import { dispatchMessage } from "./dispatch"
import { addErrorMessage } from "./scrollback"
const MAX_RETRIES = 5
let retries = 0
let connected = false
let msgQueue: Omit<Message, "session">[] = []
let ws: WebSocket | null = null
// open our websocket connection
export function startConnection() {
const url = new URL(`/ws?session=${sessionId}`, location.href)
url.protocol = url.protocol.replace('http', 'ws')
ws = new WebSocket(url)
ws.onmessage = receive
ws.onclose = retryConnection
ws.onerror = () => ws?.close()
ws.onopen = () => {
connected = true
msgQueue.forEach(msg => send(msg))
msgQueue.length = 0
}
}
// send any message
export function send(msg: Omit<Message, "session">) {
if (!connected) {
msgQueue.push(msg)
startConnection()
return
}
if (!(msg as any).session) (msg as any).session = sessionId
ws?.readyState === 1 && ws.send(JSON.stringify(msg))
console.log("-> send", msg)
}
async function receive(e: MessageEvent) {
const data = JSON.parse(e.data) as Message
console.log("<- receive", data)
await dispatchMessage(data)
}
// close it... plz don't do this, though
export function close() {
ws?.close(1000, 'bye')
}
function retryConnection() {
connected = false
if (retries >= MAX_RETRIES) {
addErrorMessage(`Failed to reconnect ${retries} times. Server is down.`)
if (ws) ws.onclose = () => { }
return
}
retries++
addErrorMessage(`Connection lost. Retrying...`)
setTimeout(startConnection, 2000)
}