///
import {Server, createServer, IncomingMessage, ServerResponse} from 'http';
import {HttpRouter, HttpRouterGuard} from "./http.router";
import {HttpStatic, HttpStaticResource} from "./http.static";
import {HttpChannel} from "./http.channel";
export interface HttpServerDelegate {
staticConfig?: HttpStaticResource;
bootstrap?: () => void;
shutdown?: () => void;
onBootstrap?: () => void;
onShutdown?: () => void;
}
export interface HttpServerMetadata {
base: string;
port?: number;
host?: [number, number, number, number];
services?: any[];
static?: string[],
channels?: HttpChannel[];
guards?: HttpRouterGuard[];
}
export interface HttpIO {
request: IncomingMessage;
response: ServerResponse;
}
export class HttpServerFactory {
static create(options?: HttpServerMetadata) {
return new HttpServerFactory(Object.assign({
port: 8260,
host: [0, 0, 0, 0],
}, options));
}
protected context: Server;
protected delegate: HttpServerDelegate;
protected channels: HttpChannel[] = [];
protected router = HttpRouter.create();
protected static: HttpStatic;
protected constructor(protected options: HttpServerMetadata) {
if (this.options.channels) this.options.channels.forEach(channel => this.channel(channel));
if (this.options.guards) this.options.guards.forEach(guard => this.guard(guard));
if (this.options.services) this.options.services.forEach(service => this.service(service));
}
setDelegate(delegate: HttpServerDelegate) {
this.delegate = delegate;
this.static = HttpStatic.create(this.options.base, delegate.staticConfig);
this.options.static.forEach(path => this.static.set(path));
}
protected crossChannel(index: number, io: HttpIO) {
const endOrNull = this.channels.length === 0 || this.channels.length === index;
return endOrNull ? Promise.resolve(io) : this.channels[index++].handler(io).then(io => this.crossChannel(index, io));
}
bootstrap() {
this.context = createServer((request: IncomingMessage, response: ServerResponse) => {
let postData;
request.on("data", chunk => {
if (postData) {
postData += chunk;
} else {
postData = chunk;
}
});
request.on("end", () => {
if (postData) {
( request).data = postData.toString();
}
const io_$0 = {request: request, response: response};
// 先过滤静态资源的请求
this.static.cross(0, io_$0).then((io_$1: HttpIO) => {
// 再过滤请求
this.crossChannel(0, io_$1).then((io_$2: HttpIO) => {
// 最后导航到指定 endpoint 中
this.router.nav(io_$2).catch(err => console.log(err));
}).catch(err => console.log(err));
}).catch(err => console.log(err));
});
});
const port = this.options.port;
const host = this.options.host.join(".");
this.context.listen(port, host, () => {
console.log(`http://localhost:${port}`);
this.delegate.onBootstrap && this.delegate.onBootstrap();
});
}
channel(channel: HttpChannel) {
this.channels.push(channel);
}
guard(guard: HttpRouterGuard) {
this.router.addGuard(guard);
}
service(serviceClass: any) {
let service: any;
switch (typeof serviceClass) {
case "object":
service = serviceClass;
break;
case "function":
service = new serviceClass();
break;
default:
return;
}
this.router.addService(service);
}
shutdown() {
this.context.close(() => {
this.delegate.onShutdown && this.delegate.onShutdown();
});
}
}
export function HttpServer(metadata: HttpServerMetadata) {
const loader: any = ServerLoader;
loader.metadata = metadata;
return loader;
}
export class ServerLoader {
protected static metadata: HttpServerMetadata;
constructor(ServerClass) {
const context = HttpServerFactory.create(ServerLoader.metadata);
const delegate: HttpServerDelegate = new ServerClass();
context.setDelegate(delegate);
context.bootstrap();
}
}