UNPKG

@n1k1t/mock-server

Version:

The ultimate toolkit to intercept, transform, and simulate HTTP/WS traffic with type-safe expectations

174 lines 8.29 kB
"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