Init server and http-server

This commit is contained in:
Alexandre Bodin 2021-09-01 16:00:24 +02:00
parent 76d1ac7ada
commit bc2760f14f
5 changed files with 208 additions and 74 deletions

View File

@ -1,14 +1,12 @@
'use strict';
const Koa = require('koa');
const Router = require('koa-router');
const _ = require('lodash');
const { createLogger } = require('@strapi/logger');
const { Database } = require('@strapi/database');
const loadConfiguration = require('./core/app-configuration');
const { createHTTPServer } = require('./server');
const { createServer } = require('./server');
const { createContainer } = require('./container');
const utils = require('./utils');
const initializeMiddlewares = require('./middlewares');
@ -57,9 +55,8 @@ class Strapi {
this.isLoaded = false;
this.reload = this.reload();
this.app = new Koa();
this.router = new Router();
this.server = createHTTPServer(this, this.app);
this.server = createServer(strapi);
this.fs = createStrapiFs(this);
this.eventHub = createEventHub();
this.startupLogger = createStartupLogger(this);

View File

@ -0,0 +1,64 @@
'use strict';
const http = require('http');
const createHTTPServer = (strapi, koaApp) => {
const connections = new Set();
// lazy creation of the request listener
let handler;
const listener = function handleRequest(req, res) {
if (!handler) {
handler = koaApp.callback();
}
return handler(req, res);
};
const server = http.createServer(listener);
server.on('connection', connection => {
connections.add(connection);
connection.on('close', () => {
connections.delete(connection);
});
});
// handle port in use cleanly
server.on('error', err => {
if (err.code === 'EADDRINUSE') {
return strapi.stopWithError(`The port ${err.port} is already used by another application.`);
}
strapi.log.error(err);
});
server.destroy = async () => {
for (const connection of connections) {
connection.destroy();
connections.delete(connection);
}
if (!server.listening) {
return;
}
return new Promise((resolve, reject) =>
server.close(error => {
if (error) {
return reject(error);
}
resolve();
})
);
};
return server;
};
module.exports = {
createHTTPServer,
};

View File

@ -1,64 +1,129 @@
'use strict';
const http = require('http');
const Koa = require('koa');
const Router = require('@koa/router');
const mount = require('koa-mount');
const createHTTPServer = (strapi, koaApp) => {
const connections = new Set();
const { createHTTPServer } = require('./http-server');
// lazy creation of the request listener
let handler;
const listener = function handleRequest(req, res) {
if (!handler) {
handler = koaApp.callback();
}
return handler(req, res);
const createRoute = (route, router) => {
router[route.method.toLowerCase()](route.path, route.handler);
};
const server = http.createServer(listener);
// TODO: connect to compose Endpoint
const addRoutes = (routes, app) => {
if (Array.isArray(routes)) {
const router = new Router();
server.on('connection', connection => {
connections.add(connection);
routes.forEach(route => createRoute(route, router));
connection.on('close', () => {
connections.delete(connection);
});
});
// handle port in use cleanly
server.on('error', err => {
if (err.code === 'EADDRINUSE') {
return strapi.stopWithError(`The port ${err.port} is already used by another application.`);
return app.use(router.routes()).use(router.allowedMethods());
}
strapi.log.error(err);
});
if (routes.routes) {
const router = new Router({ prefix: routes.prefix });
server.destroy = async () => {
for (const connection of connections) {
connection.destroy();
routes.routes.forEach(route => createRoute(route, router));
connections.delete(connection);
app.use(router.routes()).use(router.allowedMethods());
}
if (!server.listening) {
return;
}
return new Promise((resolve, reject) =>
server.close(error => {
if (error) {
return reject(error);
}
resolve();
})
);
};
return server;
const createAPI = prefix => {
const app = new Koa();
return {
prefix,
use(fn) {
app.use(fn);
return this;
},
routes(routes) {
addRoutes(routes, app);
return this;
},
get middleware() {
return app;
},
};
};
/**
* @typedef Server
*
* @property {Koa} app
* @property {http.Server} app
*/
/**
*
* @param {Strapi} strapi
* @returns {Server}
*/
const createServer = strapi => {
const app = new Koa();
const httpServer = createHTTPServer(strapi, this.app);
const apis = {
admin: createAPI('admin'),
'content-api': createAPI('api'),
};
return {
app,
httpServer,
/**
* Add a middleware to the main koa app or an api
* @param {string|function} path
* @param {function} fn
* @returns {Server}
*/
use(path, fn) {
if (typeof path === 'function') {
app.use(path);
return this;
}
if (typeof path === 'string') {
apis[path].use(fn);
return this;
}
throw new Error('Use expects to be called with (fn) or (name, callback)');
},
routes(routes) {
if (routes.type) {
const api = apis[routes.type];
if (!api) {
throw new Error(`API ${routes.type} not found. Possible APIs are ${Object.keys(apis)}`);
}
apis[routes.type].routes(routes);
return this;
}
addRoutes(routes, app);
return this;
},
start(args) {
Object.values(apis).forEach(api => {
app.use(mount(`/${api.prefix}`, api.app));
});
return httpServer.listen(...args);
},
async destroy() {
await this.httpServer.destroy();
},
};
};
module.exports = {
createHTTPServer,
createServer,
};

View File

@ -14,10 +14,11 @@
},
"dependencies": {
"@koa/cors": "^3.0.0",
"@koa/router": "10.1.1",
"@strapi/admin": "3.6.8",
"@strapi/database": "3.6.8",
"@strapi/generators": "3.6.8",
"@strapi/generate-new": "3.6.8",
"@strapi/generators": "3.6.8",
"@strapi/logger": "3.6.8",
"@strapi/plugin-content-manager": "3.6.8",
"@strapi/plugin-content-type-builder": "3.6.8",
@ -52,7 +53,7 @@
"koa-i18n": "^2.1.0",
"koa-ip": "^2.0.0",
"koa-locale": "~1.3.0",
"koa-router": "^7.4.0",
"koa-mount": "4.0.0",
"koa-session": "^6.2.0",
"koa-static": "^5.0.0",
"lodash": "4.17.21",

View File

@ -1932,6 +1932,17 @@
dependencies:
vary "^1.1.2"
"@koa/router@10.1.1":
version "10.1.1"
resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78"
integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==
dependencies:
debug "^4.1.1"
http-errors "^1.7.3"
koa-compose "^4.1.0"
methods "^1.1.2"
path-to-regexp "^6.1.0"
"@lerna/add@3.21.0":
version "3.21.0"
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.21.0.tgz#27007bde71cc7b0a2969ab3c2f0ae41578b4577b"
@ -10778,7 +10789,7 @@ http-errors@1.7.3, http-errors@~1.7.2:
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-errors@^1.3.1, http-errors@^1.6.3, http-errors@^1.7.3:
http-errors@^1.6.3, http-errors@^1.7.3:
version "1.8.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
@ -12895,6 +12906,14 @@ koa-locale@~1.3.0:
dependencies:
delegates "1.0.0"
koa-mount@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-4.0.0.tgz#e0265e58198e1a14ef889514c607254ff386329c"
integrity sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==
dependencies:
debug "^4.0.1"
koa-compose "^4.1.0"
koa-passport@4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa"
@ -12909,18 +12928,6 @@ koa-range@0.3.0:
dependencies:
stream-slice "^0.1.2"
koa-router@^7.4.0:
version "7.4.0"
resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0"
integrity sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==
dependencies:
debug "^3.1.0"
http-errors "^1.3.1"
koa-compose "^3.0.0"
methods "^1.0.1"
path-to-regexp "^1.1.1"
urijs "^1.19.0"
koa-send@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
@ -14065,7 +14072,7 @@ merge2@^1.2.3, merge2@^1.3.0:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
methods@1.1.2, methods@^1.0.1, methods@^1.1.2, methods@~1.1.2:
methods@1.1.2, methods@^1.1.2, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
@ -15893,7 +15900,7 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-to-regexp@^1.1.1, path-to-regexp@^1.7.0:
path-to-regexp@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
@ -15905,6 +15912,11 @@ path-to-regexp@^3.1.0:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f"
integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==
path-to-regexp@^6.1.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@ -20976,11 +20988,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
urijs@^1.19.0:
version "1.19.7"
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.7.tgz#4f594e59113928fea63c00ce688fb395b1168ab9"
integrity sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"