import handler from "./handler"; import { path, response, request, AllMismatchInterrupted, responder, method, } from "./interface/index"; import { defaultHeaders } from "./interface/response"; import route from "./route"; import { methodENUM } from "./interface/method"; import { createPlatformAdapater, platformAdapaterConstructor, platformAdapater, } from "./platform/index"; import { platformAdapaterMapping } from "./platform/export"; import { platform } from "./lib"; export class router { public routes: route[]; public errorResponder: ( errorCode: number, errorMessage?: string ) => responder; constructor(routes: route[] = []) { this.routes = routes; } add(route: route) { this.routes.push(route); return this; } binding(path: path, handler: handler) { this.add(new route([path], [handler])); return this; } create( method: method, responder: ( request: request ) => | Promise> | Promise | Promise | Promise | Promise ) { return new handler(method, [ async (request: request) => { const answer = await responder(request); if (answer instanceof response) { return answer; } else if (typeof answer == "string") { return new response(answer); } else if (typeof answer == "number") { return new response(answer.toString()); } else if (typeof answer == "object") { return new response( JSON.stringify(answer), 200, new defaultHeaders({ "Content-Type": "application/json; charset=utf-8", }) ); } else { return new response("", 204); } }, ]); } use(routers: router[], path: path): void { routers.forEach((router) => { this.binding(path, router.toHandler()); }); } route(path: path): router { const Router = new router([]); this.use([Router], path); return Router; } async _respond( request: request, responseMessage: response = new response("") ): Promise> { request.originURL = request.url; request.url.pathname = request.params["0"] ? "/" + request.params["0"] : request.originURL.pathname; let mismatchCount = 0; for (let route of this.routes) { const isMatched = await route.exec(request.url.pathname); if (!isMatched.matched) { mismatchCount++; continue; } isMatched.attributes.forEach((e) => { request.params[e.name] = e.value; }); try { let thisResponse: response | void = responseMessage; for (let handler of route.handlers) { if ( handler.method != request.method && handler.method != methodENUM.ANY ) { continue; } thisResponse = await handler.respond( request, thisResponse ?? responseMessage ); } if (thisResponse instanceof response) { responseMessage = thisResponse; } else { // means that the handler is a middleware that doesn't change the response throw AllMismatchInterrupted; } } catch (e) { if (e instanceof response) { throw e; } if (e === AllMismatchInterrupted) mismatchCount++; else { if (typeof this.errorResponder == "function") { responseMessage = (await this.errorResponder(500, e.toString() + "\n")(request)) ?? new response(e.toString(), 500); console.log(e); } else { throw e; } } } } if (mismatchCount == this.routes.length) { throw AllMismatchInterrupted; } return responseMessage; } public respond = this._respond; toHandler(): handler { return new handler(methodENUM.ANY, [ (request: request, responseMessage?: response) => { return this.respond(request, responseMessage ?? new response("")); }, ]); } useErrorResponder( errorResponder: ( errorCode: number, errorMessage?: string ) => responder ): this { this.errorResponder = errorResponder; return this; } } export default router; export class rootRouter extends router { public adapater: platformAdapater; errorResponder = (errorCode: number, errorMessage?: string) => async (_request: request): Promise> => new response(errorMessage ?? "", errorCode); respond = async (request: request): Promise> => { let responseMessage: response = new response(""); try { responseMessage = await this._respond(request, responseMessage); } catch (e) { if (e instanceof response) { return e; } else if (e === AllMismatchInterrupted) { responseMessage = (await this.errorResponder(404, "404 Not Found\n")(request)) ?? new response("404 Not Found\n", 404); } else { responseMessage = (await this.errorResponder(500, e.toString() + "\n")(request)) ?? new response(e.toString(), 500); console.log(e); } } return responseMessage; }; useAdapater(adapater: platformAdapaterConstructor): this { this.adapater = createPlatformAdapater(adapater, this); return this; } useMappingAdapter( mapping: { [platform: string]: platformAdapaterConstructor } = platformAdapaterMapping ): this { if (typeof platform == "undefined") throw new Error("Cannot detect platform"); if (mapping[platform] == undefined) throw new Error("Platform not found in mapping"); else this.useAdapater(mapping[platform]); return this; } listen(port: number): void { if (this.adapater == null) throw new Error("No platform adapter set"); this.adapater.listen(port); } }