Skip to content

Commit 6e9078d

Browse files
parzivailsmokku
authored andcommitted
Support attaching to remote DAP server using websockets
1 parent d725713 commit 6e9078d

File tree

4 files changed

+87
-21
lines changed

4 files changed

+87
-21
lines changed

package.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@
4747
"vscode:prepublish": "rimraf dist && npm run -S esbuild-base -- --minify && npm run -S esbuild-web -- --minify",
4848
"test": "npm run check && npm run typecheck"
4949
},
50+
"dependencies": {
51+
"ws": "^8.18.2"
52+
},
5053
"devDependencies": {
5154
"@biomejs/biome": "^1.9.4",
5255
"@types/node": "22.x",
5356
"@types/vscode": "^1.99.0",
57+
"@types/ws": "^8.18.1",
5458
"@vscode/debugadapter": "^1.68.0",
5559
"@vscode/vsce": "^3.3.2",
5660
"esbuild": "^0.25.3",
@@ -178,22 +182,17 @@
178182
}
179183
},
180184
"attach": {
181-
"required": ["program", "port"],
185+
"required": ["program", "address"],
182186
"properties": {
183187
"program": {
184188
"type": "string",
185189
"format": "uri-reference",
186190
"description": "Path of program to be debugged (debugee)."
187191
},
188-
"port": {
189-
"type": "number",
190-
"description": "TCP port to attach to."
191-
},
192-
"host": {
192+
"address": {
193193
"type": "string",
194-
"format": "uri-reference",
195-
"description": "TCP host to attach to.",
196-
"default": true
194+
"format": "uri",
195+
"description": "Remote address to attach to."
197196
},
198197
"trace": {
199198
"type": "boolean",

sampleWorkspace/.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"request": "attach",
2121
"name": "Attach running",
2222
"program": "hello_world.bin",
23-
"port": 4567,
23+
"address": "ws://localhost:4567/debug/",
2424
"trace": true
2525
}
2626
]

src/cc65Debug.ts

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import * as path from "node:path";
1616
import { Logger, LoggingDebugSession, TerminatedEvent, logger } from "@vscode/debugadapter";
1717
import type { DebugProtocol } from "@vscode/debugprotocol";
1818
import type { DebugSession } from "vscode";
19+
import { WebSocket } from "ws";
1920
import {
2021
type DbgFile,
2122
type DbgMap,
@@ -77,7 +78,7 @@ export class Cc65DebugSession extends LoggingDebugSession {
7778

7879
private _program: ChildProcessWithoutNullStreams | undefined;
7980

80-
/// connected over TCP port?
81+
private _websocket: WebSocket | undefined;
8182
private _connected = false;
8283

8384
private _debugData: DbgMap | undefined;
@@ -155,7 +156,8 @@ export class Cc65DebugSession extends LoggingDebugSession {
155156

156157
const header = `Content-Length: ${contentLength}\r\n\r\n`;
157158

158-
this._program?.stdin.write(header + json, "utf8");
159+
if (this._program) this._program?.stdin.write(header + json, "utf8");
160+
if (this._websocket) this._websocket?.send(header + json);
159161
}
160162

161163
public sendResponse(response: DebugProtocol.Response): void {
@@ -514,8 +516,52 @@ export class Cc65DebugSession extends LoggingDebugSession {
514516
/**
515517
* Attempts to connect to an existing debugger adapter.
516518
*/
517-
protected connectAdapter(port: number, host: string): Promise<void> {
518-
throw new Error("Connecting to existing debugger not supported yet.");
519+
protected connectAdapter(address: string | URL): Promise<void> {
520+
console.debug("connectAdapter", address);
521+
522+
const addr = typeof address === "string" ? new URL(address) : address;
523+
524+
if (["ws:", "wss:"].includes(addr.protocol)) {
525+
return new Promise((resolve, reject) => {
526+
const ws = new WebSocket(addr);
527+
528+
ws.addEventListener("open", (event) => {
529+
console.log(`WebSocket connection established to ${addr}`);
530+
logger.log(`WebSocket connection established to ${addr}`);
531+
this._websocket = ws;
532+
this._connected = true;
533+
resolve();
534+
});
535+
536+
ws.addEventListener("message", (event) => {
537+
if (typeof event.data === "string" || event.data instanceof String) {
538+
this._processData(Buffer.from(String(event.data), "utf-8"));
539+
} else {
540+
console.warn("Received non-text websocket data, ignoring.");
541+
logger.warn("Received non-text websocket data, ignoring.");
542+
}
543+
});
544+
545+
ws.addEventListener("error", (error) => {
546+
console.error(`WebSocket error: ${error}`);
547+
logger.error(`WebSocket error: ${error}`);
548+
reject(error.message);
549+
});
550+
551+
ws.addEventListener("close", (event) => {
552+
console.log(
553+
`WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason}`,
554+
);
555+
logger.log(
556+
`WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason}`,
557+
);
558+
});
559+
});
560+
}
561+
562+
throw new Error(
563+
`Unsupported connection protocol: ${addr.protocol}. Only 'ws:' and 'wss:' are supported`,
564+
);
519565
}
520566

521567
/**
@@ -553,9 +599,9 @@ export class Cc65DebugSession extends LoggingDebugSession {
553599

554600
case "attach":
555601
{
556-
const { port, host = "localhost" } = this._session.configuration;
602+
const { address } = this._session.configuration;
557603
try {
558-
await this.connectAdapter(port, host);
604+
await this.connectAdapter(address);
559605
} catch (error) {
560606
return this.sendErrorResponse(response, {
561607
id: ErrorCodes.DAP_CONNECT_ERROR,
@@ -591,11 +637,13 @@ export class Cc65DebugSession extends LoggingDebugSession {
591637
request?: DebugProtocol.Request,
592638
) {
593639
console.log("attachRequest", args);
594-
return this.sendErrorResponse(response, {
595-
id: ErrorCodes.DAP_NOT_SUPPORTED,
596-
format: "Attaching to TCP port is not yet supported.",
597-
showUser: true,
598-
});
640+
641+
if (!this._connected)
642+
return this.sendErrorResponse(response, {
643+
id: ErrorCodes.DAP_CONNECT_ERROR,
644+
format: "Connection to the debug server was not established",
645+
showUser: true,
646+
});
599647
}
600648

601649
protected disconnectRequest(

yarn.lock

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,13 @@
299299
wrap-ansi "^8.1.0"
300300
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
301301

302+
"@types/node@*":
303+
version "22.15.18"
304+
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.18.tgz#2f8240f7e932f571c2d45f555ba0b6c3f7a75963"
305+
integrity sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==
306+
dependencies:
307+
undici-types "~6.21.0"
308+
302309
"@types/node@22.x":
303310
version "22.15.3"
304311
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.3.tgz#b7fb9396a8ec5b5dfb1345d8ac2502060e9af68b"
@@ -311,6 +318,13 @@
311318
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.99.1.tgz#bde6e2d9ccbe0493fded98ad639bf2671b8ec9ee"
312319
integrity sha512-cQlqxHZ040ta6ovZXnXRxs3fJiTmlurkIWOfZVcLSZPcm9J4ikFpXuB7gihofGn5ng+kDVma5EmJIclfk0trPQ==
313320

321+
"@types/ws@^8.18.1":
322+
version "8.18.1"
323+
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9"
324+
integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==
325+
dependencies:
326+
"@types/node" "*"
327+
314328
"@vscode/debugadapter@^1.68.0":
315329
version "1.68.0"
316330
resolved "https://registry.yarnpkg.com/@vscode/debugadapter/-/debugadapter-1.68.0.tgz#abb23463cb750ca4a6f0834c5d4db659258dc159"
@@ -1867,6 +1881,11 @@ wrappy@1:
18671881
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
18681882
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
18691883

1884+
ws@^8.18.2:
1885+
version "8.18.2"
1886+
resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a"
1887+
integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==
1888+
18701889
xml2js@^0.5.0:
18711890
version "0.5.0"
18721891
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7"

0 commit comments

Comments
 (0)