@n1k1t/mock-server
Version:
The ultimate toolkit to intercept, transform, and simulate HTTP/WS traffic with type-safe expectations
174 lines • 8.29 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockServer = void 0;
const customParseFormat_1 = __importDefault(require("dayjs/plugin/customParseFormat"));
const relativeTime_1 = __importDefault(require("dayjs/plugin/relativeTime"));
const utc_1 = __importDefault(require("dayjs/plugin/utc"));
const dayjs_1 = __importDefault(require("dayjs"));
const ioredis_1 = require("ioredis");
const ws_1 = require("ws");
const http_1 = require("http");
const socket_io_1 = require("socket.io");
const models_1 = require("./models");
const logger_1 = require("../logger");
const transports = __importStar(require("./transports"));
const services = __importStar(require("./services"));
const config_1 = __importDefault(require("../config"));
__exportStar(require("./transports"), exports);
__exportStar(require("./models"), exports);
__exportStar(require("./types"), exports);
dayjs_1.default.extend(customParseFormat_1.default);
dayjs_1.default.extend(relativeTime_1.default);
dayjs_1.default.extend(utc_1.default);
const logger = logger_1.Logger.build('Server');
class MockServer {
constructor(configuration) {
this.configuration = configuration;
this.timestamp = Date.now();
this.authority = `http://${this.configuration.host}:${this.configuration.port}`;
this.databases = {
redis: this.configuration.databases?.redis
? new ioredis_1.Redis({ keyPrefix: 'mock:', ...this.configuration.databases?.redis })
: null,
};
this.exchanges = {
io: (0, models_1.buildSocketIoExchange)({ emit: () => false }),
};
this.providers = models_1.ProvidersStorage.build(this);
this.transports = models_1.TransportsStorage.build()
.register('http', new transports.HttpTransport())
.register('ws', new transports.WsTransport());
this.router = models_1.Router.build(this);
this.wss = new ws_1.WebSocketServer({ noServer: true });
this.http = (0, http_1.createServer)(transports.buildHttpListener(this.router))
.on('upgrade', transports.buildWsListener(this.router));
this.io = new socket_io_1.Server(this.http, {
maxHttpBufferSize: 1e8,
...(process.env['NODE_ENV'] === 'development' && {
cors: { origin: '*' },
}),
});
this.services = {
shutdown: services.ShutdownService.build(this),
metrics: services.MetricsService.build(this),
redis: services.RedisService.build(this),
containers: services.ContainersService.build(this),
history: services.HistoryService.build(this),
};
this.system = {
transports: {
http: new transports.SystemHttpTransport(this),
io: new transports.SystemSocketIoTransport(this),
},
};
this.databases.redis?.on('reconnecting', () => logger.info('Redis is reconnecting'));
this.databases.redis?.on('connect', () => logger.info('Redis has connected'));
this.databases.redis?.on('close', () => logger.info('Redis has closed'));
this.databases.redis?.on('error', (error) => logger.info('Got redis error', error?.stack ?? error));
}
/** Default client to work with main API */
get client() {
return this.providers.default.client;
}
async setupJobs() {
/** Containers expiration */
setInterval(() => this.services.containers.flush(), (this.configuration.containers?.expiredCleaningInterval ?? 60 * 60) * 1000);
/** Providers expiration */
setInterval(() => this.providers.expired().forEach((provider) => {
this.providers.unregister(provider);
this.router.unregister(provider);
}), (this.configuration.providers?.expiredCleaningInterval ?? 5 * 60) * 1000);
/** Memory metrics */
setInterval(() => this.services.metrics.register('memory', { mbs: process.memoryUsage().heapUsed / 1024 / 1024 }), 5 * 1000);
/** Containers metrics */
setInterval(() => this.services.metrics.register('containers', {
count: this.providers.extract().reduce((acc, provider) => acc + provider.storages.containers.size, 0),
}), 10 * 60 * 1000);
/** Reqests rate blank metrics */
setInterval(() => this.services.metrics.register('rate', { count: 0 }), 60 * 1000);
if (this.databases.redis) {
/** Containers persistence */
setInterval(() => this.services.containers.backup(), 10 * 60 * 1000);
/** History persistence */
setInterval(() => this.services.history.backup(), 10 * 60 * 1000);
/** Redis usage metrics */
setInterval(async () => {
const usage = await this.services.redis.usage();
this.services.metrics.register('cache', {
redis_mbs: usage.bytes / 1024 / 1024,
redis_count: usage.count,
});
}, 10 * 60 * 1000);
}
if (this.configuration.hooks?.shudown?.isEnabled !== false) {
process.on('SIGTERM', () => this.services.shutdown.exit());
process.on('SIGQUIT', () => this.services.shutdown.exit());
process.on('SIGINT', () => this.services.shutdown.exit());
process.on('SIGHUP', () => this.services.shutdown.exit());
}
}
/** Starts and setups mock server */
static async start(configuration) {
const routes = config_1.default.get('routes');
const server = new MockServer(configuration);
await new Promise((resolve) => server.http.listen(configuration.port, configuration.host, () => {
logger.info(`Has started on [${server.authority}]`);
logger.info(`GUI is available on [${server.authority}${routes.system.root}${routes.system.gui}/]`);
resolve();
}));
Object
.entries(configuration.transports ?? {})
.forEach(([type, transport]) => server.transports.register(type, transport));
await server.services.containers.restore();
await server.services.history.restore();
await server.setupJobs();
server.router.register(`${routes.system.root}/**`, {
provider: server.providers.default,
transports: {
http: server.system.transports.http,
},
});
return server;
}
}
exports.MockServer = MockServer;
//# sourceMappingURL=index.js.map