Skip to content

Commit 8c484a0

Browse files
committed
fix(app): terminal issues
1 parent a0b3bbf commit 8c484a0

1 file changed

Lines changed: 19 additions & 85 deletions

File tree

packages/opencode/src/pty/index.ts

Lines changed: 19 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -23,60 +23,6 @@ export namespace Pty {
2323
close: (code?: number, reason?: string) => void
2424
}
2525

26-
type Subscriber = {
27-
id: number
28-
token: unknown
29-
}
30-
31-
const sockets = new WeakMap<object, number>()
32-
const owners = new WeakMap<object, string>()
33-
let socketCounter = 0
34-
35-
const tagSocket = (ws: Socket) => {
36-
if (!ws || typeof ws !== "object") return
37-
const next = (socketCounter = (socketCounter + 1) % Number.MAX_SAFE_INTEGER)
38-
sockets.set(ws, next)
39-
return next
40-
}
41-
42-
const token = (ws: Socket) => {
43-
const data = ws.data
44-
if (data === undefined) return
45-
if (data === null) return
46-
if (typeof data !== "object") return data
47-
48-
const id = (data as { connId?: unknown }).connId
49-
if (typeof id === "number" || typeof id === "string") return id
50-
51-
const href = (data as { href?: unknown }).href
52-
if (typeof href === "string") return href
53-
54-
const url = (data as { url?: unknown }).url
55-
if (typeof url === "string") return url
56-
if (url && typeof url === "object") {
57-
const href = (url as { href?: unknown }).href
58-
if (typeof href === "string") return href
59-
return url
60-
}
61-
62-
const events = (data as { events?: unknown }).events
63-
if (typeof events === "number" || typeof events === "string") return events
64-
if (events && typeof events === "object") {
65-
const id = (events as { connId?: unknown }).connId
66-
if (typeof id === "number" || typeof id === "string") return id
67-
68-
const id2 = (events as { connection?: unknown }).connection
69-
if (typeof id2 === "number" || typeof id2 === "string") return id2
70-
71-
const id3 = (events as { id?: unknown }).id
72-
if (typeof id3 === "number" || typeof id3 === "string") return id3
73-
74-
return events
75-
}
76-
77-
return data
78-
}
79-
8026
// WebSocket control frame: 0x00 + UTF-8 JSON.
8127
const meta = (cursor: number) => {
8228
const json = JSON.stringify({ cursor })
@@ -141,7 +87,7 @@ export namespace Pty {
14187
buffer: string
14288
bufferCursor: number
14389
cursor: number
144-
subscribers: Map<Socket, Subscriber>
90+
subscribers: Map<unknown, Socket>
14591
}
14692

14793
const state = Instance.state(
@@ -151,9 +97,9 @@ export namespace Pty {
15197
try {
15298
session.process.kill()
15399
} catch {}
154-
for (const ws of session.subscribers.keys()) {
100+
for (const [key, ws] of session.subscribers.entries()) {
155101
try {
156-
ws.close()
102+
if (ws.data === key) ws.close()
157103
} catch {
158104
// ignore
159105
}
@@ -224,26 +170,21 @@ export namespace Pty {
224170
ptyProcess.onData((chunk) => {
225171
session.cursor += chunk.length
226172

227-
for (const [ws, sub] of session.subscribers) {
173+
for (const [key, ws] of session.subscribers.entries()) {
228174
if (ws.readyState !== 1) {
229-
session.subscribers.delete(ws)
230-
continue
231-
}
232-
233-
if (typeof ws === "object" && sockets.get(ws) !== sub.id) {
234-
session.subscribers.delete(ws)
175+
session.subscribers.delete(key)
235176
continue
236177
}
237178

238-
if (token(ws) !== sub.token) {
239-
session.subscribers.delete(ws)
179+
if (ws.data !== key) {
180+
session.subscribers.delete(key)
240181
continue
241182
}
242183

243184
try {
244185
ws.send(chunk)
245186
} catch {
246-
session.subscribers.delete(ws)
187+
session.subscribers.delete(key)
247188
}
248189
}
249190

@@ -256,9 +197,9 @@ export namespace Pty {
256197
ptyProcess.onExit(({ exitCode }) => {
257198
log.info("session exited", { id, exitCode })
258199
session.info.status = "exited"
259-
for (const ws of session.subscribers.keys()) {
200+
for (const [key, ws] of session.subscribers.entries()) {
260201
try {
261-
ws.close()
202+
if (ws.data === key) ws.close()
262203
} catch {
263204
// ignore
264205
}
@@ -291,9 +232,9 @@ export namespace Pty {
291232
try {
292233
session.process.kill()
293234
} catch {}
294-
for (const ws of session.subscribers.keys()) {
235+
for (const [key, ws] of session.subscribers.entries()) {
295236
try {
296-
ws.close()
237+
if (ws.data === key) ws.close()
297238
} catch {
298239
// ignore
299240
}
@@ -325,23 +266,16 @@ export namespace Pty {
325266
}
326267
log.info("client connected to session", { id })
327268

328-
const socketId = tagSocket(ws)
329-
if (socketId === undefined) {
330-
ws.close()
331-
return
332-
}
333-
334-
const previous = owners.get(ws)
335-
if (previous && previous !== id) {
336-
state().get(previous)?.subscribers.delete(ws)
337-
}
269+
// Use ws.data as the unique key for this connection lifecycle.
270+
// If ws.data is undefined, fallback to ws object.
271+
const connectionKey = ws.data && typeof ws.data === "object" ? ws.data : ws
338272

339-
owners.set(ws, id)
340-
session.subscribers.set(ws, { id: socketId, token: token(ws) })
273+
// Optionally cleanup if the key somehow exists
274+
session.subscribers.delete(connectionKey)
275+
session.subscribers.set(connectionKey, ws)
341276

342277
const cleanup = () => {
343-
session.subscribers.delete(ws)
344-
if (owners.get(ws) === id) owners.delete(ws)
278+
session.subscribers.delete(connectionKey)
345279
}
346280

347281
const start = session.bufferCursor

0 commit comments

Comments
 (0)