@koex/bootstrap
Version:
koex bootstrap
264 lines (262 loc) • 8.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.bootstrap = exports.Bootstrap = exports.getNetworkAddress = void 0;
const core_1 = require("@koex/core");
const boxen = require("boxen");
const chalk = require("chalk");
const os = require("os");
const interfaces = os.networkInterfaces();
function defineReadonlyProperties(target, properties) {
for (const propertyKey in properties) {
Object.defineProperty(target, propertyKey, {
enumerable: true,
get() {
return properties[propertyKey];
},
set(value) {
const targetName = (target.constructor && target.constructor.name) || 'unknown';
throw new Error(`Readonly property (${propertyKey}) in ${targetName}`);
},
});
}
}
const getNetworkAddress = () => {
for (const fields of Object.values(interfaces)) {
for (const interf of fields) {
const { address, family, internal } = interf;
if (family === 'IPv4' && !internal) {
return address;
}
}
}
};
exports.getNetworkAddress = getNetworkAddress;
function createTimer(name, logger = console) {
const start = process.hrtime();
return {
done: () => {
const d = process.hrtime(start);
const time = d[0] * 1e3 + d[1] / 1e6;
logger.info.apply(logger, [`[load][${name}]`, `+${time.toFixed(3)}ms`]);
},
};
}
class Bootstrap {
constructor(app = new core_1.default()) {
this.app = app;
this.composeLoaders = [];
if (!('bootInfo' in app)) {
const bootInfo = {
bootStartedAt: new Date(),
};
defineReadonlyProperties(app, {
bootInfo,
});
}
}
registerLoader(name, loader) {
this.composeLoaders.push({
name,
loader,
});
return this;
}
async runLoader(name, loader) {
const { app } = this;
const timer = createTimer(name, app.logger);
try {
await loader();
}
catch (error) {
app.logger.error(error);
}
finally {
timer.done();
}
}
extendsApplication(key, value) {
const { app } = this;
defineReadonlyProperties(app, {
[key]: value,
});
}
extendContext(key, value) {
const { app } = this;
app.use(async (ctx, next) => {
ctx[key] = value;
return await next();
});
}
extends(key, value, options) {
var _a, _b;
const isApp = (_a = options === null || options === void 0 ? void 0 : options.app) !== null && _a !== void 0 ? _a : true;
const isContext = (_b = options === null || options === void 0 ? void 0 : options.context) !== null && _b !== void 0 ? _b : false;
if (isApp) {
this.extendsApplication(key, value);
}
if (isContext) {
this.extendContext(key, value);
}
}
loadConfig(fn) {
const { app } = this;
this.registerLoader('config', async () => {
const config = await fn.apply(this, app);
if (config) {
this.extends('config', config, {
app: true,
context: true,
});
}
});
return this;
}
loadHelpers(fn) {
const { app } = this;
this.registerLoader('helpers', async () => {
const helpers = await fn.apply(this, app);
if (helpers) {
this.extends('helpers', helpers, {
app: false,
context: true,
});
}
});
return this;
}
loadMiddlewares(fn) {
const { app } = this;
this.registerLoader('middlewares', async () => {
const middlewares = await fn.apply(this, app);
if (middlewares) {
this.extends('middlewares', middlewares, {
app: true,
context: false,
});
}
});
return this;
}
loadModels(fn) {
const { app } = this;
this.registerLoader('models', async () => {
const models = await fn.apply(this, app);
if (models) {
this.extends('models', models, {
app: true,
context: true,
});
}
});
return this;
}
loadServices(fn) {
const { app } = this;
this.registerLoader('services', async () => {
const services = await fn.apply(this, app);
if (services) {
this.extends('services', services, {
app: true,
context: true,
});
}
});
return this;
}
loadControllers(fn) {
const { app } = this;
this.registerLoader('controllers', async () => {
const controllers = await fn.apply(this, app);
if (controllers) {
this.extends('controllers', controllers, {
app: true,
context: false,
});
}
});
return this;
}
loadRoutes(fn) {
const { app } = this;
this.registerLoader('routes', async () => {
const routes = await fn.apply(this, app);
if (routes) {
this.extends('routes', routes, {
app: true,
context: false,
});
}
});
return this;
}
async prepare() {
const { app, runLoader } = this;
for (const { name, loader } of this.composeLoaders) {
await runLoader.apply(this, [name, loader]);
}
return new Bootstrap(app);
}
showBootMessage(server, host, port) {
const { app } = this;
app.logger.info('[bootloader] start at:', app.bootInfo.bootStartedAt);
app.logger.info('[bootloader] load time:', `${app.bootInfo.bootTime.toFixed(3)}ms`);
app.logger.info('[bootloader] running at:', app.bootInfo.runningStartedAt);
const details = server.address();
const address = {
local: `http://${host}:${port}`,
network: 'unknown',
};
if (typeof details === 'string') {
address.local = details;
}
else {
const host = ['::', '0.0.0.0'].indexOf(details.address) !== -1
? 'localhost'
: details.address;
const port = details.port;
const ip = (0, exports.getNetworkAddress)();
address.local = `http://${host}:${port}`;
address.network = ip ? `http://${ip}:${port}` : 'unknown';
}
const message = `
${chalk.green('Serving!')}
- ${chalk.bold('Local')}: ${address.local}
- ${chalk.bold('On Your Network')}: ${address.network}
${chalk.grey('Copied local address to clipboard!')}
`;
console.log(boxen(message, {
padding: 1,
borderColor: 'green',
margin: 1,
}));
}
async startServer() {
const { app, showBootMessage } = this;
return new Promise((resolve, reject) => {
var _a, _b;
const port = ~~process.env.PORT || ((_a = app.config) === null || _a === void 0 ? void 0 : _a.port) || 8080;
const host = process.env.HOST || ((_b = app.config) === null || _b === void 0 ? void 0 : _b.host) || '127.0.0.1';
const server = app.listen(port, host, () => {
defineReadonlyProperties(app.bootInfo, {
bootTime: +new Date() - +app.bootInfo.bootStartedAt,
runningStartedAt: new Date(),
});
Object.defineProperty(app.bootInfo, 'uptime', {
enumerable: true,
get() {
return +new Date() - +app.bootInfo.runningStartedAt;
},
});
showBootMessage.apply(this, [server, host, port]);
resolve(server);
});
});
}
}
exports.Bootstrap = Bootstrap;
function bootstrap(app) {
return new Bootstrap(app);
}
exports.bootstrap = bootstrap;
exports.default = bootstrap;
//# sourceMappingURL=index.js.map