This commit is contained in:
Chris Wanstrath 2025-09-20 18:32:22 -07:00
parent 3ff1b9f3fa
commit d66b3f9f5f
6 changed files with 39 additions and 18 deletions

View File

@ -4,6 +4,8 @@
import { addInput, setStatus, addOutput } from "./scrollback.js"
import { send } from "./websocket.js"
import { randomID } from "../shared/utils.js"
import type { Message, CommandResult } from "../shared/types.js"
import type { CompoundAssignmentOperator } from "typescript"
export function runCommand(input: string) {
const id = randomID()
@ -15,6 +17,16 @@ export function runCommand(input: string) {
// message received from server
export function handleMessage(e: MessageEvent) {
const data = JSON.parse(e.data)
addOutput(data.id, data.data)
setStatus(data.id, "ok")
console.log("-> receive", data)
if (data.type === "output") {
handleOutput(data)
} else {
console.error("unknown message type", data)
}
}
function handleOutput(msg: Message) {
const result = msg.data as CommandResult
setStatus(msg.id, result.status)
addOutput(msg.id, result.output)
}

View File

@ -1,7 +1,7 @@
////
// The terminal communicates with the shell via websockets.
import type { Message } from "../shared/message.js"
import type { Message } from "../shared/types.js"
import { sessionID } from "./session.js"
import { handleMessage } from "./shell.js"

View File

@ -7,7 +7,7 @@ import { NOSE_ICON, NOSE_DIR, NOSE_BIN, NOSE_WWW } from "./config"
import { transpile, isFile, tilde } from "./utils"
import { apps, serveApp, publishDNS } from "./webapp"
import { runCommand } from "./shell"
import type { Message } from "./shared/message"
import type { Message } from "./shared/types"
import { Layout } from "./components/layout"
import { Terminal } from "./components/terminal"
@ -52,22 +52,28 @@ app.on("GET", ["/js/:path{.+}", "/shared/:path{.+}"], async c => {
// websocket
//
const connections: any[] = []
app.get("/ws", upgradeWebSocket((c) => {
return {
onOpen(_e, ws) {
connections.push(ws)
},
onMessage(event, ws) {
console.log(`Message from client: ${event.data}`)
let data: Message | undefined
try {
data = JSON.parse(event.data.toString())
} catch (e) {
console.error("JSON parsing error", e)
ws.send(JSON.stringify({ type: "error", data: "json parsing error" }))
return
}
if (!data) return
const result = runCommand(data.data)
ws.send(JSON.stringify({ id: data.id, data: result }))
const result = runCommand(data.data as string)
ws.send(JSON.stringify({ id: data.id, type: "output", data: result }))
},
onClose: () => console.log('Connection closed'),
}
@ -119,6 +125,7 @@ if (process.env.BUN_HOT) {
// @ts-ignore
globalThis.__hot_reload_cleanup = () => {
connections.forEach(conn => conn?.close())
}
for (const sig of ["SIGINT", "SIGTERM"] as const) {

View File

@ -1,6 +0,0 @@
export type Message = {
session?: string
id: string
type: "input" | "output"
data: any
}

11
src/shared/types.ts Normal file
View File

@ -0,0 +1,11 @@
export type Message = {
session?: string
id: string
type: "input" | "output"
data: string | CommandResult
}
export type CommandResult = {
status: "ok" | "error"
output: string
}

View File

@ -1,11 +1,8 @@
////
// runs commands and such.
type CommandResult = {
type: "ok" | "error"
data: any
}
import type { CommandResult } from "./shared/types"
export function runCommand(input: string): CommandResult {
return { type: "ok", data: "command: " + input }
return { status: "ok", output: "command: " + input }
}