oox 0.3.0-beta9 → 0.3.2

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 (47) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +29 -32
  3. package/app.js +131 -143
  4. package/bin/argv.js +63 -70
  5. package/bin/cli.js +57 -43
  6. package/bin/configurer.js +60 -62
  7. package/bin/loader.mjs +392 -279
  8. package/bin/proxy-import.js +12 -0
  9. package/bin/proxy-require.js +88 -0
  10. package/bin/register.js +46 -55
  11. package/bin/starter.js +63 -66
  12. package/index.js +155 -168
  13. package/index.mjs +4 -4
  14. package/logger.js +25 -40
  15. package/modules/http/index.js +286 -192
  16. package/modules/http/router.js +205 -0
  17. package/modules/http/utils.js +75 -73
  18. package/modules/index.js +86 -88
  19. package/modules/module.js +11 -16
  20. package/modules/socketio/client.js +97 -101
  21. package/modules/socketio/index.js +171 -168
  22. package/modules/socketio/server.js +188 -136
  23. package/modules/socketio/socket.js +1 -4
  24. package/package.json +14 -12
  25. package/types/app.d.ts +50 -51
  26. package/types/bin/argv.d.ts +8 -8
  27. package/types/bin/cli.d.ts +6 -2
  28. package/types/bin/configurer.d.ts +3 -1
  29. package/types/bin/proxy-import.d.ts +4 -0
  30. package/types/bin/proxy-require.d.ts +5 -0
  31. package/types/bin/register.d.ts +1 -1
  32. package/types/bin/starter.d.ts +5 -1
  33. package/types/index.d.ts +78 -76
  34. package/types/logger.d.ts +5 -4
  35. package/types/modules/http/index.d.ts +65 -47
  36. package/types/modules/http/router.d.ts +49 -0
  37. package/types/modules/http/utils.d.ts +14 -17
  38. package/types/modules/index.d.ts +24 -24
  39. package/types/modules/module.d.ts +11 -13
  40. package/types/modules/socketio/client.d.ts +23 -23
  41. package/types/modules/socketio/index.d.ts +37 -37
  42. package/types/modules/socketio/server.d.ts +44 -35
  43. package/types/modules/socketio/socket.d.ts +11 -11
  44. package/types/utils.d.ts +6 -6
  45. package/utils.js +57 -63
  46. package/bin/proxyer.js +0 -61
  47. package/types/bin/proxyer.d.ts +0 -1
@@ -0,0 +1,12 @@
1
+ import { register } from 'node:module';
2
+ import * as oox from '../index.js';
3
+ /**
4
+ * 注册ECMAScript Module加载器
5
+ */
6
+ export async function registModuleLoader() {
7
+ register(import.meta.resolve('oox/loader'), import.meta.url, {
8
+ data: {
9
+ ooxConfig: oox.config
10
+ }
11
+ });
12
+ }
@@ -0,0 +1,88 @@
1
+ import * as fs from 'node:fs';
2
+ import { createRequire } from 'module';
3
+ import * as path from 'node:path';
4
+ import * as oox from '../index.js';
5
+ import { Module } from 'node:module';
6
+ const require = createRequire(import.meta.url);
7
+ /**
8
+ * 为了不重复创建Proxy,这个对象用于保存各个RPC服务的各个属性Proxy
9
+ */
10
+ const rpcServiceAttrMap = Object.create(null);
11
+ /**
12
+ * 重写 require 缓存
13
+ */
14
+ function rewriteModuleCache(id, exports) {
15
+ const pathname = id.split(path.sep).slice(0, -1).join(path.sep);
16
+ const pathSplit = pathname.split(path.sep);
17
+ const paths = pathSplit.map((v, i, a) => a.slice(0, i + 1).concat('node_modules').join(path.sep)).reverse();
18
+ const m = new Module(id);
19
+ m.path = pathname;
20
+ m.exports = exports;
21
+ m.filename = m.id;
22
+ m.loaded = true;
23
+ m.children = [];
24
+ m.paths = paths;
25
+ require.cache[id] = m;
26
+ }
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
+ export function proxyGroup(groupDirectory, excludes = []) {
46
+ if (!groupDirectory)
47
+ return;
48
+ const directory = path.resolve(groupDirectory);
49
+ const stat = fs.statSync(directory);
50
+ if (!stat.isDirectory())
51
+ throw new Error('group must be directory');
52
+ const subs = fs.readdirSync(directory);
53
+ for (const filename of subs) {
54
+ const fullPath = path.resolve(directory + path.sep + filename);
55
+ const stat = fs.statSync(fullPath);
56
+ let id = '', name = '';
57
+ if (stat.isDirectory()) {
58
+ const entries = fs.readdirSync(fullPath);
59
+ for (const entry of entries) {
60
+ if (/^index\.((\w?js)|(ts\w?))$/.test(entry))
61
+ id = path.resolve(fullPath, entry);
62
+ }
63
+ name = filename;
64
+ }
65
+ else {
66
+ const scriptMatch = filename.match(/(\w+)\.((\w?js)|(ts\w?))$/);
67
+ if (!scriptMatch)
68
+ continue;
69
+ id = fullPath;
70
+ name = scriptMatch[1];
71
+ }
72
+ if (!excludes.includes(name))
73
+ rewriteModuleCache(id, dotCall(name, ''));
74
+ }
75
+ }
76
+ /**
77
+ * 将所有 group 目录下的 commonjs require 转换为 RPC
78
+ */
79
+ export function inGroupConvertRequireToRPC() {
80
+ const { name, group, ignore } = oox.config;
81
+ // 代理<服务间调用>
82
+ if (group) {
83
+ const excludes = [name];
84
+ if (Array.isArray(ignore))
85
+ excludes.push(...ignore);
86
+ proxyGroup(group, excludes);
87
+ }
88
+ }
package/bin/register.js CHANGED
@@ -1,55 +1,46 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registry = void 0;
4
- const chalk_1 = require("chalk");
5
- const oox = require("../index");
6
- const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
7
- function urlFormatter(url) {
8
- // :6000
9
- if (url.startsWith(':'))
10
- url = oox.config.host + url;
11
- // http://127.0.0.1:6000
12
- if (url.startsWith('http://'))
13
- url = url.slice(7);
14
- // 127.0.0.1:6000
15
- if (!url.startsWith('ws://'))
16
- url = 'ws://' + url;
17
- const urlObject = new URL(url);
18
- if (urlObject.pathname === '/' && !url.endsWith('/'))
19
- url = url + '/socket.io';
20
- return url;
21
- }
22
- async function connect(url, prevError = null) {
23
- const socketio = oox.modules.get('socketio');
24
- const { host } = oox.config;
25
- const { port, path } = socketio.config;
26
- if (`ws://${host}:${port}${path}` === url)
27
- return;
28
- try {
29
- const socket = await socketio.connect(url);
30
- onConnection(socket, url);
31
- }
32
- catch (error) {
33
- if (!prevError)
34
- console.log((0, chalk_1.red) `[Registry]`, chalk_1.underline.red `${url}`, 'error.');
35
- await delay(5000);
36
- connect(url, error);
37
- }
38
- }
39
- async function onConnection(socket, url) {
40
- const { name } = socket.data;
41
- socket.on('disconnect', async () => {
42
- console.log((0, chalk_1.red) `[Registry]`, `Service<${name}>`, chalk_1.underline.red `${url}`, 'disconnected.');
43
- await delay(1000);
44
- connect(url);
45
- });
46
- console.log((0, chalk_1.green) `[Registry]`, `Service<${name}>`, chalk_1.underline.green `${url}`, 'connected.');
47
- }
48
- async function registry(urls) {
49
- if ('string' === typeof urls)
50
- urls = [urls];
51
- for (const url of urls) {
52
- connect(urlFormatter(url));
53
- }
54
- }
55
- exports.registry = registry;
1
+ import chalk from 'chalk';
2
+ import * as oox from '../index.js';
3
+ import { default as SocketIOModule } from '../modules/socketio/index.js';
4
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
5
+ function urlFormatter(url) {
6
+ let _url = SocketIOModule.genWebSocketUrl(url);
7
+ const urlObject = new URL(_url);
8
+ if (urlObject.pathname === '/' && !url.endsWith('/'))
9
+ _url += '/socket.io';
10
+ return _url;
11
+ }
12
+ async function connect(url, prevError = null) {
13
+ const socketio = oox.modules.get('socketio');
14
+ const { host } = oox.config;
15
+ const { port, path } = socketio.config;
16
+ const urlObject = new URL(url);
17
+ // check if url is self
18
+ if (urlObject.host === host && urlObject.port === String(port))
19
+ return;
20
+ try {
21
+ const socket = await socketio.connect(url);
22
+ onConnection(socket, url);
23
+ }
24
+ catch (error) {
25
+ if (!prevError)
26
+ console.log(chalk.red('[Registry]'), chalk.underline.red(`${url}`), 'error.');
27
+ await delay(2000);
28
+ connect(url, error);
29
+ }
30
+ }
31
+ async function onConnection(socket, url) {
32
+ const { name } = socket.data;
33
+ socket.once('disconnect', async () => {
34
+ console.log(chalk.red('[Registry]'), `Service<${name}>`, chalk.underline.red(`${url}`), 'disconnected.');
35
+ await delay(1000);
36
+ connect(url);
37
+ });
38
+ console.log(chalk.green('[Registry]'), `Service<${name}>`, chalk.underline.green(`${url}`), 'connected.');
39
+ }
40
+ export async function registry(urls) {
41
+ if ('string' === typeof urls)
42
+ urls = [urls];
43
+ for (const url of urls) {
44
+ connect(urlFormatter(url));
45
+ }
46
+ }
package/bin/starter.js CHANGED
@@ -1,66 +1,63 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.startup = void 0;
4
- const path = require("node:path");
5
- const chalk_1 = require("chalk");
6
- const oox = require("../index");
7
- const proxyer_1 = require("./proxyer");
8
- const configurer_1 = require("./configurer");
9
- const register_1 = require("./register");
10
- function getEntryFile(env) {
11
- const args = process.argv.slice(2);
12
- var [entryFilename] = args.filter(arg => !arg.includes('=') && arg.endsWith('.js'));
13
- if (!entryFilename)
14
- throw new Error('Cannot find entry file');
15
- const fullPath = path.resolve(entryFilename);
16
- const filename = path.basename(fullPath);
17
- const fullDirectory = path.dirname(fullPath);
18
- const directory = fullDirectory.split(path.sep).pop();
19
- const groupFullDirectory = env.group ? path.resolve(env.group) : '';
20
- var name = filename === 'index.js' && groupFullDirectory !== fullDirectory ? directory : filename.split('.js')[0];
21
- return { name, path: fullPath, group: groupFullDirectory };
22
- }
23
- async function loadEntry(name, entryPath) {
24
- oox.config.name = name;
25
- // Typescript 4.7.3, not supported import() expression
26
- const methods = await eval(`import('file://${entryPath.replace(/\\/g, '/')}')`);
27
- oox.setMethods(methods.default || methods);
28
- }
29
- async function startup() {
30
- // 加载环境变量
31
- const env = await (0, configurer_1.configure)();
32
- Object.assign(oox.config, env);
33
- // 获取服务入口地址
34
- const entryFile = getEntryFile(env);
35
- oox.config.entryFile = {
36
- path: entryFile.path.replace(/\\/g, '/'),
37
- group: entryFile.group.replace(/\\/g, '/'),
38
- };
39
- // 代理<服务间调用>
40
- if (env.group) {
41
- const excludes = [entryFile.name];
42
- if (Array.isArray(env.ignore))
43
- excludes.push(...env.ignore);
44
- (0, proxyer_1.proxyGroup)(entryFile.group, excludes);
45
- }
46
- // 加载服务
47
- await loadEntry(entryFile.name, entryFile.path);
48
- // 模块配置
49
- oox.modules.setConfig(oox.config);
50
- oox.emit('app:configured');
51
- const { http: { config: httpConfig }, socketio: { config: socketioConfig } } = oox.modules.builtins;
52
- // 服务启动
53
- await oox.serve();
54
- oox.emit('app:served');
55
- console.log();
56
- console.log('Service', (0, chalk_1.bold) `${oox.config.name}`, 'running.');
57
- if (!httpConfig.disabled)
58
- console.log(' at', chalk_1.underline.green `http://${oox.config.host}:${httpConfig.port}${httpConfig.path}`);
59
- if (!socketioConfig.disabled)
60
- console.log(' at', chalk_1.underline.green `ws://${oox.config.host}:${socketioConfig.port}${socketioConfig.path}`);
61
- console.log();
62
- // 服务注册
63
- if (env.registry)
64
- (0, register_1.registry)(env.registry);
65
- }
66
- exports.startup = startup;
1
+ import * as path from 'node:path';
2
+ import chalk from 'chalk';
3
+ import * as oox from '../index.js';
4
+ import { buildConfig } from './configurer.js';
5
+ import { registry } from './register.js';
6
+ function getEntryInfo(env, entryFilename) {
7
+ const entryMatchRegExp = /(\w+)\.((\w?js)|(ts\w?))$/;
8
+ if (!entryFilename) {
9
+ const args = process.argv.slice(2);
10
+ entryFilename = args.find(arg => !arg.includes('=') && entryMatchRegExp.test(arg));
11
+ }
12
+ if (!entryFilename)
13
+ throw new Error('Cannot find entry file: ' + entryFilename);
14
+ const fullPath = path.resolve(entryFilename);
15
+ const filename = path.basename(fullPath);
16
+ const fullDirectory = path.dirname(fullPath);
17
+ const directory = fullDirectory.split(path.sep).pop();
18
+ const groupFullDirectory = env.group ? path.resolve(env.group) : '';
19
+ const entryMatch = filename.match(entryMatchRegExp);
20
+ const entryFilenameWithoutExtension = entryMatch[1];
21
+ const name = entryFilenameWithoutExtension === 'index' && groupFullDirectory !== fullDirectory ? directory : entryFilenameWithoutExtension;
22
+ return { name, path: fullPath, group: groupFullDirectory };
23
+ }
24
+ async function loadEntry(name, entryPath) {
25
+ // oox.config.name = name
26
+ const methods = await import(`file://${entryPath.replace(/\\/g, '/')}`);
27
+ oox.setMethods(methods.default || methods);
28
+ }
29
+ export async function configure(env, entryFilename) {
30
+ // 加载环境变量
31
+ env = await buildConfig(env);
32
+ Object.assign(oox.config, env);
33
+ // 获取服务入口地址
34
+ const entryInfo = getEntryInfo(env, entryFilename);
35
+ oox.config.name = entryInfo.name;
36
+ oox.config.entryInfo = {
37
+ path: entryInfo.path.replace(/\\/g, '/'),
38
+ group: entryInfo.group.replace(/\\/g, '/'),
39
+ };
40
+ // 模块配置
41
+ oox.modules.setConfig(oox.config);
42
+ oox.emit('app:configured');
43
+ return oox.config;
44
+ }
45
+ export async function startup() {
46
+ const { config } = oox;
47
+ // 加载服务
48
+ await loadEntry(config.name, config.entryInfo.path);
49
+ // 服务启动
50
+ await oox.serve();
51
+ oox.emit('app:served');
52
+ const { http, socketio } = oox.modules.builtins;
53
+ console.log();
54
+ console.log('Service', chalk.bold(`${oox.config.name}`), 'running.');
55
+ if (http.config.enabled)
56
+ console.log(' at', chalk.underline.green(http.getUrl()));
57
+ if (socketio.config.enabled)
58
+ console.log(' at', chalk.underline.green(socketio.getUrl()));
59
+ console.log();
60
+ // 服务注册
61
+ if (config.registry)
62
+ registry(config.registry);
63
+ }