diff --git a/http_server_bun.test.ts b/http_server_bun.test.ts index baa82cd..e1316f9 100644 --- a/http_server_bun.test.ts +++ b/http_server_bun.test.ts @@ -125,3 +125,29 @@ Deno.test({ teardown(); }, }); + +Deno.test({ + name: "bun server closes on abort signal", + // this is working but there is some sort of hanging promise somewhere I can't + // narrow down at the moment + ignore: true, + async fn() { + setup([new Request(new URL("http://localhost:8080/"))]); + const controller = new AbortController(); + const { signal } = controller; + const server = new Server(createMockApp(), { port: 8080, signal }); + const listener = await server.listen(); + assertEquals(listener, { addr: { hostname: "localhost", port: 8080 } }); + assert(currentServer); + for await (const req of server) { + assert(!req.body); + assertEquals(req.url, "/"); + await req.respond(new Response("hello world")); + } + controller.abort(); + await currentServer.runPromise; + assertEquals(currentServer.stoppedCount, 1); + assertEquals(currentServer.responses.length, 1); + teardown(); + }, +}); diff --git a/http_server_bun.ts b/http_server_bun.ts index e11c68c..91c8843 100644 --- a/http_server_bun.ts +++ b/http_server_bun.ts @@ -166,13 +166,13 @@ class BunRequest implements ServerRequest { /** An implementation of the oak server abstraction for handling requests on * Bun using the built in Bun http server. */ export class Server implements OakServer { - #options: Omit; + #options: ServeOptions | ServeTlsOptions; #server?: BunServer; #stream?: ReadableStream; constructor( _app: Application, - options: Omit, + options: ServeOptions | ServeTlsOptions, ) { this.#options = options; } @@ -187,7 +187,7 @@ export class Server implements OakServer { if (this.#server) { throw new Error("Server already listening."); } - const { onListen, hostname, port } = this.#options; + const { onListen, hostname, port, signal } = this.#options; const tls = isServeTlsOptions(this.#options) ? { key: this.#options.key, cert: this.#options.cert } : undefined; @@ -204,6 +204,10 @@ export class Server implements OakServer { port, tls, }); + signal?.addEventListener("abort", () => { + controller.close(); + this.close(); + }, { once: true }); { const { hostname, port } = this.#server; if (onListen) { diff --git a/http_server_node.ts b/http_server_node.ts index 08fe934..e2b5248 100644 --- a/http_server_node.ts +++ b/http_server_node.ts @@ -6,7 +6,13 @@ * @module */ -import type { Listener, OakServer, ServerRequest } from "./types.ts"; +import type { + Listener, + OakServer, + ServeOptions, + ServerRequest, + ServeTlsOptions, +} from "./types.ts"; import { createPromiseWithResolvers } from "./utils/create_promise_with_resolvers.ts"; // There are quite a few differences between Deno's `std/node/http` and the @@ -155,10 +161,13 @@ export class Server implements OakServer { constructor( _app: unknown, - options: Deno.ListenOptions | Deno.ListenTlsOptions, + options: ServeOptions | ServeTlsOptions, ) { this.#host = options.hostname ?? "127.0.0.1"; - this.#port = options.port; + this.#port = options.port ?? 80; + options.signal?.addEventListener("abort", () => { + this.close(); + }, { once: true }); } close(): void { @@ -169,11 +178,16 @@ export class Server implements OakServer { const { createServer } = await import("node:http"); let server: NodeHttpServer; this.#requestStream = new ReadableStream({ - start(controller) { + start: (controller) => { server = createServer((req, res) => { // deno-lint-ignore no-explicit-any controller.enqueue(new NodeRequest(req as any, res as any)); }); + this.#abortController.signal.addEventListener( + "abort", + () => controller.close(), + { once: true }, + ); }, }); server!.listen({