aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-debug-adapter-protocol/src/debugger/signal.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/bun-debug-adapter-protocol/src/debugger/signal.ts')
-rw-r--r--packages/bun-debug-adapter-protocol/src/debugger/signal.ts87
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}`);
+ }
+}