UNPKG

@cliz/inlets

Version:
187 lines (186 loc) 9.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cli_1 = require("@cliz/cli"); const fs = require("fs"); const path = require("path"); const doreamon_1 = require("@zodash/doreamon"); const config_1 = require("../config"); const server_1 = require("../core/server"); const utils_1 = require("../core/server/utils"); exports.default = (0, cli_1.defineSubCommand)(createCommand => { return createCommand('inlets server') .option('-d, --domain', 'Domain for server', { required: true }) .option('-p, --port <port>', 'Port for server (default 8080)', { default: 8080 }) .option('--tcp-port <tcpPort>', 'TCP Port for server (default 8443)', { default: config_1.default.defaultTCPPort }) .option('-s, --secure', 'Server with https, only for url', { default: config_1.default.defaultSecure, }) .option('-t, --token <token>', 'Token for authentication', { required: false }) .option('-c, --config <config>', 'Config file', { default: cli_1.api.path.configfile('inlets.yml'), }) .action(async ({ args, options: _options, program }) => { var _a; const options = _options; const configLogger = doreamon_1.default.logger.getLogger('server:config'); const configRef = { current: null }; const loadConfig = async (configPath) => { try { if (await cli_1.api.fs.isExist(configPath)) { const loadedConfig = await cli_1.api.fs.yml.load(configPath); configRef.current = loadedConfig; configLogger.info(`配置文件已加载: ${configPath}`); return loadedConfig; } } catch (error) { const message = error instanceof Error ? error.message : String(error); configLogger.error(`加载配置文件失败: ${message}`); } return null; }; const configPath = path.resolve(options.config); const initialConfig = await loadConfig(configPath); if (!options.token && !(initialConfig === null || initialConfig === void 0 ? void 0 : initialConfig.token) && !(initialConfig === null || initialConfig === void 0 ? void 0 : initialConfig.clients)) { throw new Error(`token or clients is required in ${options.config}`); } let notificationInstance = null; if (initialConfig === null || initialConfig === void 0 ? void 0 : initialConfig.notification) { notificationInstance = new utils_1.Notification(initialConfig.notification); } let watcher = null; let reloadTimer = null; if (await cli_1.api.fs.isExist(configPath)) { watcher = fs.watch(configPath, async (eventType, filename) => { if (eventType === 'change') { configLogger.info(`检测到配置文件变化: ${filename}`); if (reloadTimer) { clearTimeout(reloadTimer); } reloadTimer = setTimeout(async () => { var _a, _b, _c, _d, _e; try { const oldClientsCount = ((_b = (_a = configRef.current) === null || _a === void 0 ? void 0 : _a.clients) === null || _b === void 0 ? void 0 : _b.length) || 0; await loadConfig(configPath); const newClientsCount = ((_d = (_c = configRef.current) === null || _c === void 0 ? void 0 : _c.clients) === null || _d === void 0 ? void 0 : _d.length) || 0; configLogger.info(`配置文件已热更新 (客户端数量: ${oldClientsCount} -> ${newClientsCount})`); if ((_e = configRef.current) === null || _e === void 0 ? void 0 : _e.notification) { notificationInstance = new utils_1.Notification(configRef.current.notification); } else { notificationInstance = null; } if (notificationInstance) { await notificationInstance.notify(`[配置更新] 配置文件已重新加载`, [ `配置文件路径: ${configPath}`, `客户端数量: ${oldClientsCount} -> ${newClientsCount}`, `当前时间: ${doreamon_1.default.date().format('YYYY-MM-DD HH:mm:ss')}`, ]); } } catch (error) { const message = error instanceof Error ? error.message : String(error); configLogger.error(`热更新失败: ${message}`); } }, 200); } }); watcher.on('error', (error) => { const message = error instanceof Error ? error.message : String(error); configLogger.error(`文件监听出错: ${message}`); }); configLogger.info(`已开始监听配置文件: ${configPath}`); } const cleanup = () => { if (watcher) { watcher.close(); watcher = null; } if (reloadTimer) { clearTimeout(reloadTimer); reloadTimer = null; } }; process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup); process.on('exit', cleanup); const token = async (authType, clientId, _options) => { var _a; const currentConfig = configRef.current; if (authType === 'credentials') { const client = (_a = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.clients) === null || _a === void 0 ? void 0 : _a.find(c => c.clientId === clientId); if (!client || !client.clientSecret) { throw new Error(`invalid client credentials for clientId: ${clientId}`); } return { authType, token: client.clientSecret, }; } if (authType === 'public') { if ((_options === null || _options === void 0 ? void 0 : _options.type) !== 'http') { throw new Error(`auth type public is only allowed by http type`); } return { authType, token: 'public', }; } const token = options.token || (currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.token); if (!token) { throw new Error(`unsupported auth type: ${authType}`); } return { authType, token: token, config: { version: program.getVersion(), notification: currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.notification, }, }; }; const get = (name) => { var _a; return options[name] || ((_a = configRef.current) === null || _a === void 0 ? void 0 : _a[name]); }; const buildBandwidthLimits = () => { var _a, _b, _c; const currentConfig = configRef.current; if (!(currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.bandwidthLimits) && !((_a = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.clients) === null || _a === void 0 ? void 0 : _a.some(c => c.bandwidthLimit))) { return undefined; } const limits = { byClientId: {}, }; if ((_b = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.bandwidthLimits) === null || _b === void 0 ? void 0 : _b.global) { limits.global = currentConfig.bandwidthLimits.global; } if (currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.clients) { for (const client of currentConfig.clients) { if (client.bandwidthLimit) { limits.byClientId[client.clientId] = client.bandwidthLimit; } } } if ((_c = currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.bandwidthLimits) === null || _c === void 0 ? void 0 : _c.clients) { for (const [clientId, limit] of Object.entries(currentConfig.bandwidthLimits.clients)) { limits.byClientId[clientId] = limit; } } return limits; }; const _opt = { ...args, ...options, domain: get('domain'), port: get('port'), tcpPort: get('tcpPort'), secure: get('secure'), version: program.getVersion(), token, notification: ((_a = configRef.current) === null || _a === void 0 ? void 0 : _a.notification) || (initialConfig === null || initialConfig === void 0 ? void 0 : initialConfig.notification), bandwidthLimits: buildBandwidthLimits(), }; return (0, server_1.server)(_opt); }); });