Skip to content

Commit

Permalink
Add "listen" event for Application.
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk committed May 27, 2020
1 parent 094916b commit 71f25d7
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 47 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,36 @@ otherwise it will be set to `text/plain`. If the value is an object, other
than a `Uint8Array` or `null`, the object will be passed to `JSON.stringify()`
and the `Content-Type` will be set to `application/json`.

### Opening the server

The application method `.listen()` is used to open the server, start listening
for requests, and processing the registered middleware for each request. This
method returns a promise when the server closes.

Once the server is open, before it starts processing requests, the application
will fire a `"listen"` event, which can be listened for via the
`.addEventListener()` method. For example:

```ts
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.addEventListener("listen", ({ hostname, port, secure }) => {
console.log(
`Listening on: ${secure ? "https://" : "http://"}${
hostname ?? "localhost"
}:${port}`
);
});
// register some middleware
await app.listen({ port: 80 });
```

To start u

### Closing the server

If you want to close the application, the application supports the option of
Expand Down
53 changes: 45 additions & 8 deletions application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,32 @@ interface ApplicationErrorEventListenerObject<S> {
handleEvent(evt: ApplicationErrorEvent<S>): void | Promise<void>;
}

export interface ApplicationErrorEventInit<S extends State>
extends ErrorEventInit {
interface ApplicationErrorEventInit<S extends State> extends ErrorEventInit {
context?: Context<S>;
}

type ApplicationErrorEventListenerOrEventListenerObject<S> =
| ApplicationErrorEventListener<S>
| ApplicationErrorEventListenerObject<S>;

interface ApplicationListenEventListener {
(evt: ApplicationListenEvent): void | Promise<void>;
}

interface ApplicationListenEventListenerObject {
handleEvent(evt: ApplicationListenEvent): void | Promise<void>;
}

interface ApplicationListenEventInit extends EventInit {
hostname?: string;
port: number;
secure: boolean;
}

type ApplicationListenEventListenerOrEventListenerObject =
| ApplicationListenEventListener
| ApplicationListenEventListenerObject;

export interface ApplicationOptions<S> {
/** An initial set of keys (or instance of `KeyGrip`) to be used for signing
* cookies produced by the application. */
Expand Down Expand Up @@ -78,12 +95,25 @@ const ADDR_REGEXP = /^\[?([^\]]*)\]?:([0-9]{1,5})$/;
export class ApplicationErrorEvent<S extends State> extends ErrorEvent {
context?: Context<S>;

constructor(type: string, eventInitDict: ApplicationErrorEventInit<S>) {
super(type, eventInitDict);
constructor(eventInitDict: ApplicationErrorEventInit<S>) {
super("error", eventInitDict);
this.context = eventInitDict.context;
}
}

export class ApplicationListenEvent extends Event {
hostname?: string;
port: number;
secure: boolean;

constructor(eventInitDict: ApplicationListenEventInit) {
super("listen", eventInitDict);
this.hostname = eventInitDict.hostname;
this.port = eventInitDict.port;
this.secure = eventInitDict.secure;
}
}

/** A class which registers middleware (via `.use()`) and then processes
* inbound requests against that middleware (via `.listen()`).
*
Expand Down Expand Up @@ -149,9 +179,7 @@ export class Application<AS extends State = Record<string, any>>
error = new Error(`non-error thrown: ${JSON.stringify(error)}`);
}
const { message } = error;
this.dispatchEvent(
new ApplicationErrorEvent("error", { context, message, error }),
);
this.dispatchEvent(new ApplicationErrorEvent({ context, message, error }));
if (!context.response.writable) {
return;
}
Expand Down Expand Up @@ -210,6 +238,11 @@ export class Application<AS extends State = Record<string, any>>
listener: ApplicationErrorEventListenerOrEventListenerObject<AS> | null,
options?: boolean | AddEventListenerOptions,
): void;
addEventListener(
type: "listen",
listener: ApplicationListenEventListenerOrEventListenerObject | null,
options?: boolean | AddEventListenerOptions,
): void;
addEventListener(
type: string,
listener: EventListenerOrEventListenerObject | null,
Expand Down Expand Up @@ -265,6 +298,10 @@ export class Application<AS extends State = Record<string, any>>
state.closing = true;
});
}
const { hostname, port, secure = false } = options;
this.dispatchEvent(
new ApplicationListenEvent({ hostname, port, secure }),
);
try {
for await (const request of server) {
this.#handleRequest(request, state);
Expand All @@ -274,7 +311,7 @@ export class Application<AS extends State = Record<string, any>>
? error.message
: "Application Error";
this.dispatchEvent(
new ApplicationErrorEvent("error", { message, error }),
new ApplicationErrorEvent({ message, error }),
);
}
}
Expand Down
19 changes: 19 additions & 0 deletions application_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,22 @@ test({
});
},
});

test({
name: "application listen event",
async fn() {
const app = new Application({ serve });
let called = 0;
app.addEventListener("listen", (evt) => {
called++;
assertEquals(evt.hostname, "localhost");
assertEquals(evt.port, 80);
assertEquals(evt.secure, false);
});
app.use((ctx) => {
ctx.response.body = "hello world";
});
await app.listen({ hostname: "localhost", port: 80 });
assertEquals(called, 1);
},
});
12 changes: 7 additions & 5 deletions examples/closeServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ app.use(router.allowedMethods());
// A basic 404 page
app.use(notFound);

app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

// Utilise the signal from the controller
const { signal } = controller;
const options = { hostname: "127.0.0.1", port: 8000, signal };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
await app.listen({ hostname: "127.0.0.1", port: 8000, signal });
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/cookieServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ app.use((ctx) => {
}
});

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/echoServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ app.use(async (ctx) => {
}
});

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });
console.log(bold("Finished."));
12 changes: 8 additions & 4 deletions examples/httpsServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ app.use((ctx) => {
ctx.response.body = "Hello World!";
});

const options = {
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({
port: 8000,
secure: true,
certFile: "./examples/tls/localhost.crt",
keyFile: "./examples/tls/localhost.key",
};
console.log(bold("Start listening on ") + yellow(String(options.port)));
await app.listen(options);
});
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/readerServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ app.use(async (ctx) => {
ctx.response.type = "text/plain";
});

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/routingServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,11 @@ app.use(router.allowedMethods());
// A basic 404 page
app.use(notFound);

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ app.use((ctx) => {
ctx.response.body = "Hello World!";
});

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });
console.log(bold("Finished."));
12 changes: 7 additions & 5 deletions examples/staticServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ app.use(async (context) => {
});
});

const options = { hostname: "127.0.0.1", port: 8000 };
console.log(
bold("Start listening on ") + yellow(`${options.hostname}:${options.port}`),
);
await app.listen(options);
app.addEventListener("listen", ({ hostname, port }) => {
console.log(
bold("Start listening on ") + yellow(`${hostname}:${port}`),
);
});

await app.listen({ hostname: "127.0.0.1", port: 8000 });

0 comments on commit 71f25d7

Please sign in to comment.