UNPKG

@deepkit/framework

Version:

288 lines 16 kB
"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