@deepkit/framework
Version:
288 lines • 16 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebMemoryWorker = exports.WebWorker = exports.WebMemoryWorkerFactory = exports.WebWorkerFactory = exports.RpcServer = exports.__ΩRpcServerInterface = exports.__ΩRpcServerOptions = exports.__ΩRpcServerCreateConnection = exports.__ΩRpcServerListener = exports.__ΩWebServerOptions = void 0;
exports.createRpcConnection = createRpcConnection;
/*@ts-ignore*/
const { __ΩLoggerInterface } = require('@deepkit/logger');
/*@ts-ignore*/
const { __ΩTransportConnection } = require('@deepkit/rpc');
function __assignType(fn, args) {
fn.__type = args;
return fn;
}
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
const rpc_1 = require("@deepkit/rpc");
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const ws_1 = __importDefault(require("ws"));
const selfsigned_1 = __importDefault(require("selfsigned"));
const http_2 = require("@deepkit/http");
const injector_1 = require("@deepkit/injector");
const rpc_js_1 = require("./rpc.js");
// @ts-ignore
const path_1 = require("path");
const fs_1 = require("fs");
const core_1 = require("@deepkit/core");
// @ts-ignore
const compression_1 = __importDefault(require("compression"));
const zlib_1 = require("zlib");
const __ΩWebServerOptions = ['host', 'port', 'varPath', 'compression', 'httpsPort', () => http_2.HttpConfig, 'http', 'server', 'gracefulShutdownTimeout', 'ssl', 'sslKey', 'sslCertificate', 'sslCa', 'sslCrl', 'sslOptions', 'selfSigned', 'WebServerOptions', 'P&4!\'4"&4#\'4$\'4%8P7&4\'!4(8\'4))4*&4+8&4,8&4-8&4.8P!!K4/8)408Mw1y'];
exports.__ΩWebServerOptions = __ΩWebServerOptions;
const __ΩRpcServerListener = ['close', 'RpcServerListener', 'PPP$$`J1!Mw"y'];
exports.__ΩRpcServerListener = __ΩRpcServerListener;
const __ΩRpcServerCreateConnection = [() => __ΩTransportConnection, 'transport', () => http_2.HttpRequest, 'request', () => rpc_1.RpcKernelBaseConnection, '', 'RpcServerCreateConnection', 'PPn!2"P7#2$8P7%v&Mw\'y'];
exports.__ΩRpcServerCreateConnection = __ΩRpcServerCreateConnection;
const __ΩRpcServerOptions = ['server', 'RpcServerOptions', 'PP!!J4!8Mw"y'];
exports.__ΩRpcServerOptions = __ΩRpcServerOptions;
const __ΩRpcServerInterface = [() => __ΩRpcServerOptions, 'options', () => __ΩRpcServerCreateConnection, 'createRpcConnection', 'start', 'RpcServerInterface', 'PPn!2"n#2$$1%Mw&y'];
exports.__ΩRpcServerInterface = __ΩRpcServerInterface;
class RpcServer {
start(options, createRpcConnection) {
const { Server } = ws_1.default;
const server = new Server(options);
server.on('connection', __assignType((ws, req) => {
const connection = createRpcConnection({
writeBinary: __assignType(function writeBinary(message) {
ws.send(message);
}, ['message', 'writeBinary', 'P"2!"/"']),
close: __assignType(function close() {
ws.close();
}, ['close', 'P"/!']),
bufferedAmount: __assignType(function bufferedAmount() {
return ws.bufferedAmount;
}, ['bufferedAmount', 'P\'/!']),
clientAddress: __assignType(function clientAddress() {
return req.getRemoteAddress();
}, ['clientAddress', 'P&/!'])
}, req);
ws.on('message', __assignType((message) => {
connection.feed(message);
}, ['message', '', 'PW2!"/"']));
ws.on('error', __assignType((error) => {
connection.close(error);
}, ['error', '', 'P"2!"/"']));
ws.on('close', () => {
connection.close();
});
}, ['ws', () => http_2.HttpRequest, 'req', '', 'P"2!P7"2#"/$']));
return {
close: __assignType(function close() {
server.close();
}, ['close', 'P"/!'])
};
}
}
exports.RpcServer = RpcServer;
RpcServer.__type = [() => __ΩRpcServerOptions, 'options', () => __ΩRpcServerCreateConnection, 'createRpcConnection', () => __ΩRpcServerListener, 'start', () => __ΩRpcServerInterface, 'RpcServer', 'Pn!2"n#2$n%0&5n\'x"w('];
class WebWorkerFactory {
constructor(httpKernel, logger, rpcControllers, injectorContext, rpcServer, rpcKernel) {
this.httpKernel = httpKernel;
this.logger = logger;
this.rpcControllers = rpcControllers;
this.injectorContext = injectorContext;
this.rpcServer = rpcServer;
this.rpcKernel = rpcKernel;
}
create(id, options) {
return new WebWorker(id, this.logger, this.httpKernel, this.rpcKernel, this.injectorContext, options, this.rpcServer);
}
}
exports.WebWorkerFactory = WebWorkerFactory;
WebWorkerFactory.__type = [() => http_2.HttpKernel, 'httpKernel', () => __ΩLoggerInterface, 'logger', () => rpc_js_1.RpcControllers, 'rpcControllers', () => injector_1.InjectorContext, 'injectorContext', () => RpcServer, 'rpcServer', () => rpc_1.RpcKernel, 'rpcKernel', 'constructor', 'id', () => __ΩWebServerOptions, 'options', () => WebWorker, 'create', 'WebWorkerFactory', 'PP7!2"<n#2$:P7%2&<P7\'2(<P7)2*<P7+2,<"0-P\'2.n/20P71025w3'];
class WebMemoryWorkerFactory extends WebWorkerFactory {
create(id, options) {
return new WebMemoryWorker(id, this.logger, this.httpKernel, this.rpcKernel, this.injectorContext, options, this.rpcServer);
}
}
exports.WebMemoryWorkerFactory = WebMemoryWorkerFactory;
WebMemoryWorkerFactory.__type = [() => WebWorkerFactory, 'id', () => __ΩWebServerOptions, 'options', () => WebMemoryWorker, 'create', 'WebMemoryWorkerFactory', 'P7!P\'2"n#2$P7%0&5w\''];
function createRpcConnection(rootScopedContext, rpcKernel, transport, request) {
const injector = rootScopedContext.createChildScope('rpc');
injector.set(http_2.HttpRequest, request);
injector.set(rpc_js_1.RpcInjectorContext, injector);
const connection = rpcKernel.createConnection(transport, injector);
injector.set(rpc_1.SessionState, connection.sessionState);
injector.set(rpc_1.RpcKernelConnection, connection);
injector.set(rpc_1.RpcKernelBaseConnection, connection);
return connection;
}
createRpcConnection.__type = [() => injector_1.InjectorContext, 'rootScopedContext', () => rpc_1.RpcKernel, 'rpcKernel', () => __ΩTransportConnection, 'transport', () => http_2.HttpRequest, 'request', 'createRpcConnection', 'PP7!2"P7#2$n%2&P7\'2(8"/)'];
class WebWorker {
constructor(id, logger, httpKernel, rpcKernel, injectorContext, options, rpcServer) {
this.id = id;
this.logger = logger;
this.httpKernel = httpKernel;
this.rpcKernel = rpcKernel;
this.injectorContext = injectorContext;
this.options = options;
this.rpcServer = rpcServer;
//during shutdown, we don't want to accept new connections
this.shuttingDown = false;
this.activeRequests = 0;
this.compressionOptions = {
level: 0,
chunkSize: zlib_1.constants.Z_DEFAULT_CHUNK,
memLevel: zlib_1.constants.Z_DEFAULT_MEMLEVEL,
strategy: zlib_1.constants.Z_DEFAULT_STRATEGY,
windowBits: zlib_1.constants.Z_DEFAULT_WINDOWBITS,
};
this.handleRequest = this.handleRequest.bind(this);
if (this.options.compression) {
this.compressionOptions.level = this.options.compression;
}
}
handleRequest(request, response) {
if (this.shuttingDown) {
response.writeHead(503, 'Service Unavailable');
response.end();
return;
}
if (this.compressionOptions.level > 0) {
// this modifies response object, so it must be called before any data is written
(0, compression_1.default)(this.compressionOptions)(request, response, () => undefined);
}
this.activeRequests++;
response.on('close', () => {
this.activeRequests--;
});
return this.httpKernel.handleRequest(request, response);
}
applyServerSettings(server) {
const config = this.options.http;
if ('undefined' !== typeof config.timeout)
server.timeout = config.timeout;
if ('undefined' !== typeof config.requestTimeout)
server.requestTimeout = config.requestTimeout;
if ('undefined' !== typeof config.headersTimeout)
server.headersTimeout = config.headersTimeout;
if ('undefined' !== typeof config.maxHeadersCount)
server.maxHeadersCount = config.maxHeadersCount;
if ('undefined' !== typeof config.keepAliveTimeout)
server.keepAliveTimeout = config.keepAliveTimeout;
if ('undefined' !== typeof config.maxRequestsPerSocket)
server.maxRequestsPerSocket = config.maxRequestsPerSocket;
}
start() {
if (this.options.server) {
this.server = this.options.server;
this.server.on('request', this.handleRequest);
}
else {
if (this.options.ssl) {
const options = this.options.sslOptions || {};
if (this.options.selfSigned) {
const keyPath = (0, path_1.join)(this.options.varPath, `self-signed-${this.options.host}.key`);
const certificatePath = (0, path_1.join)(this.options.varPath, `self-signed-${this.options.host}.cert`);
if ((0, fs_1.existsSync)(keyPath) && (0, fs_1.existsSync)(certificatePath)) {
options.key = (0, fs_1.readFileSync)(keyPath, 'utf8');
options.cert = (0, fs_1.readFileSync)(certificatePath, 'utf8');
}
else {
const attrs = [{ name: 'commonName', value: this.options.host }];
const pems = selfsigned_1.default.generate(attrs, { days: 365 });
options.cert = pems.cert;
options.key = pems.private;
(0, fs_1.writeFileSync)(keyPath, pems.private, 'utf8');
(0, fs_1.writeFileSync)(certificatePath, pems.cert, 'utf8');
this.logger.log(`Self signed certificate for ${this.options.host} created at ${certificatePath}`);
this.logger.log(`Tip: If you want to open this server via chrome for localhost, use chrome://flags/#allow-insecure-localhost`);
}
}
if (!options.key && this.options.sslKey)
options.key = (0, fs_1.readFileSync)(this.options.sslKey, 'utf8');
if (!options.ca && this.options.sslCa)
options.ca = (0, fs_1.readFileSync)(this.options.sslCa, 'utf8');
if (!options.cert && this.options.sslCertificate)
options.cert = (0, fs_1.readFileSync)(this.options.sslCertificate, 'utf8');
if (!options.crl && this.options.sslCrl)
options.crl = (0, fs_1.readFileSync)(this.options.sslCrl, 'utf8');
this.servers = new https_1.default.Server(Object.assign({ IncomingMessage: http_2.HttpRequest, ServerResponse: http_2.HttpResponse, }, options), this.handleRequest);
this.servers.requestTimeout;
this.servers.listen(this.options.httpsPort || this.options.port, this.options.host);
}
const startHttpServer = !this.servers || (this.servers && this.options.httpsPort);
if (startHttpServer) {
this.server = new http_1.default.Server({ IncomingMessage: http_2.HttpRequest, ServerResponse: http_2.HttpResponse }, this.handleRequest);
this.server.listen(this.options.port, this.options.host);
}
}
if (this.servers)
this.applyServerSettings(this.servers);
if (this.server)
this.applyServerSettings(this.server);
this.startRpc();
}
startRpc() {
if (this.server) {
this.rpcListener = this.rpcServer.start({ server: this.server }, __assignType((transport, request) => {
if (this.shuttingDown) {
transport.close();
throw new Error('Server is shutting down');
}
return createRpcConnection(this.injectorContext, this.rpcKernel, transport, request);
}, ['transport', () => http_2.HttpRequest, 'request', '', 'P"2!P7"2#8"/$']));
}
if (this.servers) {
this.rpcListener = this.rpcServer.start({ server: this.servers }, __assignType((transport, request) => {
if (this.shuttingDown) {
transport.close();
throw new Error('Server is shutting down');
}
return createRpcConnection(this.injectorContext, this.rpcKernel, transport, request);
}, ['transport', () => http_2.HttpRequest, 'request', '', 'P"2!P7"2#8"/$']));
}
}
async close(graceful = false) {
if (graceful) {
if (this.options.server && this.server) {
this.server.off('request', this.handleRequest);
}
this.shuttingDown = true;
//wait until all http requests are finished
if (this.activeRequests) {
this.logger.log(`Waiting ${this.options.gracefulShutdownTimeout}s for all ${this.activeRequests} http requests to finish ...`);
const started = Date.now();
while (this.activeRequests) {
//if timeout is exceeded
if (this.options.gracefulShutdownTimeout && (Date.now() - started) / 1000 > this.options.gracefulShutdownTimeout) {
this.logger.log(`Timeout of ${this.options.gracefulShutdownTimeout}s exceeded. Closing ${this.activeRequests} open http requests.`);
break;
}
await (0, core_1.sleep)(0.1);
}
}
}
if (this.rpcListener)
await this.rpcListener.close();
if (this.server)
this.server.close();
if (this.servers)
this.servers.close();
}
}
exports.WebWorker = WebWorker;
WebWorker.__type = [() => __ΩRpcServerListener, 'rpcListener', 'server', 'servers', 'shuttingDown', function () { return false; }, 'activeRequests', function () { return 0; }, 'compressionOptions', function () { return {
level: 0,
chunkSize: zlib_1.constants.Z_DEFAULT_CHUNK,
memLevel: zlib_1.constants.Z_DEFAULT_MEMLEVEL,
strategy: zlib_1.constants.Z_DEFAULT_STRATEGY,
windowBits: zlib_1.constants.Z_DEFAULT_WINDOWBITS,
}; }, 'id', () => __ΩLoggerInterface, 'logger', () => http_2.HttpKernel, 'httpKernel', () => rpc_1.RpcKernel, 'rpcKernel', () => injector_1.InjectorContext, 'injectorContext', () => __ΩWebServerOptions, 'options', () => RpcServer, 'rpcServer', 'constructor', () => http_2.HttpRequest, 'request', () => http_2.HttpResponse, 'response', 'handleRequest', 'applyServerSettings', 'start', 'startRpc', 'graceful', 'close', 'WebWorker', 'n!3"8<P!!J3#8<!3$8<)3%<>&\'3\'<>(!3)<>*P\'2+:9n,2-:P7.2/:P7021:P7223<n425<P7627;"08PP792:P7;2<"0=P!2#"0>P"0?P"0@;P"2A"0B5wC'];
class WebMemoryWorker extends WebWorker {
start() {
}
}
exports.WebMemoryWorker = WebMemoryWorker;
WebMemoryWorker.__type = [() => WebWorker, 'start', 'WebMemoryWorker', 'P7!P"0"5w#'];
//# sourceMappingURL=worker.js.map