mirror of
https://github.com/186526/handlers.js
synced 2024-10-13 00:29:43 +00:00
format
This commit is contained in:
@ -1,43 +1,46 @@
|
||||
import { method, request, responder, response } from "./interface/index";
|
||||
import { method, request, responder, response } from './interface/index';
|
||||
|
||||
export class handler<RequestCustomType, ResponseCustomType> {
|
||||
public responders: responder<RequestCustomType, ResponseCustomType>[];
|
||||
public method: method;
|
||||
public responders: responder<RequestCustomType, ResponseCustomType>[];
|
||||
public method: method;
|
||||
|
||||
constructor(
|
||||
method: method,
|
||||
responders: responder<RequestCustomType, ResponseCustomType>[]
|
||||
) {
|
||||
this.responders = responders;
|
||||
this.method = method;
|
||||
}
|
||||
constructor(
|
||||
method: method,
|
||||
responders: responder<RequestCustomType, ResponseCustomType>[],
|
||||
) {
|
||||
this.responders = responders;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
add(responder: responder<RequestCustomType, ResponseCustomType>) {
|
||||
this.responders.push(responder);
|
||||
}
|
||||
add(responder: responder<RequestCustomType, ResponseCustomType>) {
|
||||
this.responders.push(responder);
|
||||
}
|
||||
|
||||
async respond(
|
||||
request: request<RequestCustomType>,
|
||||
responseMessage: response<ResponseCustomType> = new response<ResponseCustomType>(
|
||||
""
|
||||
)
|
||||
): Promise<response<ResponseCustomType> | void> {
|
||||
switch (this.responders.length) {
|
||||
case 0:
|
||||
Promise.reject("No responders found in this handler.");
|
||||
break;
|
||||
case 1:
|
||||
return this.responders[0](request, responseMessage);
|
||||
default:
|
||||
for (let responder of this.responders) {
|
||||
let thisResponse = await responder(request, responseMessage);
|
||||
if (thisResponse instanceof response) {
|
||||
responseMessage = thisResponse;
|
||||
}
|
||||
}
|
||||
return responseMessage;
|
||||
}
|
||||
}
|
||||
async respond(
|
||||
request: request<RequestCustomType>,
|
||||
responseMessage: response<ResponseCustomType> = new response<ResponseCustomType>(
|
||||
'',
|
||||
),
|
||||
): Promise<response<ResponseCustomType> | void> {
|
||||
switch (this.responders.length) {
|
||||
case 0:
|
||||
Promise.reject('No responders found in this handler.');
|
||||
break;
|
||||
case 1:
|
||||
return this.responders[0](request, responseMessage);
|
||||
default:
|
||||
for (let responder of this.responders) {
|
||||
let thisResponse = await responder(
|
||||
request,
|
||||
responseMessage,
|
||||
);
|
||||
if (thisResponse instanceof response) {
|
||||
responseMessage = thisResponse;
|
||||
}
|
||||
}
|
||||
return responseMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default handler;
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import * as lib from "../lib";
|
||||
import * as lib from '../lib';
|
||||
export class headers {
|
||||
public headers: { [key: string]: string } = {};
|
||||
constructor(headers: { [key: string]: string }) {
|
||||
this.headers = {};
|
||||
Object.keys(headers).forEach((key) => {
|
||||
this.headers[lib.firstUpperCase(key)] = headers[key];
|
||||
});
|
||||
}
|
||||
delete(key: string) {
|
||||
delete this.headers[lib.firstUpperCase(key)];
|
||||
}
|
||||
get(key: string): string | undefined {
|
||||
return this.headers[lib.firstUpperCase(key)];
|
||||
}
|
||||
has(key: string): boolean {
|
||||
return this.headers.hasOwnProperty(lib.firstUpperCase(key));
|
||||
}
|
||||
set(key: string, value: string) {
|
||||
this.headers[lib.firstUpperCase(key)] = value;
|
||||
}
|
||||
toObject() {
|
||||
return this.headers;
|
||||
}
|
||||
forEach(func: (key: string, value: string) => any) {
|
||||
Object.keys(this.headers).forEach((key) => {
|
||||
func(key, this.headers[key]);
|
||||
})
|
||||
}
|
||||
public headers: { [key: string]: string } = {};
|
||||
constructor(headers: { [key: string]: string }) {
|
||||
this.headers = {};
|
||||
Object.keys(headers).forEach((key) => {
|
||||
this.headers[lib.firstUpperCase(key)] = headers[key];
|
||||
});
|
||||
}
|
||||
delete(key: string) {
|
||||
delete this.headers[lib.firstUpperCase(key)];
|
||||
}
|
||||
get(key: string): string | undefined {
|
||||
return this.headers[lib.firstUpperCase(key)];
|
||||
}
|
||||
has(key: string): boolean {
|
||||
return this.headers.hasOwnProperty(lib.firstUpperCase(key));
|
||||
}
|
||||
set(key: string, value: string) {
|
||||
this.headers[lib.firstUpperCase(key)] = value;
|
||||
}
|
||||
toObject() {
|
||||
return this.headers;
|
||||
}
|
||||
forEach(func: (key: string, value: string) => any) {
|
||||
Object.keys(this.headers).forEach((key) => {
|
||||
func(key, this.headers[key]);
|
||||
});
|
||||
}
|
||||
}
|
||||
export default headers;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export { request } from "./request";
|
||||
export { response } from "./response";
|
||||
export { method } from "./method";
|
||||
export { headers } from "./headers";
|
||||
export { responder } from "./responder";
|
||||
export const AllMismatchInterrupted = new Error("AllMismatchInterrupted");
|
||||
export { request } from './request';
|
||||
export { response } from './response';
|
||||
export { method } from './method';
|
||||
export { headers } from './headers';
|
||||
export { responder } from './responder';
|
||||
export const AllMismatchInterrupted = new Error('AllMismatchInterrupted');
|
||||
export type path = string | RegExp;
|
||||
|
||||
@ -1,61 +1,72 @@
|
||||
export enum methodENUM {
|
||||
/**
|
||||
* The `CONNECT` method establishes a tunnel to the server identified by the
|
||||
* target resource.
|
||||
*/
|
||||
CONNECT = "CONNECT",
|
||||
/**
|
||||
* The `CONNECT` method establishes a tunnel to the server identified by the
|
||||
* target resource.
|
||||
*/
|
||||
CONNECT = 'CONNECT',
|
||||
|
||||
/**
|
||||
* The `DELETE` method deletes the specified resource.
|
||||
*/
|
||||
DELETE = "DELETE",
|
||||
/**
|
||||
* The `DELETE` method deletes the specified resource.
|
||||
*/
|
||||
DELETE = 'DELETE',
|
||||
|
||||
/**
|
||||
* The `GET` method requests a representation of the specified resource.
|
||||
* Requests using GET should only retrieve data.
|
||||
*/
|
||||
GET = "GET",
|
||||
/**
|
||||
* The `GET` method requests a representation of the specified resource.
|
||||
* Requests using GET should only retrieve data.
|
||||
*/
|
||||
GET = 'GET',
|
||||
|
||||
/**
|
||||
* The `HEAD` method asks for a response identical to that of a GET request,
|
||||
* but without the response body.
|
||||
*/
|
||||
HEAD = "HEAD",
|
||||
/**
|
||||
* The `HEAD` method asks for a response identical to that of a GET request,
|
||||
* but without the response body.
|
||||
*/
|
||||
HEAD = 'HEAD',
|
||||
|
||||
/**
|
||||
* The `OPTIONS` method is used to describe the communication options for the
|
||||
* target resource.
|
||||
*/
|
||||
OPTIONS = "OPTIONS",
|
||||
/**
|
||||
* The `OPTIONS` method is used to describe the communication options for the
|
||||
* target resource.
|
||||
*/
|
||||
OPTIONS = 'OPTIONS',
|
||||
|
||||
/**
|
||||
* The PATCH method is used to apply partial modifications to a resource.
|
||||
*/
|
||||
PATCH = "PATCH",
|
||||
/**
|
||||
* The PATCH method is used to apply partial modifications to a resource.
|
||||
*/
|
||||
PATCH = 'PATCH',
|
||||
|
||||
/**
|
||||
* The `POST` method is used to submit an entity to the specified resource,
|
||||
* often causing a change in state or side effects on the server.
|
||||
*/
|
||||
POST = "POST",
|
||||
/**
|
||||
* The `POST` method is used to submit an entity to the specified resource,
|
||||
* often causing a change in state or side effects on the server.
|
||||
*/
|
||||
POST = 'POST',
|
||||
|
||||
/**
|
||||
* The `PUT` method replaces all current representations of the target
|
||||
* resource with the request payload.
|
||||
*/
|
||||
PUT = "PUT",
|
||||
/**
|
||||
* The `PUT` method replaces all current representations of the target
|
||||
* resource with the request payload.
|
||||
*/
|
||||
PUT = 'PUT',
|
||||
|
||||
/**
|
||||
* The `TRACE` method performs a message loop-back test along the path to the
|
||||
* target resource.
|
||||
*/
|
||||
TRACE = "TRACE",
|
||||
/**
|
||||
* The `ANY` method will match any method.
|
||||
*/
|
||||
ANY = "ANY",
|
||||
/**
|
||||
* The `TRACE` method performs a message loop-back test along the path to the
|
||||
* target resource.
|
||||
*/
|
||||
TRACE = 'TRACE',
|
||||
/**
|
||||
* The `ANY` method will match any method.
|
||||
*/
|
||||
ANY = 'ANY',
|
||||
}
|
||||
|
||||
export type method = "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | "ANY" | methodENUM;
|
||||
export type method =
|
||||
| 'CONNECT'
|
||||
| 'DELETE'
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'OPTIONS'
|
||||
| 'PATCH'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'TRACE'
|
||||
| 'ANY'
|
||||
| methodENUM;
|
||||
|
||||
export default method;
|
||||
export default method;
|
||||
|
||||
@ -1,34 +1,37 @@
|
||||
import method from "./method";
|
||||
import headers from "./headers";
|
||||
import method from './method';
|
||||
import headers from './headers';
|
||||
export class request<RequestCustomType> {
|
||||
public readonly method: method;
|
||||
public readonly url: URL;
|
||||
public originURL?: URL;
|
||||
public readonly headers: headers;
|
||||
public readonly body: any;
|
||||
public readonly query: URLSearchParams;
|
||||
public params: { [key: string]: string | undefined };
|
||||
public custom: RequestCustomType;
|
||||
public ip: string;
|
||||
public constructor(
|
||||
method: method,
|
||||
url: URL,
|
||||
headers: headers,
|
||||
body: any,
|
||||
params: { [key: string]: string },
|
||||
ip: string = "0.0.0.0"
|
||||
) {
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
this.query = new URLSearchParams(url.search);
|
||||
this.params = params;
|
||||
this.ip = headers.get("X-REAL-IP") ?? headers.get("X-Forwarded-For")?.split(" ")[0] ?? ip;
|
||||
}
|
||||
public extends(custom: RequestCustomType): request<RequestCustomType> {
|
||||
this.custom = custom;
|
||||
return this;
|
||||
}
|
||||
public readonly method: method;
|
||||
public readonly url: URL;
|
||||
public originURL?: URL;
|
||||
public readonly headers: headers;
|
||||
public readonly body: any;
|
||||
public readonly query: URLSearchParams;
|
||||
public params: { [key: string]: string | undefined };
|
||||
public custom: RequestCustomType;
|
||||
public ip: string;
|
||||
public constructor(
|
||||
method: method,
|
||||
url: URL,
|
||||
headers: headers,
|
||||
body: any,
|
||||
params: { [key: string]: string },
|
||||
ip: string = '0.0.0.0',
|
||||
) {
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
this.query = new URLSearchParams(url.search);
|
||||
this.params = params;
|
||||
this.ip =
|
||||
headers.get('X-REAL-IP') ??
|
||||
headers.get('X-Forwarded-For')?.split(' ')[0] ??
|
||||
ip;
|
||||
}
|
||||
public extends(custom: RequestCustomType): request<RequestCustomType> {
|
||||
this.custom = custom;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
export default request;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { request, response } from "./index";
|
||||
import { request, response } from './index';
|
||||
export interface responder<RequestCustomType, ResponseCustomType> {
|
||||
(
|
||||
request: request<RequestCustomType>,
|
||||
reponse?: response<ResponseCustomType>
|
||||
): Promise<response<ResponseCustomType>> | Promise<void> | void;
|
||||
(
|
||||
request: request<RequestCustomType>,
|
||||
reponse?: response<ResponseCustomType>,
|
||||
): Promise<response<ResponseCustomType>> | Promise<void> | void;
|
||||
}
|
||||
export default responder;
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
import headers from "./headers";
|
||||
import packageJSON from "../../package.json";
|
||||
import { platform, version } from "../lib";
|
||||
import headers from './headers';
|
||||
import packageJSON from '../../package.json';
|
||||
import { platform, version } from '../lib';
|
||||
|
||||
export class defaultHeaders extends headers {
|
||||
constructor(headers: { [key: string]: string } = {}) {
|
||||
super(headers);
|
||||
if (!this.has("Content-Type"))
|
||||
this.set("Content-Type", "text/plain; charset=utf-8");
|
||||
this.set(
|
||||
"Server",
|
||||
`Handlers.js/${packageJSON.version} ${platform}/${version}`
|
||||
);
|
||||
}
|
||||
constructor(headers: { [key: string]: string } = {}) {
|
||||
super(headers);
|
||||
if (!this.has('Content-Type'))
|
||||
this.set('Content-Type', 'text/plain; charset=utf-8');
|
||||
this.set(
|
||||
'Server',
|
||||
`Handlers.js/${packageJSON.version} ${platform}/${version}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
export class response<ResponseCustomType> {
|
||||
public status: number;
|
||||
public headers: headers;
|
||||
public body: any;
|
||||
public custom: ResponseCustomType;
|
||||
public constructor(
|
||||
body: any,
|
||||
status: number = 200,
|
||||
headers: headers = new defaultHeaders()
|
||||
) {
|
||||
this.status = status;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
public extends(custom: ResponseCustomType): response<ResponseCustomType> {
|
||||
this.custom = custom;
|
||||
return this;
|
||||
}
|
||||
public status: number;
|
||||
public headers: headers;
|
||||
public body: any;
|
||||
public custom: ResponseCustomType;
|
||||
public constructor(
|
||||
body: any,
|
||||
status: number = 200,
|
||||
headers: headers = new defaultHeaders(),
|
||||
) {
|
||||
this.status = status;
|
||||
this.headers = headers;
|
||||
this.body = body;
|
||||
}
|
||||
public extends(custom: ResponseCustomType): response<ResponseCustomType> {
|
||||
this.custom = custom;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
export default response;
|
||||
|
||||
58
src/lib.ts
58
src/lib.ts
@ -1,34 +1,34 @@
|
||||
export const firstUpperCase = ([first, ...rest]: string) =>
|
||||
first?.toUpperCase() + rest.map((e) => e.toLowerCase()).join("");
|
||||
first?.toUpperCase() + rest.map((e) => e.toLowerCase()).join('');
|
||||
export const platform = (() => {
|
||||
if (typeof process != "undefined") {
|
||||
return "Node.js";
|
||||
}
|
||||
if (typeof Deno != "undefined") {
|
||||
return "Deno";
|
||||
}
|
||||
if (typeof Bun != "undefined") {
|
||||
return "Bun";
|
||||
}
|
||||
if (typeof tjs != "undefined") {
|
||||
return "txiki.js";
|
||||
}
|
||||
if (typeof self != "undefined") {
|
||||
return "Service Worker";
|
||||
}
|
||||
return undefined;
|
||||
if (typeof process != 'undefined') {
|
||||
return 'Node.js';
|
||||
}
|
||||
if (typeof Deno != 'undefined') {
|
||||
return 'Deno';
|
||||
}
|
||||
if (typeof Bun != 'undefined') {
|
||||
return 'Bun';
|
||||
}
|
||||
if (typeof tjs != 'undefined') {
|
||||
return 'txiki.js';
|
||||
}
|
||||
if (typeof self != 'undefined') {
|
||||
return 'Service Worker';
|
||||
}
|
||||
return undefined;
|
||||
})();
|
||||
export const version = (() => {
|
||||
switch (platform) {
|
||||
case "Node.js" || "Bun":
|
||||
return process.version;
|
||||
case "Deno":
|
||||
return Deno.version.deno;
|
||||
case "txiki.js":
|
||||
return tjs.versions.tjs;
|
||||
case "Service Worker":
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
switch (platform) {
|
||||
case 'Node.js' || 'Bun':
|
||||
return process.version;
|
||||
case 'Deno':
|
||||
return Deno.version.deno;
|
||||
case 'txiki.js':
|
||||
return tjs.versions.tjs;
|
||||
case 'Service Worker':
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { SWPlatformAdapter } from "./serviceworker";
|
||||
import { platformAdapater } from "./index";
|
||||
import { SWPlatformAdapter } from './serviceworker';
|
||||
import { platformAdapater } from './index';
|
||||
|
||||
export class BunPlatformAdapter<T = any, K = any>
|
||||
extends SWPlatformAdapter<T, K>
|
||||
implements platformAdapater<T, K>
|
||||
extends SWPlatformAdapter<T, K>
|
||||
implements platformAdapater<T, K>
|
||||
{
|
||||
async listen(port: number): Promise<void> {
|
||||
Bun.serve({
|
||||
fetch: async (request: Request): Promise<Response> => {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(request).then((request) =>
|
||||
this.router.respond(request)
|
||||
)
|
||||
);
|
||||
},
|
||||
port,
|
||||
});
|
||||
}
|
||||
async listen(port: number): Promise<void> {
|
||||
Bun.serve({
|
||||
fetch: async (request: Request): Promise<Response> => {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(request).then((request) =>
|
||||
this.router.respond(request),
|
||||
),
|
||||
);
|
||||
},
|
||||
port,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,26 +1,25 @@
|
||||
import { SWPlatformAdapter } from "./serviceworker";
|
||||
import { platformAdapater } from "./index";
|
||||
|
||||
import { request } from "../interface/request";
|
||||
import { headers } from "../interface/headers";
|
||||
import { methodENUM } from "src/interface/method";
|
||||
import { SWPlatformAdapter } from './serviceworker';
|
||||
import { platformAdapater } from './index';
|
||||
|
||||
import { request } from '../interface/request';
|
||||
import { headers } from '../interface/headers';
|
||||
import { methodENUM } from 'src/interface/method';
|
||||
|
||||
const DefaultConn: Deno.Conn = {
|
||||
localAddr: {
|
||||
transport: "tcp",
|
||||
hostname: "0.0.0.0",
|
||||
transport: 'tcp',
|
||||
hostname: '0.0.0.0',
|
||||
port: 80,
|
||||
},
|
||||
remoteAddr: {
|
||||
transport: "tcp",
|
||||
hostname: "0.0.0.0",
|
||||
transport: 'tcp',
|
||||
hostname: '0.0.0.0',
|
||||
port: 80,
|
||||
},
|
||||
rid: 0,
|
||||
closeWrite: async () => undefined,
|
||||
readable: "",
|
||||
writable: "",
|
||||
readable: '',
|
||||
writable: '',
|
||||
read: async (p: Uint8Array) => null,
|
||||
write: async (p: Uint8Array) => 0,
|
||||
close: () => undefined,
|
||||
@ -37,14 +36,19 @@ export class DenoPlatformAdapter<T = any, K = any>
|
||||
const httpConnection = Deno.serveHttp(connection);
|
||||
|
||||
for await (const requestEvent of httpConnection) {
|
||||
requestEvent.respondWith(this.handler(requestEvent, connection));
|
||||
requestEvent.respondWith(
|
||||
this.handler(requestEvent, connection),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleRequest(nativeRequest: Request, connection: Deno.Conn = DefaultConn): Promise<request<T>> {
|
||||
async handleRequest(
|
||||
nativeRequest: Request,
|
||||
connection: Deno.Conn = DefaultConn,
|
||||
): Promise<request<T>> {
|
||||
const requestHeaders = new headers(
|
||||
Object.fromEntries(nativeRequest.headers.entries())
|
||||
Object.fromEntries(nativeRequest.headers.entries()),
|
||||
);
|
||||
const requestMessage: request<T> = new request(
|
||||
<methodENUM>nativeRequest.method,
|
||||
@ -52,16 +56,20 @@ export class DenoPlatformAdapter<T = any, K = any>
|
||||
requestHeaders,
|
||||
await nativeRequest.text(),
|
||||
{},
|
||||
`${connection.remoteAddr.hostname}:${connection.remoteAddr.port}` || ""
|
||||
`${connection.remoteAddr.hostname}:${connection.remoteAddr.port}` ||
|
||||
'',
|
||||
);
|
||||
return requestMessage;
|
||||
}
|
||||
|
||||
async handler(event: FetchEvent, connection: Deno.Conn = DefaultConn): Promise<Response> {
|
||||
async handler(
|
||||
event: FetchEvent,
|
||||
connection: Deno.Conn = DefaultConn,
|
||||
): Promise<Response> {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(event.request, connection).then((request) =>
|
||||
this.router.respond(request)
|
||||
)
|
||||
)
|
||||
await this.handleRequest(event.request, connection).then(
|
||||
(request) => this.router.respond(request),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
import { NodePlatformAdapter } from "./node";
|
||||
import { SWPlatformAdapter } from "./serviceworker";
|
||||
import { DenoPlatformAdapter } from "./deno";
|
||||
import { TxikiPlatformAdapter } from "./txiki";
|
||||
import { NodePlatformAdapter } from './node';
|
||||
import { SWPlatformAdapter } from './serviceworker';
|
||||
import { DenoPlatformAdapter } from './deno';
|
||||
import { TxikiPlatformAdapter } from './txiki';
|
||||
|
||||
export const platformAdapaterMapping = {
|
||||
"Node.js": NodePlatformAdapter,
|
||||
"Service Worker": SWPlatformAdapter,
|
||||
"Deno": DenoPlatformAdapter,
|
||||
"txiki.js": TxikiPlatformAdapter,
|
||||
'Node.js': NodePlatformAdapter,
|
||||
'Service Worker': SWPlatformAdapter,
|
||||
Deno: DenoPlatformAdapter,
|
||||
'txiki.js': TxikiPlatformAdapter,
|
||||
};
|
||||
|
||||
export { NodePlatformAdapter, SWPlatformAdapter, DenoPlatformAdapter, TxikiPlatformAdapter };
|
||||
export {
|
||||
NodePlatformAdapter,
|
||||
SWPlatformAdapter,
|
||||
DenoPlatformAdapter,
|
||||
TxikiPlatformAdapter,
|
||||
};
|
||||
|
||||
@ -1,20 +1,23 @@
|
||||
import { request, response } from "../interface/index";
|
||||
import { router } from "../router";
|
||||
import { request, response } from '../interface/index';
|
||||
import { router } from '../router';
|
||||
|
||||
export interface platformAdapater<T = any, K = any> {
|
||||
router: router<T, K>;
|
||||
listen(port: number): void;
|
||||
handleRequest(nativeRequest: any): Promise<request<T>>;
|
||||
handleResponse(response: response<K> | Promise<response<K>>, nativeResponse?: any): any;
|
||||
router: router<T, K>;
|
||||
listen(port: number): void;
|
||||
handleRequest(nativeRequest: any): Promise<request<T>>;
|
||||
handleResponse(
|
||||
response: response<K> | Promise<response<K>>,
|
||||
nativeResponse?: any,
|
||||
): any;
|
||||
}
|
||||
|
||||
export interface platformAdapaterConstructor<T = any, K = any> {
|
||||
new (router: router<T, K>): platformAdapater<T, K>;
|
||||
new (router: router<T, K>): platformAdapater<T, K>;
|
||||
}
|
||||
|
||||
export function createPlatformAdapater(
|
||||
adapater: platformAdapaterConstructor,
|
||||
router: router
|
||||
adapater: platformAdapaterConstructor,
|
||||
router: router,
|
||||
): platformAdapater {
|
||||
return new adapater(router);
|
||||
return new adapater(router);
|
||||
}
|
||||
|
||||
@ -1,77 +1,81 @@
|
||||
import { platformAdapater } from "./index";
|
||||
import { request, response } from "../interface/index";
|
||||
import { router } from "../router";
|
||||
import { headers } from "../interface/headers";
|
||||
import { platformAdapater } from './index';
|
||||
import { request, response } from '../interface/index';
|
||||
import { router } from '../router';
|
||||
import { headers } from '../interface/headers';
|
||||
|
||||
import http from "http";
|
||||
import { methodENUM } from "src/interface/method";
|
||||
import http from 'http';
|
||||
import { methodENUM } from 'src/interface/method';
|
||||
|
||||
export class NodePlatformAdapter<T = any, K = any> implements platformAdapater {
|
||||
public router: router<T, K>;
|
||||
public router: router<T, K>;
|
||||
|
||||
constructor(router: router<T, K>) {
|
||||
this.router = router;
|
||||
}
|
||||
constructor(router: router<T, K>) {
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
async listen(port: number): Promise<void> {
|
||||
const server = http.createServer();
|
||||
server.on(
|
||||
"request",
|
||||
async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
const request = await this.handleRequest(req);
|
||||
const response = await this.router.respond(request);
|
||||
this.handleResponse(response, res);
|
||||
}
|
||||
);
|
||||
server.listen(port);
|
||||
return;
|
||||
}
|
||||
async listen(port: number): Promise<void> {
|
||||
const server = http.createServer();
|
||||
server.on(
|
||||
'request',
|
||||
async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
const request = await this.handleRequest(req);
|
||||
const response = await this.router.respond(request);
|
||||
this.handleResponse(response, res);
|
||||
},
|
||||
);
|
||||
server.listen(port);
|
||||
return;
|
||||
}
|
||||
|
||||
async handleRequest(
|
||||
nativeRequest: http.IncomingMessage
|
||||
): Promise<request<T>> {
|
||||
if (
|
||||
typeof nativeRequest.method != "string" ||
|
||||
typeof nativeRequest.url != "string" ||
|
||||
typeof nativeRequest.headers != "object"
|
||||
) {
|
||||
throw new Error("Invalid request");
|
||||
}
|
||||
async handleRequest(
|
||||
nativeRequest: http.IncomingMessage,
|
||||
): Promise<request<T>> {
|
||||
if (
|
||||
typeof nativeRequest.method != 'string' ||
|
||||
typeof nativeRequest.url != 'string' ||
|
||||
typeof nativeRequest.headers != 'object'
|
||||
) {
|
||||
throw new Error('Invalid request');
|
||||
}
|
||||
|
||||
let body: string = "";
|
||||
const ip: string = nativeRequest.socket.remoteAddress?.replace("::ffff:", "") ?? "0.0.0.0";
|
||||
const requestHeaders = new headers(<any>nativeRequest.headers);
|
||||
let body: string = '';
|
||||
const ip: string =
|
||||
nativeRequest.socket.remoteAddress?.replace('::ffff:', '') ??
|
||||
'0.0.0.0';
|
||||
const requestHeaders = new headers(<any>nativeRequest.headers);
|
||||
|
||||
if (!["GET", "HEAD", "DELETE", "OPTIONS"].includes(nativeRequest.method)) {
|
||||
nativeRequest.on("data", (data: string) => {
|
||||
body += data;
|
||||
});
|
||||
if (
|
||||
!['GET', 'HEAD', 'DELETE', 'OPTIONS'].includes(nativeRequest.method)
|
||||
) {
|
||||
nativeRequest.on('data', (data: string) => {
|
||||
body += data;
|
||||
});
|
||||
|
||||
await new Promise((resolve) =>
|
||||
nativeRequest.on("end", () => {
|
||||
resolve(true);
|
||||
})
|
||||
);
|
||||
}
|
||||
await new Promise((resolve) =>
|
||||
nativeRequest.on('end', () => {
|
||||
resolve(true);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return new request<T>(
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(
|
||||
nativeRequest.url,
|
||||
`http://${requestHeaders.get("host") ?? "localhost"}`
|
||||
),
|
||||
requestHeaders,
|
||||
body,
|
||||
{},
|
||||
ip
|
||||
);
|
||||
}
|
||||
return new request<T>(
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(
|
||||
nativeRequest.url,
|
||||
`http://${requestHeaders.get('host') ?? 'localhost'}`,
|
||||
),
|
||||
requestHeaders,
|
||||
body,
|
||||
{},
|
||||
ip,
|
||||
);
|
||||
}
|
||||
|
||||
handleResponse(response: response<K>, nativeResponse: http.ServerResponse) {
|
||||
nativeResponse.statusCode = response.status;
|
||||
response.headers.forEach((key, value) => {
|
||||
nativeResponse.setHeader(key, value);
|
||||
});
|
||||
nativeResponse.end(response.body);
|
||||
}
|
||||
handleResponse(response: response<K>, nativeResponse: http.ServerResponse) {
|
||||
nativeResponse.statusCode = response.status;
|
||||
response.headers.forEach((key, value) => {
|
||||
nativeResponse.setHeader(key, value);
|
||||
});
|
||||
nativeResponse.end(response.body);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,53 +1,55 @@
|
||||
import { platformAdapater } from "./index";
|
||||
import { request } from "../interface/request";
|
||||
import { response } from "../interface/response";
|
||||
import { router } from "../router";
|
||||
import { headers } from "../interface/headers";
|
||||
import { platformAdapater } from './index';
|
||||
import { request } from '../interface/request';
|
||||
import { response } from '../interface/response';
|
||||
import { router } from '../router';
|
||||
import { headers } from '../interface/headers';
|
||||
|
||||
import { methodENUM } from "src/interface/method";
|
||||
import { methodENUM } from 'src/interface/method';
|
||||
|
||||
export class SWPlatformAdapter<T = any, K = any> implements platformAdapater {
|
||||
public router: router<T, K>;
|
||||
public router: router<T, K>;
|
||||
|
||||
constructor(router: router<T, K>) {
|
||||
this.router = router;
|
||||
}
|
||||
constructor(router: router<T, K>) {
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
async listen(_port?: number): Promise<void> {
|
||||
self.addEventListener("fetch", (event: FetchEvent) => {
|
||||
event.respondWith(this.handler(event));
|
||||
});
|
||||
}
|
||||
async listen(_port?: number): Promise<void> {
|
||||
self.addEventListener('fetch', (event: FetchEvent) => {
|
||||
event.respondWith(this.handler(event));
|
||||
});
|
||||
}
|
||||
|
||||
async handleRequest(nativeRequest: Request): Promise<request<T>> {
|
||||
const requestHeaders = new headers(
|
||||
Object.fromEntries(nativeRequest.headers.entries())
|
||||
);
|
||||
const requestMessage: request<T> = new request(
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(nativeRequest.url),
|
||||
requestHeaders,
|
||||
await nativeRequest.text(),
|
||||
{},
|
||||
requestHeaders.get("CF-Connecting-IP") || ""
|
||||
);
|
||||
return requestMessage;
|
||||
}
|
||||
async handleRequest(nativeRequest: Request): Promise<request<T>> {
|
||||
const requestHeaders = new headers(
|
||||
Object.fromEntries(nativeRequest.headers.entries()),
|
||||
);
|
||||
const requestMessage: request<T> = new request(
|
||||
<methodENUM>nativeRequest.method,
|
||||
new URL(nativeRequest.url),
|
||||
requestHeaders,
|
||||
await nativeRequest.text(),
|
||||
{},
|
||||
requestHeaders.get('CF-Connecting-IP') || '',
|
||||
);
|
||||
return requestMessage;
|
||||
}
|
||||
|
||||
async handleResponse(response: response<K>): Promise<Response> {
|
||||
if (response.status === 204) { response.body = null; }
|
||||
const nativResponse = new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: response.headers.headers,
|
||||
});
|
||||
return nativResponse;
|
||||
}
|
||||
async handleResponse(response: response<K>): Promise<Response> {
|
||||
if (response.status === 204) {
|
||||
response.body = null;
|
||||
}
|
||||
const nativResponse = new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: response.headers.headers,
|
||||
});
|
||||
return nativResponse;
|
||||
}
|
||||
|
||||
async handler(event: FetchEvent): Promise<Response> {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(event.request).then((request) =>
|
||||
this.router.respond(request)
|
||||
)
|
||||
)
|
||||
}
|
||||
async handler(event: FetchEvent): Promise<Response> {
|
||||
return await this.handleResponse(
|
||||
await this.handleRequest(event.request).then((request) =>
|
||||
this.router.respond(request),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { request } from "../../interface/request";
|
||||
import { response } from "../../interface";
|
||||
import { headers } from "../../interface/headers";
|
||||
import { methodENUM } from "../../interface/method";
|
||||
import { request } from '../../interface/request';
|
||||
import { response } from '../../interface';
|
||||
import { headers } from '../../interface/headers';
|
||||
import { methodENUM } from '../../interface/method';
|
||||
|
||||
import statusCode from "./statusCode.json";
|
||||
import statusCode from './statusCode.json';
|
||||
|
||||
export class HttpConn {
|
||||
private closed: boolean = false;
|
||||
@ -16,44 +16,63 @@ export class HttpConn {
|
||||
}
|
||||
|
||||
private readMessage(httpMessage: string): request<any> {
|
||||
const lines = httpMessage.split("\n");
|
||||
const lines = httpMessage.split('\n');
|
||||
const firstLine = lines[0];
|
||||
const dividingIndex = lines.indexOf("\r") ?? lines.indexOf("");
|
||||
const dividingIndex = lines.indexOf('\r') ?? lines.indexOf('');
|
||||
const rawHeaders = lines.slice(1, dividingIndex);
|
||||
|
||||
const [method, path, version] = firstLine.split(" ");
|
||||
const [method, path, version] = firstLine.split(' ');
|
||||
|
||||
if (version in ['HTTP/1.1', 'HTTP/1.0', 'HTTP/0.9']) {
|
||||
this.conn.close();
|
||||
}
|
||||
|
||||
const requestHeaders = new headers({});
|
||||
for (const header of rawHeaders) {
|
||||
const [key, value] = header.split(": ");
|
||||
const [key, value] = header.split(': ');
|
||||
requestHeaders.set(key, value);
|
||||
}
|
||||
|
||||
const url = new URL(path, `http://${requestHeaders.get("Host")}/` ?? `http://${this.conn.localAddress.ip}:${this.conn.localAddress.port}/`);
|
||||
const url = new URL(
|
||||
path,
|
||||
`http://${requestHeaders.get('Host')}/` ??
|
||||
`http://${this.conn.localAddress.ip}:${this.conn.localAddress.port}/`,
|
||||
);
|
||||
|
||||
const body = lines.slice(dividingIndex + 1).join("\n");
|
||||
const body = lines.slice(dividingIndex + 1).join('\n');
|
||||
|
||||
const requestMessage = new request<any>(<methodENUM>method, url, requestHeaders, body, {}, this.conn.remoteAddress.ip);
|
||||
const requestMessage = new request<any>(
|
||||
<methodENUM>method,
|
||||
url,
|
||||
requestHeaders,
|
||||
body,
|
||||
{},
|
||||
this.conn.remoteAddress.ip,
|
||||
);
|
||||
return requestMessage;
|
||||
}
|
||||
|
||||
private handleResponse(response: response<any>) {
|
||||
let responseMessage: string = "";
|
||||
responseMessage += "HTTP/1.1 " + response.status + " " + statusCode[<"100">response.status.toString()] ?? "";
|
||||
let responseMessage: string = '';
|
||||
responseMessage +=
|
||||
'HTTP/1.1 ' +
|
||||
response.status +
|
||||
' ' +
|
||||
statusCode[<'100'>response.status.toString()] ?? '';
|
||||
|
||||
response.headers.forEach((key, value) => {
|
||||
responseMessage += "\n" + key + ": " + value;
|
||||
responseMessage += '\n' + key + ': ' + value;
|
||||
});
|
||||
|
||||
responseMessage += "\n\n" + response.body;
|
||||
responseMessage += '\n\n' + response.body;
|
||||
|
||||
this.conn.write(new TextEncoder().encode(responseMessage));
|
||||
this.conn.shutdown();
|
||||
this.conn.close();
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
private async read(): Promise<request<any> | undefined> {
|
||||
let message = "";
|
||||
let message = '';
|
||||
const { done, value } = await this.reader.read();
|
||||
|
||||
if (done || this.closed) {
|
||||
@ -61,9 +80,15 @@ export class HttpConn {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
message += String.fromCharCode(...Object.values(<{
|
||||
[key: string]: number
|
||||
}>value));
|
||||
message += String.fromCharCode(
|
||||
...Object.values(
|
||||
<
|
||||
{
|
||||
[key: string]: number;
|
||||
}
|
||||
>value,
|
||||
),
|
||||
);
|
||||
|
||||
const requestMessage = this.readMessage(message);
|
||||
return requestMessage;
|
||||
@ -82,13 +107,13 @@ export class HttpConn {
|
||||
respondWith: (response: response<any>) => {
|
||||
httpConn.handleResponse(response);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default function serveHttp(Connection: tjs.Connection) {
|
||||
return new HttpConn(Connection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,4 +61,4 @@
|
||||
"509": "Bandwidth Limit Exceeded",
|
||||
"510": "Not Extended",
|
||||
"511": "Network Authentication Required"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { platformAdapater } from "./index";
|
||||
import { request } from "../interface/request";
|
||||
import { response } from "../interface/response";
|
||||
import { router } from "../router";
|
||||
import serveHttp from "./txiki-js/serveHttp";
|
||||
import { platformAdapater } from './index';
|
||||
import { request } from '../interface/request';
|
||||
import { response } from '../interface/response';
|
||||
import { router } from '../router';
|
||||
import serveHttp from './txiki-js/serveHttp';
|
||||
|
||||
export class TxikiPlatformAdapter<T = any, K = any> implements platformAdapater {
|
||||
export class TxikiPlatformAdapter<T = any, K = any>
|
||||
implements platformAdapater
|
||||
{
|
||||
public router: router<T, K>;
|
||||
|
||||
constructor(router: router<T, K>) {
|
||||
@ -12,13 +14,16 @@ export class TxikiPlatformAdapter<T = any, K = any> implements platformAdapater
|
||||
}
|
||||
|
||||
async listen(port?: number): Promise<void> {
|
||||
const Server = await tjs.listen("tcp", "0.0.0.0", port);
|
||||
const Server = await tjs.listen('tcp', '0.0.0.0', port);
|
||||
|
||||
for await (const conn of Server) {
|
||||
const httpConn = serveHttp(conn);
|
||||
|
||||
for await (const conn of httpConn) {
|
||||
if (typeof conn == "undefined" || typeof conn.request == "undefined") {
|
||||
if (
|
||||
typeof conn == 'undefined' ||
|
||||
typeof conn.request == 'undefined'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
conn.respondWith(await this.router.respond(conn.request));
|
||||
@ -33,4 +38,4 @@ export class TxikiPlatformAdapter<T = any, K = any> implements platformAdapater
|
||||
async handleResponse(response: response<K>): Promise<response<K>> {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
111
src/route.ts
111
src/route.ts
@ -1,71 +1,70 @@
|
||||
import { path } from "./interface";
|
||||
import handler from "./handler";
|
||||
import { pathToRegexp } from "path-to-regexp";
|
||||
import { path } from './interface';
|
||||
import handler from './handler';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
|
||||
interface matchedStatus {
|
||||
matched: boolean;
|
||||
attributes: {
|
||||
name: string;
|
||||
value: string | undefined;
|
||||
}[];
|
||||
matched: boolean;
|
||||
attributes: {
|
||||
name: string;
|
||||
value: string | undefined;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface regExpKey {
|
||||
name: string;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
pattern: string;
|
||||
modifier: string;
|
||||
};
|
||||
name: string;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
pattern: string;
|
||||
modifier: string;
|
||||
}
|
||||
|
||||
export class route {
|
||||
private paths: path[];
|
||||
public handlers: handler<any, any>[];
|
||||
private regExps: { regExp: RegExp, keys: regExpKey[] }[] = [];
|
||||
private paths: path[];
|
||||
public handlers: handler<any, any>[];
|
||||
private regExps: { regExp: RegExp; keys: regExpKey[] }[] = [];
|
||||
|
||||
constructor(paths: path[], handlers: handler<any, any>[]) {
|
||||
this.paths = paths;
|
||||
this.handlers = handlers;
|
||||
constructor(paths: path[], handlers: handler<any, any>[]) {
|
||||
this.paths = paths;
|
||||
this.handlers = handlers;
|
||||
|
||||
this.paths.forEach(path => {
|
||||
const keys: regExpKey[] = [];
|
||||
this.regExps.push({ regExp: pathToRegexp(path, keys), keys });
|
||||
})
|
||||
}
|
||||
async exec(path: string): Promise<matchedStatus> {
|
||||
let Answer = await Promise.all<Promise<matchedStatus>>(
|
||||
this.regExps.map(async (it) => {
|
||||
this.paths.forEach((path) => {
|
||||
const keys: regExpKey[] = [];
|
||||
this.regExps.push({ regExp: pathToRegexp(path, keys), keys });
|
||||
});
|
||||
}
|
||||
async exec(path: string): Promise<matchedStatus> {
|
||||
let Answer = await Promise.all<Promise<matchedStatus>>(
|
||||
this.regExps.map(async (it) => {
|
||||
const answer = it.regExp.exec(path);
|
||||
if (answer === null)
|
||||
return {
|
||||
matched: false,
|
||||
attributes: [],
|
||||
};
|
||||
|
||||
const answer = it.regExp.exec(path);
|
||||
if (answer === null)
|
||||
return {
|
||||
matched: false,
|
||||
attributes: [],
|
||||
};
|
||||
let attributes: matchedStatus['attributes'] = [];
|
||||
|
||||
let attributes: matchedStatus["attributes"] = [];
|
||||
it.keys.forEach((key, index) => {
|
||||
attributes.push({
|
||||
name: key.name,
|
||||
value: answer[index + 1],
|
||||
});
|
||||
});
|
||||
|
||||
it.keys.forEach((key, index) => {
|
||||
attributes.push({
|
||||
name: key.name,
|
||||
value: answer[index + 1],
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
matched: true,
|
||||
attributes: attributes,
|
||||
};
|
||||
})
|
||||
);
|
||||
Answer = Answer.filter((it) => it.matched);
|
||||
if (Answer.length === 0)
|
||||
return {
|
||||
matched: false,
|
||||
attributes: [],
|
||||
};
|
||||
else return Answer[0];
|
||||
}
|
||||
return {
|
||||
matched: true,
|
||||
attributes: attributes,
|
||||
};
|
||||
}),
|
||||
);
|
||||
Answer = Answer.filter((it) => it.matched);
|
||||
if (Answer.length === 0)
|
||||
return {
|
||||
matched: false,
|
||||
attributes: [],
|
||||
};
|
||||
else return Answer[0];
|
||||
}
|
||||
}
|
||||
|
||||
export default route;
|
||||
|
||||
403
src/router.ts
403
src/router.ts
@ -1,225 +1,238 @@
|
||||
import handler from "./handler";
|
||||
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";
|
||||
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";
|
||||
createPlatformAdapater,
|
||||
platformAdapaterConstructor,
|
||||
platformAdapater,
|
||||
} from './platform/index';
|
||||
import { platformAdapaterMapping } from './platform/export';
|
||||
import { platform } from './lib';
|
||||
|
||||
export class router<K = any, V = any> {
|
||||
public routes: route[];
|
||||
public routes: route[];
|
||||
|
||||
public errorResponder: (
|
||||
errorCode: number,
|
||||
errorMessage?: string
|
||||
) => responder<K, V>;
|
||||
public errorResponder: (
|
||||
errorCode: number,
|
||||
errorMessage?: string,
|
||||
) => responder<K, V>;
|
||||
|
||||
constructor(routes: route[] = []) {
|
||||
this.routes = routes;
|
||||
}
|
||||
constructor(routes: route[] = []) {
|
||||
this.routes = routes;
|
||||
}
|
||||
|
||||
add(route: route) {
|
||||
this.routes.push(route);
|
||||
return this;
|
||||
}
|
||||
add(route: route) {
|
||||
this.routes.push(route);
|
||||
return this;
|
||||
}
|
||||
|
||||
binding(path: path, handler: handler<K, V>) {
|
||||
this.add(new route([path], [handler]));
|
||||
return this;
|
||||
}
|
||||
binding(path: path, handler: handler<K, V>) {
|
||||
this.add(new route([path], [handler]));
|
||||
return this;
|
||||
}
|
||||
|
||||
create(
|
||||
method: method,
|
||||
responder: (
|
||||
request: request<K>
|
||||
) =>
|
||||
| Promise<response<V>>
|
||||
| Promise<string>
|
||||
| Promise<object>
|
||||
| Promise<number>
|
||||
| Promise<void>
|
||||
) {
|
||||
return new handler<K, V>(method, [
|
||||
async (request: request<K>) => {
|
||||
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);
|
||||
}
|
||||
},
|
||||
]);
|
||||
}
|
||||
create(
|
||||
method: method,
|
||||
responder: (
|
||||
request: request<K>,
|
||||
) =>
|
||||
| Promise<response<V>>
|
||||
| Promise<string>
|
||||
| Promise<object>
|
||||
| Promise<number>
|
||||
| Promise<void>,
|
||||
) {
|
||||
return new handler<K, V>(method, [
|
||||
async (request: request<K>) => {
|
||||
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());
|
||||
});
|
||||
}
|
||||
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;
|
||||
}
|
||||
route(path: path): router {
|
||||
const Router = new router([]);
|
||||
this.use([Router], path);
|
||||
return Router;
|
||||
}
|
||||
|
||||
async _respond(
|
||||
request: request<K>,
|
||||
responseMessage: response<V> = new response<V>("")
|
||||
): Promise<response<V>> {
|
||||
request.originURL = request.url;
|
||||
request.url.pathname = request.params["0"]
|
||||
? "/" + request.params["0"]
|
||||
: request.originURL.pathname;
|
||||
async _respond(
|
||||
request: request<K>,
|
||||
responseMessage: response<V> = new response<V>(''),
|
||||
): Promise<response<V>> {
|
||||
request.originURL = request.url;
|
||||
request.url.pathname = request.params['0']
|
||||
? '/' + request.params['0']
|
||||
: request.originURL.pathname;
|
||||
|
||||
let mismatchCount = 0;
|
||||
let mismatchCount = 0;
|
||||
|
||||
for (let route of this.routes) {
|
||||
const isMatched = await route.exec(request.url.pathname);
|
||||
for (let route of this.routes) {
|
||||
const isMatched = await route.exec(request.url.pathname);
|
||||
|
||||
if (!isMatched.matched) {
|
||||
mismatchCount++;
|
||||
continue;
|
||||
}
|
||||
if (!isMatched.matched) {
|
||||
mismatchCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
isMatched.attributes.forEach((e) => {
|
||||
request.params[e.name] = e.value;
|
||||
});
|
||||
isMatched.attributes.forEach((e) => {
|
||||
request.params[e.name] = e.value;
|
||||
});
|
||||
|
||||
try {
|
||||
let thisResponse: response<V> | 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
let thisResponse: response<V> | 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;
|
||||
}
|
||||
if (mismatchCount == this.routes.length) {
|
||||
throw AllMismatchInterrupted;
|
||||
}
|
||||
|
||||
return responseMessage;
|
||||
}
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
public respond = this._respond;
|
||||
public respond = this._respond;
|
||||
|
||||
toHandler(): handler<K, V> {
|
||||
return new handler(methodENUM.ANY, [
|
||||
(request: request<K>, responseMessage?: response<V>) => {
|
||||
return this.respond(request, responseMessage ?? new response(""));
|
||||
},
|
||||
]);
|
||||
}
|
||||
toHandler(): handler<K, V> {
|
||||
return new handler(methodENUM.ANY, [
|
||||
(request: request<K>, responseMessage?: response<V>) => {
|
||||
return this.respond(
|
||||
request,
|
||||
responseMessage ?? new response(''),
|
||||
);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
useErrorResponder(
|
||||
errorResponder: (
|
||||
errorCode: number,
|
||||
errorMessage?: string
|
||||
) => responder<K, V>
|
||||
): this {
|
||||
this.errorResponder = errorResponder;
|
||||
return this;
|
||||
}
|
||||
useErrorResponder(
|
||||
errorResponder: (
|
||||
errorCode: number,
|
||||
errorMessage?: string,
|
||||
) => responder<K, V>,
|
||||
): this {
|
||||
this.errorResponder = errorResponder;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default router;
|
||||
|
||||
export class rootRouter<K = any, V = any> extends router<K, V> {
|
||||
public adapater: platformAdapater<K, V>;
|
||||
errorResponder =
|
||||
(errorCode: number, errorMessage?: string) =>
|
||||
async (_request: request<K>): Promise<response<V>> =>
|
||||
new response(errorMessage ?? "", errorCode);
|
||||
public adapater: platformAdapater<K, V>;
|
||||
errorResponder =
|
||||
(errorCode: number, errorMessage?: string) =>
|
||||
async (_request: request<K>): Promise<response<V>> =>
|
||||
new response(errorMessage ?? '', errorCode);
|
||||
|
||||
respond = async (request: request<K>): Promise<response<V>> => {
|
||||
let responseMessage: response<V> = 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);
|
||||
}
|
||||
}
|
||||
respond = async (request: request<K>): Promise<response<V>> => {
|
||||
let responseMessage: response<V> = 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user