silvie
Version:
Typescript Back-end Framework
311 lines (305 loc) • 12.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _http = _interopRequireDefault(require("http"));
var _https = _interopRequireDefault(require("https"));
var _spdy = _interopRequireDefault(require("spdy"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _cors = _interopRequireDefault(require("cors"));
var _multer = _interopRequireDefault(require("multer"));
var _bodyParser = _interopRequireDefault(require("body-parser"));
var _cookieParser = _interopRequireDefault(require("cookie-parser"));
var _express = _interopRequireDefault(require("express"));
var _middleware = require("../middleware");
var _expressSession = _interopRequireDefault(require("express-session"));
var _uuid = require("uuid");
var _redis = _interopRequireDefault(require("redis"));
var _connectRedis = _interopRequireDefault(require("connect-redis"));
var _sessionFileStore = _interopRequireDefault(require("session-file-store"));
var _log = _interopRequireDefault(require("../../utils/log"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
const config = process.configs.http;
class HTTPServer {
constructor() {
_defineProperty(this, "app", void 0);
_defineProperty(this, "srv", void 0);
_defineProperty(this, "upload", void 0);
_defineProperty(this, "globalMiddlewares", []);
_defineProperty(this, "routes", []);
}
/**
* Initialize a new HTTP Server
*/
init(instanceCallback) {
let app = (0, _express.default)();
app.disable('x-powered-by');
if (config.trustProxy) {
app.set('trust proxy', 1);
}
if (instanceCallback instanceof Function) {
app = instanceCallback(app);
}
this.app = app;
this.initCORS();
this.initBodyParser();
this.initCookie();
this.initSession();
this.initUploads();
this.initGlobalMiddlewares();
this.initStatics();
this.initRoutes();
this.initServer();
}
initCORS() {
if (config.cors.enabled) {
this.app.use((0, _cors.default)({
origin: config.cors.originsAllowed,
methods: config.cors.methodsAllowed,
allowedHeaders: config.cors.headersAllowed,
exposedHeaders: config.cors.headersAllowed,
credentials: config.cors.allowCredentials,
maxAge: config.cors.maxAge,
preflightContinue: config.cors.continuePreflight,
optionsSuccessStatus: config.cors.optionsSuccessStatus
}));
}
}
initBodyParser() {
if (config.body.enabled && config.body.parsers instanceof Array) {
config.body.parsers.forEach(parser => {
if (parser.type === 'json') {
var _parser$options;
this.app.use(_bodyParser.default.json({
limit: parser.limit,
inflate: parser.inflate,
type: parser.mime,
strict: ((_parser$options = parser.options) === null || _parser$options === void 0 ? void 0 : _parser$options.strict) || false
}));
}
if (parser.type === 'urlencoded') {
var _parser$options2, _parser$options3;
this.app.use(_bodyParser.default.urlencoded({
inflate: parser.inflate,
limit: parser.limit,
type: parser.mime,
extended: ((_parser$options2 = parser.options) === null || _parser$options2 === void 0 ? void 0 : _parser$options2.extended) || false,
parameterLimit: ((_parser$options3 = parser.options) === null || _parser$options3 === void 0 ? void 0 : _parser$options3.parameterLimit) || 1000
}));
}
if (parser.type === 'text') {
var _parser$options4;
this.app.use(_bodyParser.default.text({
inflate: parser.inflate,
limit: parser.limit,
type: parser.mime,
defaultCharset: (_parser$options4 = parser.options) === null || _parser$options4 === void 0 ? void 0 : _parser$options4.defaultCharset
}));
}
if (parser.type === 'raw') {
this.app.use(_bodyParser.default.raw({
inflate: parser.inflate,
limit: parser.limit,
type: parser.mime
}));
}
});
}
}
initSession() {
if (config.session.enabled) {
if (config.cookie.enabled && config.cookie.secret !== config.session.secret) {
throw new Error('Cookie and Session secrets do not match');
}
let store;
if (config.session.driver === 'file') {
const FileStore = (0, _sessionFileStore.default)(_expressSession.default);
store = new FileStore({
path: _path.default.resolve(process.rootPath, `.silvie/${config.session.driverOptions.file.path}`),
extension: config.session.driverOptions.file.extension,
ttl: config.session.driverOptions.file.ttl
});
} else if (config.session.driver === 'redis') {
const RedisStore = (0, _connectRedis.default)(_expressSession.default);
const redisClient = _redis.default.createClient();
store = new RedisStore({
client: redisClient,
host: config.session.driverOptions.redis.host || process.env.REDIS_HOST,
port: config.session.driverOptions.redis.port || process.env.REDIS_PORT,
password: config.session.driverOptions.redis.password || process.env.REDIS_PASSWORD,
ttl: config.session.driverOptions.redis.ttl,
prefix: config.session.driverOptions.redis.prefix
});
} else {
throw new Error(`Invalid session driver '${config.session.driver}'`);
}
this.app.use((0, _expressSession.default)({
genid: () => (0, _uuid.v4)(),
secret: config.session.secret || process.env.APP_KEY,
resave: config.session.reSave,
saveUninitialized: config.session.saveUninitialized,
unset: config.session.unsetAction,
trustProxy: config.session.trustProxy,
store,
name: config.session.cookie.name
}));
}
}
initCookie() {
if (config.cookie.enabled) {
if (config.session.enabled && config.session.secret !== config.cookie.secret) {
throw new Error('Cookie and Session secrets do not match');
}
this.app.use((0, _cookieParser.default)(config.cookie.secret || process.env.APP_KEY));
}
}
initUploads() {
if (config.uploads.enabled) {
this.upload = (0, _multer.default)({
dest: _path.default.resolve(process.rootPath, `.silvie/${config.uploads.tempDirectory}`),
limits: {
fieldSize: config.uploads.maxFileSize
}
});
}
}
initStatics() {
config.statics.forEach(statics => {
var _statics$alias;
this.app.use((_statics$alias = statics.alias) !== null && _statics$alias !== void 0 ? _statics$alias : '/', _express.default.static(_path.default.resolve(process.rootPath, statics.path), {
cacheControl: statics.options.cacheControl,
dotfiles: statics.options.dotfiles,
etag: statics.options.etag,
extensions: statics.options.extensions,
immutable: statics.options.immutable,
index: statics.options.index,
lastModified: statics.options.lastModified,
maxAge: statics.options.maxAge,
redirect: statics.options.redirect
}));
});
}
initGlobalMiddlewares() {
this.globalMiddlewares.forEach(middlewareName => {
if (middlewareName in _middleware.middlewares) {
this.app.use(_middleware.middlewares[middlewareName]);
} else {
throw new Error(`Unknown global middleware '${middlewareName}'`);
}
});
}
initRoutes() {
this.routes.forEach(route => {
const middlewareHandlers = route.middlewares.map(middlewareName => {
if (middlewareName in _middleware.middlewares) {
return _middleware.middlewares[middlewareName];
}
throw new Error(`Used unknown middleware '${middlewareName}' for route '${route.method.toUpperCase()} ${route.url}'`);
});
if (route.upload) {
if (route.upload.action === 'block') {
middlewareHandlers.push(this.upload.none());
} else if (route.upload.action === 'any') {
middlewareHandlers.push(this.upload.any());
} else if (route.upload.action === 'multiple') {
middlewareHandlers.push(this.upload.fields(route.upload.options));
} else if (route.upload.action === 'array') {
middlewareHandlers.push(this.upload.array(route.upload.options.fieldName, route.upload.options.maxCount));
} else if (route.upload.action === 'single') {
middlewareHandlers.push(this.upload.single(route.upload.options));
} else {
throw new Error(`Invalid upload type '${route.upload.action}' for route '${route.method.toUpperCase()} ${route.url}'`);
}
}
this.app[route.method](route.url, middlewareHandlers, route.handler);
});
}
initServer() {
let server = null;
if (config.HTTP2) {
if (!config.ssl.enabled) {
throw new Error('You have to enable SSL for HTTP/2');
}
if (!config.ssl.keyFile || !_fs.default.existsSync(config.ssl.keyFile)) {
throw new Error('Missing SSL Key file');
}
if (!config.ssl.certFile || !_fs.default.existsSync(config.ssl.certFile)) {
throw new Error('Missing SSL Cert file');
}
server = _spdy.default.createServer({
key: _fs.default.readFileSync(config.ssl.keyFile),
cert: _fs.default.readFileSync(config.ssl.certFile),
passphrase: config.ssl.passphrase
}, this.app);
} else if (config.ssl.enabled) {
if (!config.ssl.keyFile || !_fs.default.existsSync(config.ssl.keyFile)) {
throw new Error('Missing SSL Key file');
}
if (!config.ssl.certFile || !_fs.default.existsSync(config.ssl.certFile)) {
throw new Error('Missing SSL Cert file');
}
server = _https.default.createServer({
key: _fs.default.readFileSync(config.ssl.keyFile),
cert: _fs.default.readFileSync(config.ssl.certFile),
passphrase: config.ssl.passphrase
}, this.app);
} else {
server = _http.default.createServer(this.app);
}
this.srv = server;
}
/**
* Return express server instance
*/
get expressServer() {
return this.app;
}
/**
* Return HTTP server instance
*/
get server() {
return this.srv;
}
/**
* Registers a route handler with some middlewares
* @param method HTTP Verb
* @param url Route URL
* @param routeMiddlewares Route middlewares array
* @param upload Upload configuration
* @param handler Route handler
*/
registerRoute(method, url, routeMiddlewares = [], upload = null, handler) {
this.routes.push({
method,
url,
middlewares: routeMiddlewares,
upload,
handler
});
}
/**
* Registers a middleware on the whole HTTP Server
* @param middlewareName The name middleware to register
*/
globalMiddleware(middlewareName) {
this.globalMiddlewares.push(middlewareName);
}
/**
* Starts listening on a port in this order: --port, -p, .env.APP_PORT, config.port, customPort
*/
start(customPort = 5000, customHost = '0.0.0.0') {
const port = process.args.port || process.args.p || process.env.APP_PORT || config.port || customPort;
const host = process.args.host || process.args.h || process.env.APP_HOST || config.host || customHost;
this.srv.listen(port, host, error => {
if (error) _log.default.error('Server Start Failed', 'An error occurred');
_log.default.success('Server Started', `on http${config.HTTP2 || config.ssl.enabled ? 's' : ''}://${host}:${port}`);
});
}
}
const server = new HTTPServer();
var _default = exports.default = server;