2023-06-29 14:31:25 +00:00
|
|
|
import { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts";
|
|
|
|
import serialize from "./serialize.ts";
|
|
|
|
import HttpError from "./HttpError.ts";
|
|
|
|
import RestResponse from "./RestResponse.ts";
|
|
|
|
import RestRequest from "./RestRequest.ts";
|
|
|
|
|
|
|
|
export type HandlerRes = Promise<RestResponse | undefined> | RestResponse | undefined;
|
|
|
|
|
|
|
|
export interface Handler {
|
|
|
|
handle(req: RestRequest): HandlerRes;
|
|
|
|
}
|
|
|
|
export interface RestOptions {
|
|
|
|
route?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
// deno-lint-ignore no-explicit-any
|
|
|
|
export type ProcessFunc<T extends Router> = (this: T, req: RestRequest, arg: any, name: string) => Promise<unknown> | unknown;
|
|
|
|
|
|
|
|
export interface RouterHandler {
|
|
|
|
path: string;
|
|
|
|
handler: Handler;
|
|
|
|
}
|
|
|
|
export function addMetaQuery<T extends Router>(target: T, ...handlers: ((r: T) => RouterHandler)[]) {
|
|
|
|
let props = Reflect.getOwnMetadata('router:queries', target);
|
|
|
|
if (props === undefined) Reflect.defineMetadata('router:queries', props = [], target);
|
|
|
|
|
|
|
|
props.push(...handlers);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function makeParameterModifier<T extends Router>(func: ProcessFunc<T>) {
|
|
|
|
return (target: T, key: string, index: number) => {
|
|
|
|
let res = Reflect.getOwnMetadata('router:params', target, key);
|
|
|
|
|
|
|
|
if (res === undefined) Reflect.defineMetadata('router:params', res = [], target, key);
|
|
|
|
(res[index] ??= []).push(func);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default class Router {
|
|
|
|
private _handlers?: RouterHandler[];
|
|
|
|
public defaultHandler?: Handler;
|
|
|
|
|
|
|
|
private _init() {
|
|
|
|
if (this._handlers === undefined) {
|
|
|
|
this._handlers = [];
|
|
|
|
|
|
|
|
// why the actual fuck not
|
|
|
|
// deno-lint-ignore no-this-alias
|
|
|
|
for (let proto = this; proto instanceof Router; proto = Object.getPrototypeOf(proto)) {
|
|
|
|
const props = Reflect.getOwnMetadata('router:queries', proto);
|
|
|
|
for (const handler of props ?? []) {
|
|
|
|
this._handlers.push(handler(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this._handlers;
|
|
|
|
}
|
|
|
|
|
|
|
|
public async handle(req: RestRequest) {
|
|
|
|
for (const hnd of this._init()) {
|
|
|
|
const _req = req.match(hnd.path);
|
|
|
|
if (_req) {
|
|
|
|
try {
|
|
|
|
const res = await hnd.handler.handle(_req);
|
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
const res = await this.onError(_req, e);
|
|
|
|
if (res instanceof HttpError) return new RestResponse()
|
|
|
|
.body(await serialize(res.body))
|
|
|
|
.status(res.status);
|
|
|
|
else return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.defaultHandler?.handle(req);
|
|
|
|
}
|
|
|
|
public addHandler(path: string, handler: Handler) {
|
|
|
|
this._init().push({ path, handler });
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public onError(_req: RestRequest, error: unknown): Promise<RestResponse | HttpError> | RestResponse | HttpError {
|
|
|
|
if (error instanceof HttpError) return error;
|
|
|
|
else {
|
|
|
|
console.error(error);
|
|
|
|
try {
|
|
|
|
return new HttpError(`Internal error: ${error}\nSee logs for details`, 500);
|
|
|
|
}
|
|
|
|
catch {
|
|
|
|
return new HttpError('Internal error.\nSee logs for details', 500);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-30 00:37:07 +00:00
|
|
|
public async attach(server: Deno.Listener) {
|
|
|
|
while (true) {
|
|
|
|
for await (const conn of server) {
|
|
|
|
(async () => {
|
|
|
|
for await (const req of Deno.serveHttp(conn)) {
|
|
|
|
console.log(req.request.url);
|
|
|
|
const r = await this.handle(RestRequest.fromMessage(req));
|
|
|
|
console.log(req.request.url);
|
|
|
|
if (r) req.respondWith(r.toFetchResponse());
|
|
|
|
}
|
|
|
|
})();
|
2023-06-29 14:31:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|