feature: allow for static file uploads and deletions
feature: add HEAD and OPTIONS support to static files
This commit is contained in:
parent
582636ab5a
commit
3ef936d2d6
7 changed files with 900 additions and 120 deletions
105
server.ts
105
server.ts
|
@ -10,20 +10,26 @@ const EVENTS_TO_SHUTDOWN_ON: Deno.Signal[] = ['SIGTERM', 'SIGINT'];
|
|||
|
||||
const DEFAULT_HANDLER_DIRECTORIES = [import.meta.resolve('./handlers')];
|
||||
|
||||
/** A `HANDLER` must take a `Request` and return a `Response` if it can handle it. */
|
||||
type HANDLER = (request: Request) => Promise<Response | null | undefined> | Response | null | undefined;
|
||||
/**
|
||||
* @type HANDLER Takes a `Request` and returns a `Response` if it can properly handle the request.
|
||||
*/
|
||||
type HANDLER = (request: Request, server: SERVER) => Promise<Response | null | undefined> | Response | null | undefined;
|
||||
|
||||
/** A `LOGGER` must take a `Request`, a `Response`, and a `processing_time` and log it. */
|
||||
/**
|
||||
* @type LOGGER Takes a `Request`, `Response`, and a `processing_time` in ms to be logged.
|
||||
*/
|
||||
type LOGGER = (request: Request, response: Response, processing_time: number) => void | Promise<void>;
|
||||
|
||||
/** A `HANDLER_MODULE` must export a default method and may export an unload method to be called at shutdown. */
|
||||
/**
|
||||
* @interface HANDLER_MODULE Handler modules should export a default method (handler) and an optional `unload` method to be called at shutdown.
|
||||
*/
|
||||
interface HANDLER_MODULE {
|
||||
default: HANDLER;
|
||||
unload?: () => void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface defining the configuration for a serverus server
|
||||
* @type SERVER_OPTIONS Specifies options for creating the SERVERUS server.
|
||||
*
|
||||
* @property {string} [hostname='localhost'] - hostname to bind to
|
||||
* @property {number} [port=8000] - port to bind to
|
||||
|
@ -51,7 +57,7 @@ export const DEFAULT_SERVER_OPTIONS: SERVER_OPTIONS = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Default logger
|
||||
* @method LOG_REQUEST Default request logger.
|
||||
*
|
||||
* @param {Request} request - the incoming request
|
||||
* @param {Response} response - the outgoing response
|
||||
|
@ -71,17 +77,20 @@ function LOG_REQUEST(request: Request, response: Response, time: number) {
|
|||
}
|
||||
|
||||
/**
|
||||
* serverus SERVER
|
||||
*
|
||||
* Loads all handlers found in the [semi-]colon separated list of directories in
|
||||
* @class SERVER Loads all handlers found in the [semi-]colon separated list of directories in `SERVERUS_ROOT`.
|
||||
*/
|
||||
export class SERVER {
|
||||
private options: SERVER_OPTIONS;
|
||||
private server: Deno.HttpServer | undefined;
|
||||
private controller: AbortController | undefined;
|
||||
private shutdown_binding: (() => void) | undefined;
|
||||
private handlers: HANDLER_MODULE[];
|
||||
private original_directory: string | undefined;
|
||||
private event_listeners: Record<string, []>;
|
||||
|
||||
/**
|
||||
* @member handlers The HANDLER_MODULEs loaded for this server.
|
||||
*/
|
||||
public handlers: HANDLER_MODULE[];
|
||||
|
||||
/**
|
||||
* @param {SERVER_OPTIONS} (optional) options to configure the server
|
||||
|
@ -92,6 +101,7 @@ export class SERVER {
|
|||
...(options ?? {})
|
||||
};
|
||||
this.handlers = [];
|
||||
this.event_listeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,7 +173,7 @@ export class SERVER {
|
|||
: (this.options.logging ? LOG_REQUEST : undefined);
|
||||
|
||||
for (const handler_module of this.handlers) {
|
||||
const response = await handler_module.default(request);
|
||||
const response = await handler_module.default(request, this);
|
||||
if (response) {
|
||||
logger?.(request, response, Date.now() - request_time);
|
||||
return response;
|
||||
|
@ -189,6 +199,8 @@ export class SERVER {
|
|||
// Deno.watchFs;
|
||||
// }
|
||||
|
||||
this.emit('started', {});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -196,6 +208,8 @@ export class SERVER {
|
|||
* Stop the server
|
||||
*/
|
||||
public async stop(): Promise<void> {
|
||||
this.emit('stopping', {});
|
||||
|
||||
if (this.server) {
|
||||
this.server.finished.finally(() => {
|
||||
if (this.shutdown_binding) {
|
||||
|
@ -226,5 +240,74 @@ export class SERVER {
|
|||
}
|
||||
}
|
||||
this.handlers = [];
|
||||
|
||||
this.emit('stopped', {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event listener.
|
||||
*
|
||||
* @param {string} event The event to listen for.
|
||||
* @param {(event_data: any) => void} handler The handler for the event.
|
||||
*/
|
||||
public on(event: string, handler: (event_data: any) => void) {
|
||||
const listeners: ((event: any) => void)[] = this.event_listeners[event] = this.event_listeners[event] ?? [];
|
||||
if (!listeners.includes(handler)) {
|
||||
listeners.push(handler);
|
||||
}
|
||||
|
||||
if (Deno.env.get('SERVERUS_LOG_EVENTS')) {
|
||||
console.dir({
|
||||
on: {
|
||||
event,
|
||||
handler
|
||||
},
|
||||
listeners
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an event listener.
|
||||
*
|
||||
* @param {string} event The event that was listened to.
|
||||
* @param {(event_data: any) => void} handler The handler that was registered that should be removed.
|
||||
*/
|
||||
public off(event: string, handler: (event_data: any) => void) {
|
||||
const listeners: ((event: any) => void)[] = this.event_listeners[event] = this.event_listeners[event] ?? [];
|
||||
if (listeners.includes(handler)) {
|
||||
listeners.splice(listeners.indexOf(handler), 1);
|
||||
}
|
||||
|
||||
if (Deno.env.get('SERVERUS_LOG_EVENTS')) {
|
||||
console.dir({
|
||||
off: {
|
||||
event: event,
|
||||
handler
|
||||
},
|
||||
listeners
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public emit(event_name: string, event_data: any) {
|
||||
const listeners: ((event: any) => void)[] = this.event_listeners[event_name] = this.event_listeners[event_name] ?? [];
|
||||
const wildcard_listeners: ((event: any) => void)[] = this.event_listeners['*'] = this.event_listeners['*'] ?? [];
|
||||
const all_listeners: ((event: any) => void)[] = [...listeners, ...wildcard_listeners];
|
||||
|
||||
if (Deno.env.get('SERVERUS_LOG_EVENTS')) {
|
||||
console.dir({
|
||||
emitting: {
|
||||
event_name,
|
||||
event_data,
|
||||
listeners,
|
||||
wildcard_listeners
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const listener of all_listeners) {
|
||||
listener(event_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue