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 { addInput, setStatus, addOutput } from "./scrollback.js"
import { send } from "./websocket.js" import { send } from "./websocket.js"
import { randomID } from "../shared/utils.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) { export function runCommand(input: string) {
const id = randomID() const id = randomID()
@ -15,6 +17,16 @@ export function runCommand(input: string) {
// message received from server // message received from server
export function handleMessage(e: MessageEvent) { export function handleMessage(e: MessageEvent) {
const data = JSON.parse(e.data) const data = JSON.parse(e.data)
addOutput(data.id, data.data) console.log("-> receive", data)
setStatus(data.id, "ok") 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. // 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 { sessionID } from "./session.js"
import { handleMessage } from "./shell.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 { transpile, isFile, tilde } from "./utils"
import { apps, serveApp, publishDNS } from "./webapp" import { apps, serveApp, publishDNS } from "./webapp"
import { runCommand } from "./shell" import { runCommand } from "./shell"
import type { Message } from "./shared/message" import type { Message } from "./shared/types"
import { Layout } from "./components/layout" import { Layout } from "./components/layout"
import { Terminal } from "./components/terminal" import { Terminal } from "./components/terminal"
@ -52,22 +52,28 @@ app.on("GET", ["/js/:path{.+}", "/shared/:path{.+}"], async c => {
// websocket // websocket
// //
const connections: any[] = []
app.get("/ws", upgradeWebSocket((c) => { app.get("/ws", upgradeWebSocket((c) => {
return { return {
onOpen(_e, ws) {
connections.push(ws)
},
onMessage(event, ws) { onMessage(event, ws) {
console.log(`Message from client: ${event.data}`)
let data: Message | undefined let data: Message | undefined
try { try {
data = JSON.parse(event.data.toString()) data = JSON.parse(event.data.toString())
} catch (e) { } catch (e) {
console.error("JSON parsing error", e) console.error("JSON parsing error", e)
ws.send(JSON.stringify({ type: "error", data: "json parsing error" }))
return
} }
if (!data) return if (!data) return
const result = runCommand(data.data) const result = runCommand(data.data as string)
ws.send(JSON.stringify({ id: data.id, data: result })) ws.send(JSON.stringify({ id: data.id, type: "output", data: result }))
}, },
onClose: () => console.log('Connection closed'), onClose: () => console.log('Connection closed'),
} }
@ -119,6 +125,7 @@ if (process.env.BUN_HOT) {
// @ts-ignore // @ts-ignore
globalThis.__hot_reload_cleanup = () => { globalThis.__hot_reload_cleanup = () => {
connections.forEach(conn => conn?.close())
} }
for (const sig of ["SIGINT", "SIGTERM"] as const) { 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. // runs commands and such.
type CommandResult = { import type { CommandResult } from "./shared/types"
type: "ok" | "error"
data: any
}
export function runCommand(input: string): CommandResult { export function runCommand(input: string): CommandResult {
return { type: "ok", data: "command: " + input } return { status: "ok", output: "command: " + input }
} }