69 lines
1.7 KiB
TypeScript
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)
|
|
}
|