oox 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +13 -0
  2. package/app.js +1 -7
  3. package/bin/cli.js +45 -12
  4. package/bin/configurer.js +6 -9
  5. package/bin/proxy-require.js +1 -23
  6. package/bin/register.js +48 -15
  7. package/bin/starter.js +8 -0
  8. package/config.js +145 -0
  9. package/context.js +58 -0
  10. package/index.js +14 -133
  11. package/keepalive-connection.js +73 -0
  12. package/logger.js +2 -1
  13. package/modules/http/index.js +52 -63
  14. package/modules/http/router.js +9 -4
  15. package/modules/index.js +78 -74
  16. package/modules/module.js +1 -10
  17. package/modules/socketio/adapter.js +24 -13
  18. package/modules/socketio/server.js +37 -16
  19. package/modules/socketio/utils.js +12 -7
  20. package/package.json +13 -6
  21. package/proxy.js +30 -0
  22. package/registry.js +91 -7
  23. package/samples/index.js +1 -1
  24. package/samples/keepalive-connection-sample.js +62 -41
  25. package/types/app.d.ts +18 -24
  26. package/types/bin/configurer.d.ts +3 -1
  27. package/types/bin/register.d.ts +2 -1
  28. package/types/config.d.ts +66 -0
  29. package/types/context.d.ts +30 -0
  30. package/types/index.d.ts +10 -53
  31. package/types/keepalive-connection.d.ts +52 -16
  32. package/types/modules/http/index.d.ts +5 -8
  33. package/types/modules/index.d.ts +37 -22
  34. package/types/modules/module.d.ts +9 -9
  35. package/types/modules/socketio/adapter.d.ts +9 -4
  36. package/types/modules/socketio/server.d.ts +6 -4
  37. package/types/modules/socketio/utils.d.ts +12 -6
  38. package/types/proxy.d.ts +1 -0
  39. package/types/registry.d.ts +28 -3
  40. package/types/samples/index.d.ts +1 -1
  41. package/types/samples/keepalive-connection-sample.d.ts +33 -23
  42. package/utils.js +2 -2
package/README.md CHANGED
@@ -27,3 +27,16 @@ npm install oox
27
27
  ```bash
28
28
  npx oox --help
29
29
  ```
30
+
31
+ ### Examples
32
+ - [basic-example](./examples/basic-example)
33
+ - [routing-example](./examples/routing-example)
34
+ - [rpc-example](./examples/rpc-example)
35
+ - [distributed-example](./examples/distributed-example)
36
+ - [load-balancing-example](./examples/load-balancing-example)
37
+ - [tracing-example](./examples/tracing-example)
38
+ - [service-discovery-example](./examples/service-discovery-example)
39
+
40
+
41
+ ### Docs
42
+ [config](./docs/config.md)
package/app.js CHANGED
@@ -1,12 +1,6 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import { AsyncLocalStorage } from 'node:async_hooks';
3
2
  import { genKVMethods } from './utils.js';
4
- export * as logger from './logger.js';
5
- export class Context {
6
- // 请求溯源ID
7
- traceId = '';
8
- }
9
- export const asyncStore = new AsyncLocalStorage();
3
+ import { asyncStore } from './context.js';
10
4
  export const eventHub = new EventEmitter();
11
5
  /**
12
6
  * sourceMethods => methods
package/bin/cli.js CHANGED
@@ -16,7 +16,7 @@ if (execFilename.endsWith('oox') || fileURLToPath(import.meta.url) === execFilen
16
16
  if (!command || ['help', '-h', '-help', '--help', 'version', '-v', '-version', '--version'].includes(command)) {
17
17
  isStartup = false;
18
18
  console.log();
19
- console.log('OOX Service Engine');
19
+ console.log(pkg.description);
20
20
  console.log(chalk.bold('version'), chalk.bold.green(`${pkg.version}`));
21
21
  console.log(chalk.underline(`${pkg.homepage}`));
22
22
  console.log();
@@ -28,24 +28,54 @@ if (execFilename.endsWith('oox') || fileURLToPath(import.meta.url) === execFilen
28
28
  console.log(' oox entry.js port=8080');
29
29
  console.log();
30
30
  console.log(' oox entry.js group=app/ registry=:6000');
31
- console.log(' oox app/entry/index.js group=app/ env=envs/prod.js ignore=core');
31
+ console.log(' oox app/entry/index.js group=app/ env=.env/prod.js ignore=core');
32
32
  console.log();
33
33
  console.log(chalk.bold('Params:'));
34
- const params = [
34
+ const params_base = [
35
35
  ['default-env', 'file', '.js or .json file, merge to oox.config'],
36
- ['env', 'file', `${chalk.bold.red('default-env')}.js or .json file, merge to oox.config, ${chalk.bold('(after default-env)')}`],
36
+ ['env', 'file', `.js or .json file, merge to oox.config, ${chalk.bold('(after default-env)')}`],
37
37
  ['port', 'int', `default is ${chalk.bold('0')}, for random port, or any integer > 0`],
38
38
  ['group', 'dir', 'service group directory, all LocalCall transform to RPC'],
39
39
  ['ignore', 'name', 'set a name for LocalCall do not transform to RPC, support string | array<string>'],
40
- ['http', 'json', 'HTTP server options, support flat name, ex: http.path=/api'],
41
- ['socketio', 'json', 'SocketIO server options, support flat name'],
42
- ['isRegistry', 'bool', `default is ${chalk.bold.red('true')}, set no to disable service registry`],
40
+ ['errorStack', 'bool', 'set no to hidden error stack return'],
41
+ ];
42
+ const params_registry = [
43
+ ['isRegistry', 'bool', `set yes to enable service registry`],
43
44
  ['registryAdapter', 'name', 'set service registry adapter name'],
45
+ ['registryToken', 'token', 'set token for service registry'],
44
46
  ['registry', 'urls', 'registry service url, support string | array<string>'],
47
+ ['registry.url', 'url', 'set service registry url'],
48
+ ['registry.token', 'token', 'set service registry token'],
49
+ ];
50
+ const params_auth = [
51
+ ['token', 'token', 'set token for connection auth'],
52
+ ['allow.untrusted', 'bool', `set yes to allow untrusted caller`],
53
+ ['allow.ip', 'ip', 'set allow IP, support string | array<string>'],
54
+ ['allow.caller', 'name', 'set allow caller, support string | array<string>'],
45
55
  ['origin', 'urls', `set ${chalk.bold('*')}, allow any connections <Access-Control-Allow-Origin>`],
46
- ['errorStack', 'bool', 'set no to hidden error stack return'],
47
56
  ];
48
- console.log(mergeCommandParams(params));
57
+ const params_modules = [
58
+ ['http', 'json/bool', 'HTTP server options, support flat name, ex: http.path=/api, or set no to disable HTTP server'],
59
+ ['http.port', 'int server port'],
60
+ ['http.path', 'string', 'set HTTP server path'],
61
+ ['http.origin', 'urls', 'set HTTP server origin, support string | array<string>'],
62
+ ['http.ssl', 'json', 'set yes to enable HTTPS'],
63
+ ['http.ssl.cert', 'file', 'set HTTPS certificate path'],
64
+ ['http.ssl.key', 'file', 'set HTTPS private key path'],
65
+ ['http.ssl.ca', 'file', 'set HTTPS CA path'],
66
+ ['socketio', 'json/bool', 'SocketIO server options, support flat name, or set no to disable SocketIO server'],
67
+ ['socketio.port', 'int server port'],
68
+ ['socketio.path', 'string', 'set SocketIO server path'],
69
+ ['socketio.origin', 'urls', 'set SocketIO server origin, support string | array<string>'],
70
+ ['socketio.ssl', 'json', 'like http.ssl'],
71
+ ];
72
+ console.log(mergeCommandParams(params_base));
73
+ console.log(chalk.bold('Registry:'));
74
+ console.log(mergeCommandParams(params_registry));
75
+ console.log(chalk.bold('Auth:'));
76
+ console.log(mergeCommandParams(params_auth));
77
+ console.log(chalk.bold('Modules:'));
78
+ console.log(mergeCommandParams(params_modules));
49
79
  console.log(' ...', 'set params as', chalk.bold('foo=bar') + ',', 'usage as', chalk.bold('oox.config.foo'));
50
80
  console.log();
51
81
  }
@@ -73,10 +103,13 @@ function mergeCommandParams(params) {
73
103
  result += ' '.repeat(nameMaxLength);
74
104
  }
75
105
  else {
76
- result += ' '.repeat(nameMaxLength - name.length);
106
+ result += ' '.repeat(Math.max(0, nameMaxLength - name.length));
77
107
  }
78
- result += '[' + type + ']';
79
- result += ' '.repeat(typeMaxLength - type.length);
108
+ const typeLeftSpaceLength = Math.max(0, Math.floor((typeMaxLength - type.length) / 2));
109
+ const typeLeftSpaces = ' '.repeat(typeLeftSpaceLength);
110
+ const typeRightSpaces = ' '.repeat(Math.max(0, typeMaxLength - type.length - typeLeftSpaceLength));
111
+ result += '[' + typeLeftSpaces + type + typeRightSpaces + ']';
112
+ result += ' ';
80
113
  result += desc;
81
114
  result += '\n';
82
115
  }
package/bin/configurer.js CHANGED
@@ -12,7 +12,11 @@ function mergeFlatEnv(env) {
12
12
  const valueKey = subKeys.pop() || '';
13
13
  let tmpEnv = env;
14
14
  for (const subKey of subKeys) {
15
- if (subKey in tmpEnv) { }
15
+ if (subKey in tmpEnv) {
16
+ if ('object' !== typeof tmpEnv[subKey] || null === tmpEnv[subKey]) {
17
+ tmpEnv[subKey] = {};
18
+ }
19
+ }
16
20
  else {
17
21
  tmpEnv[subKey] = {};
18
22
  }
@@ -42,20 +46,13 @@ async function readEnvFile(filePath) {
42
46
  return env;
43
47
  }
44
48
  export async function buildConfig(mergeEnv) {
45
- const env = Object.create(null);
49
+ const env = {};
46
50
  const defaultEnvPath = argv.getEnvArg('default-env');
47
51
  const targetEnvPath = argv.getEnvArg('env');
48
52
  const defaultEnv = defaultEnvPath ? await readEnvFile(defaultEnvPath) : {};
49
53
  const targetEnv = targetEnvPath ? await readEnvFile(targetEnvPath) : {};
50
54
  Object.assign(env, defaultEnv, targetEnv, argv.getAllEnvArgs());
51
55
  mergeFlatEnv(env);
52
- if ('string' === typeof env.ignore)
53
- env.ignore = env.ignore.split(',');
54
- if ('string' === typeof env.registry)
55
- env.registry = env.registry.split(',');
56
- if ('string' === typeof env.origin && env.origin.includes(',')) {
57
- env.origin = env.origin.split(',');
58
- }
59
56
  if (mergeEnv)
60
57
  Object.assign(env, mergeEnv);
61
58
  return env;
@@ -4,10 +4,6 @@ import * as path from 'node:path';
4
4
  import * as oox from '../index.js';
5
5
  import { Module } from 'node:module';
6
6
  const require = createRequire(import.meta.url);
7
- /**
8
- * 为了不重复创建Proxy,这个对象用于保存各个RPC服务的各个属性Proxy
9
- */
10
- const rpcServiceAttrMap = Object.create(null);
11
7
  /**
12
8
  * 重写 require 缓存
13
9
  */
@@ -24,24 +20,6 @@ function rewriteModuleCache(id, exports) {
24
20
  m.paths = paths;
25
21
  require.cache[id] = m;
26
22
  }
27
- function dotCall(name, action) {
28
- return new Proxy(function () { }, {
29
- get(target, key) {
30
- const attrKey = name + '.' + (action ? action + '.' + key : key);
31
- if (rpcServiceAttrMap) {
32
- // 不重复创建Proxy
33
- return rpcServiceAttrMap[attrKey];
34
- }
35
- const attrProxy = dotCall(name, attrKey);
36
- rpcServiceAttrMap[attrKey] = attrProxy;
37
- return attrProxy;
38
- },
39
- has(target, key) { return true; },
40
- apply(target, thisArg, args) {
41
- return oox.rpc(name, action, args);
42
- }
43
- });
44
- }
45
23
  export function proxyGroup(groupDirectory, excludes = []) {
46
24
  if (!groupDirectory)
47
25
  return;
@@ -70,7 +48,7 @@ export function proxyGroup(groupDirectory, excludes = []) {
70
48
  name = scriptMatch[1];
71
49
  }
72
50
  if (!excludes.includes(name))
73
- rewriteModuleCache(id, dotCall(name, ''));
51
+ rewriteModuleCache(id, oox.proxy(name));
74
52
  }
75
53
  }
76
54
  /**
package/bin/register.js CHANGED
@@ -1,32 +1,65 @@
1
1
  import chalk from 'chalk';
2
2
  import * as oox from '../index.js';
3
+ import { randomUUID } from 'node:crypto';
3
4
  const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
4
- async function connect(url, prevError = null) {
5
- const adapter = oox.keepAliveConnectionAdapters.get(oox.config.registryAdapter);
5
+ async function connect(identify, prevError = null) {
6
+ let url = '';
7
+ let connectionData;
8
+ if (typeof identify === 'string') {
9
+ url = identify;
10
+ connectionData = {
11
+ adapter: oox.config.registryAdapter,
12
+ url,
13
+ ip: '',
14
+ name: 'anonymous',
15
+ id: randomUUID(),
16
+ token: oox.config.registryToken,
17
+ };
18
+ }
19
+ else {
20
+ url = String(identify.url || '');
21
+ connectionData = identify;
22
+ }
23
+ if (!connectionData.name)
24
+ connectionData.name = 'anonymous';
25
+ if (!connectionData.id)
26
+ connectionData.id = randomUUID();
27
+ if (!connectionData.token)
28
+ connectionData.token = oox.config.registryToken;
29
+ if (!connectionData.adapter)
30
+ connectionData.adapter = oox.config.registryAdapter;
31
+ const adapter = oox.keepAliveConnectionAdapters.get(connectionData.adapter);
32
+ if (!adapter) {
33
+ console.error(chalk.red('[Registry]'), `Registry Adapter ${chalk.bold(connectionData.adapter)} is not found`);
34
+ return;
35
+ }
36
+ if (!url) {
37
+ console.error(chalk.red('[Registry]'), `Registry URL ${chalk.bold(url)} is empty`);
38
+ return;
39
+ }
6
40
  try {
7
- const connection = await adapter.open(url);
8
- onConnection(connection, url);
41
+ const connection = await adapter.open(connectionData);
42
+ connection.isRegistry = true;
43
+ onConnection(connection);
9
44
  }
10
45
  catch (error) {
11
46
  if (!prevError)
12
- console.log(chalk.red('[Registry]'), chalk.underline.red(`${url}`), 'error.');
47
+ console.error(chalk.red('[Registry]'), chalk.underline.red(`${url}`), 'error.');
13
48
  await delay(2000);
14
- connect(url, error);
49
+ connect(identify, error);
15
50
  }
16
51
  }
17
- async function onConnection(connection, url) {
52
+ async function onConnection(connection) {
18
53
  const { name } = connection.data;
19
54
  connection.once('disconnect', async () => {
20
- console.log(chalk.red('[Registry]'), `Service<${name}>`, chalk.underline.red(`${connection.data.url || url}`), 'disconnected.');
55
+ console.error(chalk.red('[Registry]'), `Service<${name}>`, chalk.underline.red(`${connection.data.url || name}`), 'disconnected.');
21
56
  await delay(1000);
22
- connect(url);
57
+ connect(connection.data);
23
58
  });
24
- console.log(chalk.green('[Registry]'), `Service<${name}>`, chalk.underline.green(`${connection.data.url || url}`), 'connected.');
59
+ console.info(chalk.green('[Registry]'), `Service<${name}>`, chalk.underline.green(`${connection.data.url || name}`), 'connected.');
25
60
  }
26
- export async function registry(urls) {
27
- if ('string' === typeof urls)
28
- urls = [urls];
29
- for (const url of urls) {
30
- connect(url);
61
+ export async function registry(identifies) {
62
+ for (const identify of identifies) {
63
+ connect(identify);
31
64
  }
32
65
  }
package/bin/starter.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as path from 'node:path';
2
2
  import chalk from 'chalk';
3
+ import { configFormatters } from '../config.js';
3
4
  import * as oox from '../index.js';
4
5
  import { buildConfig } from './configurer.js';
5
6
  import { registry } from './register.js';
@@ -17,6 +18,8 @@ function getEntryInfo(env, entryFilename) {
17
18
  const directory = fullDirectory.split(path.sep).pop();
18
19
  const groupFullDirectory = env.group ? path.resolve(env.group) : '';
19
20
  const entryMatch = filename.match(entryMatchRegExp);
21
+ if (!entryMatch)
22
+ throw new Error('Invalid entry file name: ' + entryFilename);
20
23
  const entryFilenameWithoutExtension = entryMatch[1];
21
24
  const name = entryFilenameWithoutExtension === 'index' && groupFullDirectory !== fullDirectory ? directory : entryFilenameWithoutExtension;
22
25
  return { name, path: fullPath, group: groupFullDirectory };
@@ -37,6 +40,11 @@ export async function configure(env, entryFilename) {
37
40
  path: entryInfo.path.replace(/\\/g, '/'),
38
41
  group: entryInfo.group.replace(/\\/g, '/'),
39
42
  };
43
+ for (const key in oox.config) {
44
+ if (key in configFormatters) {
45
+ oox.config[key] = configFormatters[key](oox.config[key]);
46
+ }
47
+ }
40
48
  // 模块配置
41
49
  oox.modules.setConfig(oox.config);
42
50
  oox.emit('app:configured');
package/config.js ADDED
@@ -0,0 +1,145 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { getIPAddress } from "./utils.js";
3
+ export class Config {
4
+ // 服务ID
5
+ id = randomUUID();
6
+ // 服务名称
7
+ name = 'local';
8
+ // 服务列表路径
9
+ group = '';
10
+ // 非服务模块
11
+ ignore = [];
12
+ // 启动文件
13
+ entryInfo = {
14
+ // 启动文件路径
15
+ path: '',
16
+ // 服务列表路径
17
+ group: '',
18
+ };
19
+ // 主机地址
20
+ host = getIPAddress(4)[0];
21
+ // 默认监听端口
22
+ port = 0;
23
+ // 默认跨域设置
24
+ origin = '';
25
+ // 默认返回错误调用栈信息信息
26
+ errorStack = true;
27
+ // 是否开启服务注册功能
28
+ isRegistry = false;
29
+ // 服务注册列表
30
+ registry = [];
31
+ // 注册服务令牌
32
+ registryToken = '';
33
+ // 服务注册适配器
34
+ registryAdapter = 'socketio';
35
+ // 当前服务的令牌,验证成功则忽略allow配置
36
+ token = randomUUID();
37
+ allow = {
38
+ // 是否允许未验证令牌连接
39
+ untrusted: false,
40
+ // 是否允许指定IP连接
41
+ ip: [],
42
+ // 是否允许指定名称连接
43
+ caller: [],
44
+ };
45
+ }
46
+ export const configFormatters = {
47
+ id: function (value) {
48
+ return String(value || randomUUID());
49
+ },
50
+ name: function (value) {
51
+ return String(value || 'local');
52
+ },
53
+ group: function (value) {
54
+ return String(value || '');
55
+ },
56
+ ignore: function (value) {
57
+ if (Array.isArray(value))
58
+ return value;
59
+ if (typeof value === 'string')
60
+ return value.split(',');
61
+ return [];
62
+ },
63
+ entryInfo: function (value) {
64
+ return value;
65
+ },
66
+ host: function (value) {
67
+ return String(value || getIPAddress(4)[0]);
68
+ },
69
+ port: function (value) {
70
+ return Number(value) || 0;
71
+ },
72
+ origin: function (value) {
73
+ if (value === '*')
74
+ return value;
75
+ if (Array.isArray(value))
76
+ return value;
77
+ if (typeof value === 'string')
78
+ return value.split(',');
79
+ return '';
80
+ },
81
+ errorStack: function (value) {
82
+ return Boolean(value);
83
+ },
84
+ isRegistry: function (value) {
85
+ return Boolean(value);
86
+ },
87
+ registry: function (value) {
88
+ if ('string' === typeof value)
89
+ value = value.split(',');
90
+ if (value && !Array.isArray(value))
91
+ value = [value];
92
+ return value;
93
+ },
94
+ registryToken: function (value) {
95
+ return String(value || '');
96
+ },
97
+ registryAdapter: function (value) {
98
+ return String(value || '');
99
+ },
100
+ token: function (value) {
101
+ return String(value || '');
102
+ },
103
+ allow: function (value) {
104
+ value = value || {
105
+ untrusted: false,
106
+ ip: [],
107
+ caller: [],
108
+ };
109
+ const { ip, caller } = value;
110
+ if ('string' === typeof ip)
111
+ value.ip = ip.split(',');
112
+ if ('string' === typeof caller)
113
+ value.caller = caller.split(',');
114
+ return value;
115
+ }
116
+ };
117
+ /**
118
+ * 检查连接是否被允许
119
+ * @param ip 连接主机 IP
120
+ * @param caller 连接服务名称
121
+ * @param token 令牌
122
+ * @returns 是否被允许
123
+ */
124
+ export function checkAllow(ip, caller, token) {
125
+ // check trusted token
126
+ const trusted = !config.token || token === config.token;
127
+ if (!trusted) {
128
+ const { allow } = config;
129
+ if (!allow.untrusted) {
130
+ return { allow: false, reason: 'untrusted' };
131
+ }
132
+ if (Array.isArray(allow.ip) && allow.ip.length) {
133
+ let allowed = allow.ip.some(item => item === '*' || new RegExp(item).test(ip));
134
+ if (!allowed)
135
+ return { allow: false, reason: 'not allow ip=' + ip };
136
+ }
137
+ if (Array.isArray(allow.caller) && allow.caller.length) {
138
+ let allowed = allow.caller.some(item => item === '*' || new RegExp(item).test(caller));
139
+ if (!allowed)
140
+ return { allow: false, reason: 'not allow caller=' + caller };
141
+ }
142
+ }
143
+ return { allow: true };
144
+ }
145
+ export const config = new Config();
package/context.js ADDED
@@ -0,0 +1,58 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
3
+ export const asyncStore = new AsyncLocalStorage();
4
+ export class AppContext {
5
+ // 请求溯源ID
6
+ traceId = '';
7
+ }
8
+ export class Context extends AppContext {
9
+ // 请求溯源IP
10
+ sourceIP = '';
11
+ // 请求者IP
12
+ ip = '';
13
+ // 请求者名称
14
+ caller = 'anonymous';
15
+ // 请求者ID (长连接专用)
16
+ callerId = '';
17
+ // 请求者连接把柄
18
+ connection;
19
+ constructor(context) {
20
+ super();
21
+ if (context) {
22
+ if ('toJSON' in context && typeof context.toJSON !== 'function') {
23
+ throw new Error('Context.toJSON must be a function');
24
+ }
25
+ Object.assign(this, context);
26
+ }
27
+ }
28
+ toJSON() {
29
+ const context = Object.assign({}, this);
30
+ delete context.connection;
31
+ return context;
32
+ }
33
+ }
34
+ let genTraceIdFunction = () => randomUUID();
35
+ export function setGenTraceIdFunction(fn) {
36
+ genTraceIdFunction = fn;
37
+ }
38
+ /**
39
+ * 生成随机不重复id
40
+ */
41
+ export function genTraceId() {
42
+ return genTraceIdFunction();
43
+ }
44
+ /**
45
+ * 获取链路跟踪上下文
46
+ */
47
+ export function genContext(context) {
48
+ const newContext = new Context(context);
49
+ if (!newContext.traceId)
50
+ newContext.traceId = genTraceId();
51
+ if (!newContext.sourceIP)
52
+ newContext.sourceIP = newContext.ip;
53
+ return newContext;
54
+ }
55
+ export function getContext() {
56
+ const context = asyncStore.getStore();
57
+ return context || genContext();
58
+ }
package/index.js CHANGED
@@ -1,139 +1,20 @@
1
- import { randomUUID } from 'node:crypto';
2
- import * as app from './app.js';
3
- import { getIPAddress } from './utils.js';
4
- import * as registry from './registry.js';
5
- import Module, { ModuleConfig } from './modules/module.js';
6
- import { KeepAliveConnection, keepAliveConnectionAdapters, keepAliveConnections, enabledKeepAliveConnections } from './keepalive-connection.js';
7
- export class Context extends app.Context {
8
- // 请求溯源IP
9
- sourceIP = '';
10
- // 请求者IP
11
- ip = '';
12
- // 请求者名称
13
- caller = 'anonymous';
14
- // 请求者ID (长连接专用)
15
- callerId = '';
16
- // 请求者连接把柄
17
- connection;
18
- toJSON() {
19
- const context = Object.assign({}, this);
20
- delete context.connection;
21
- return context;
22
- }
23
- }
24
- export class Config {
25
- // 服务ID
26
- id = randomUUID();
27
- // 服务名称
28
- name = 'local';
29
- // 服务列表路径
30
- group = '';
31
- // 非服务模块
32
- ignore = [];
33
- // 启动文件
34
- entryInfo = {
35
- // 启动文件路径
36
- path: '',
37
- // 服务列表路径
38
- group: '',
39
- };
40
- // 主机地址
41
- host = getIPAddress(4)[0];
42
- // 默认监听端口
43
- port = 0;
44
- // 默认跨域设置
45
- origin = '';
46
- // 默认返回错误调用栈信息信息
47
- errorStack = true;
48
- // 是否开启服务注册功能
49
- isRegistry = true;
50
- // 服务注册列表
51
- registry = [];
52
- // 服务注册适配器
53
- registryAdapter = 'socketio';
54
- }
55
- export const config = new Config();
56
- let genTraceIdFunction = () => randomUUID();
57
- export function setGenTraceIdFunction(fn) {
58
- genTraceIdFunction = fn;
59
- }
60
- /**
61
- * 生成随机不重复id
62
- */
63
- export function genTraceId() {
64
- return genTraceIdFunction();
65
- }
66
- /**
67
- * 获取链路跟踪上下文
68
- */
69
- export function genContext(context) {
70
- const newContext = Object.assign(new Context(), context);
71
- if (!newContext.traceId)
72
- newContext.traceId = genTraceId();
73
- if (!newContext.sourceIP)
74
- newContext.sourceIP = newContext.ip;
75
- return newContext;
76
- }
77
- export function getContext() {
78
- const context = asyncStore.getStore();
79
- return context || genContext();
80
- }
81
1
  export async function serve() {
82
2
  await modules.serve();
3
+ registry.startBroadcastTimer();
83
4
  }
84
5
  export async function stop() {
85
6
  await modules.stop();
86
- }
87
- export function addKeepAliveConnection(connection) {
88
- keepAliveConnections.add(connection);
89
- }
90
- export function removeKeepAliveConnection(arg1, arg2) {
91
- if (typeof arg1 === 'string') {
92
- keepAliveConnections.remove(arg1, arg2);
93
- enabledKeepAliveConnections.remove(arg1, arg2);
94
- }
95
- else {
96
- keepAliveConnections.remove(arg1);
97
- enabledKeepAliveConnections.remove(arg1);
98
- }
99
- }
100
- /**
101
- * random connection select for default load balance policy
102
- * @param name service name
103
- * @returns selected connection
104
- */
105
- let loadBalancePolicy = (name) => {
106
- const connections = enabledKeepAliveConnections.getConnectionsOfService(name);
107
- if (!connections || !connections.size)
108
- return null;
109
- const arrayConnections = Array.from(connections.values());
110
- const index = Math.floor(Math.random() * arrayConnections.length);
111
- return arrayConnections[index];
112
- };
113
- export function setLoadBalancePolicy(policy) {
114
- loadBalancePolicy = policy;
115
- }
116
- export async function rpc(arg1, action, params, context) {
117
- if (!context || !context.traceId) {
118
- context = getContext();
119
- }
120
- let connection;
121
- if (arg1 instanceof KeepAliveConnection) {
122
- connection = arg1;
123
- }
124
- else if ('string' === typeof arg1) {
125
- connection = loadBalancePolicy(arg1);
126
- if (!connection)
127
- throw new Error(`Connection<${arg1}> not found`);
128
- }
129
- else
130
- throw new Error(`Unknown rpc arg1<${arg1}>`);
131
- return connection.adapter.rpc(connection, action, params, context);
132
- }
133
- export { KeepAliveConnection, keepAliveConnectionAdapters, keepAliveConnections, enabledKeepAliveConnections };
134
- export { Module, ModuleConfig };
7
+ registry.stopBroadcastTimer();
8
+ }
9
+ export * from './app.js';
10
+ export * from './config.js';
11
+ export * from './context.js';
12
+ export * from './keepalive-connection.js';
13
+ export * from './modules/module.js';
14
+ export * as logger from './logger.js';
15
+ export * from './proxy.js';
16
+ import * as registry from './registry.js';
135
17
  export { registry };
136
- export const { asyncStore, setMethods, getMethods, kvMethods, sourceKVMethods, call, execute, logger, on, once, off, emit, } = app;
137
- // 放在最后导入,解决循环依赖问题
138
- import Modules from './modules/index.js';
139
- export const modules = new Modules;
18
+ // 放在最后导入,避免循环依赖问题
19
+ import * as modules from './modules/index.js';
20
+ export { modules };