diff options
Diffstat (limited to 'packages/bun-debug-adapter-protocol/src/debugger/signal.ts')
-rw-r--r-- | packages/bun-debug-adapter-protocol/src/debugger/signal.ts | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/packages/bun-debug-adapter-protocol/src/debugger/signal.ts b/packages/bun-debug-adapter-protocol/src/debugger/signal.ts new file mode 100644 index 000000000..2a1b05938 --- /dev/null +++ b/packages/bun-debug-adapter-protocol/src/debugger/signal.ts @@ -0,0 +1,87 @@ +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import type { Server } from "node:net"; +import { createServer } from "node:net"; +import { EventEmitter } from "node:events"; + +const isDebug = process.env.NODE_ENV === "development"; + +export type UnixSignalEventMap = { + "Signal.listening": [string]; + "Signal.error": [Error]; + "Signal.received": [string]; + "Signal.closed": []; +}; + +/** + * Starts a server that listens for signals on a UNIX domain socket. + */ +export class UnixSignal extends EventEmitter<UnixSignalEventMap> { + #path: string; + #server: Server; + #ready: Promise<void>; + + constructor(path?: string) { + super(); + this.#path = path ? parseUnixPath(path) : randomUnixPath(); + this.#server = createServer(); + this.#server.on("listening", () => this.emit("Signal.listening", this.#path)); + this.#server.on("error", error => this.emit("Signal.error", error)); + this.#server.on("close", () => this.emit("Signal.closed")); + this.#server.on("connection", socket => { + socket.on("data", data => { + this.emit("Signal.received", data.toString()); + }); + }); + this.#ready = new Promise((resolve, reject) => { + this.#server.on("listening", resolve); + this.#server.on("error", reject); + }); + this.#server.listen(this.#path); + } + + emit<E extends keyof UnixSignalEventMap>(event: E, ...args: UnixSignalEventMap[E]): boolean { + if (isDebug) { + console.log(event, ...args); + } + + return super.emit(event, ...args); + } + + /** + * The path to the UNIX domain socket. + */ + get url(): string { + return `unix://${this.#path}`; + } + + /** + * Resolves when the server is listening or rejects if an error occurs. + */ + get ready(): Promise<void> { + return this.#ready; + } + + /** + * Closes the server. + */ + close(): void { + this.#server.close(); + } +} + +function randomUnixPath(): string { + return join(tmpdir(), `${Math.random().toString(36).slice(2)}.sock`); +} + +function parseUnixPath(path: string): string { + if (path.startsWith("/")) { + return path; + } + try { + const { pathname } = new URL(path); + return pathname; + } catch { + throw new Error(`Invalid UNIX path: ${path}`); + } +} |