oox 0.3.0-beta13 → 0.3.0-beta14
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.
- package/LICENSE +21 -21
- package/README.md +32 -32
- package/app.js +29 -41
- package/bin/argv.js +4 -11
- package/bin/cli.js +19 -19
- package/bin/configurer.js +5 -9
- package/bin/loader.mjs +379 -459
- package/bin/proxyer.js +8 -10
- package/bin/register.js +6 -10
- package/bin/starter.js +42 -34
- package/index.js +44 -59
- package/index.mjs +4 -4
- package/logger.js +13 -20
- package/modules/http/index.js +35 -24
- package/modules/http/utils.js +11 -16
- package/modules/index.js +6 -9
- package/modules/module.js +2 -7
- package/modules/socketio/client.js +8 -11
- package/modules/socketio/index.js +17 -21
- package/modules/socketio/server.js +11 -16
- package/modules/socketio/socket.js +1 -4
- package/package.json +7 -7
- package/types/app.d.ts +2 -4
- package/types/bin/cli.d.ts +2 -2
- package/types/bin/configurer.d.ts +1 -1
- package/types/bin/proxyer.d.ts +1 -1
- package/types/bin/starter.d.ts +5 -2
- package/types/index.d.ts +7 -6
- package/types/modules/http/index.d.ts +6 -3
- package/types/modules/http/utils.d.ts +0 -3
- package/types/modules/index.d.ts +3 -3
- package/types/modules/socketio/client.d.ts +2 -2
- package/types/modules/socketio/index.d.ts +4 -4
- package/types/modules/socketio/server.d.ts +2 -3
- package/types/modules/socketio/socket.d.ts +2 -2
- package/utils.js +5 -11
package/bin/proxyer.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const node_module_1 = require("node:module");
|
|
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);
|
|
8
7
|
/**
|
|
9
8
|
* 重写 require 缓存
|
|
10
9
|
*/
|
|
@@ -12,7 +11,7 @@ function rewriteModuleCache(id, exports) {
|
|
|
12
11
|
const pathname = id.split(path.sep).slice(0, -1).join(path.sep);
|
|
13
12
|
const pathSplit = pathname.split(path.sep);
|
|
14
13
|
const paths = pathSplit.map((v, i, a) => a.slice(0, i + 1).concat('node_modules').join(path.sep)).reverse();
|
|
15
|
-
const m = new
|
|
14
|
+
const m = new Module(id);
|
|
16
15
|
m.path = pathname;
|
|
17
16
|
m.exports = exports;
|
|
18
17
|
m.filename = m.id;
|
|
@@ -32,7 +31,7 @@ function dotCall(name, action) {
|
|
|
32
31
|
}
|
|
33
32
|
});
|
|
34
33
|
}
|
|
35
|
-
function proxyGroup(groupDirectory, excludes = []) {
|
|
34
|
+
export function proxyGroup(groupDirectory, excludes = []) {
|
|
36
35
|
if (!groupDirectory)
|
|
37
36
|
return;
|
|
38
37
|
const directory = path.resolve(groupDirectory);
|
|
@@ -63,4 +62,3 @@ function proxyGroup(groupDirectory, excludes = []) {
|
|
|
63
62
|
rewriteModuleCache(id, dotCall(name, ''));
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
|
-
exports.proxyGroup = proxyGroup;
|
package/bin/register.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.registry = void 0;
|
|
4
|
-
const chalk_1 = require("chalk");
|
|
5
|
-
const oox = require("../index");
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as oox from '../index.js';
|
|
6
3
|
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
7
4
|
function urlFormatter(url) {
|
|
8
5
|
// :6000
|
|
@@ -31,7 +28,7 @@ async function connect(url, prevError = null) {
|
|
|
31
28
|
}
|
|
32
29
|
catch (error) {
|
|
33
30
|
if (!prevError)
|
|
34
|
-
console.log(
|
|
31
|
+
console.log(chalk.red `[Registry]`, chalk.underline.red `${url}`, 'error.');
|
|
35
32
|
await delay(5000);
|
|
36
33
|
connect(url, error);
|
|
37
34
|
}
|
|
@@ -39,17 +36,16 @@ async function connect(url, prevError = null) {
|
|
|
39
36
|
async function onConnection(socket, url) {
|
|
40
37
|
const { name } = socket.data;
|
|
41
38
|
socket.on('disconnect', async () => {
|
|
42
|
-
console.log(
|
|
39
|
+
console.log(chalk.red `[Registry]`, `Service<${name}>`, chalk.underline.red `${url}`, 'disconnected.');
|
|
43
40
|
await delay(1000);
|
|
44
41
|
connect(url);
|
|
45
42
|
});
|
|
46
|
-
console.log(
|
|
43
|
+
console.log(chalk.green `[Registry]`, `Service<${name}>`, chalk.underline.green `${url}`, 'connected.');
|
|
47
44
|
}
|
|
48
|
-
async function registry(urls) {
|
|
45
|
+
export async function registry(urls) {
|
|
49
46
|
if ('string' === typeof urls)
|
|
50
47
|
urls = [urls];
|
|
51
48
|
for (const url of urls) {
|
|
52
49
|
connect(urlFormatter(url));
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
|
-
exports.registry = registry;
|
package/bin/starter.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const register_1 = require("./register");
|
|
10
|
-
function getEntryFile(env, entryFilename) {
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { register } from "node:module";
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import * as oox from '../index.js';
|
|
5
|
+
import { proxyGroup } from './proxyer.js';
|
|
6
|
+
import { buildConfig } from './configurer.js';
|
|
7
|
+
import { registry } from './register.js';
|
|
8
|
+
function getEntryInfo(env, entryFilename) {
|
|
11
9
|
const entryMatchRegExp = /(\w+)\.((\w?js)|(ts\w?))$/;
|
|
12
10
|
if (!entryFilename) {
|
|
13
11
|
const args = process.argv.slice(2);
|
|
@@ -22,50 +20,60 @@ function getEntryFile(env, entryFilename) {
|
|
|
22
20
|
const groupFullDirectory = env.group ? path.resolve(env.group) : '';
|
|
23
21
|
const entryMatch = filename.match(entryMatchRegExp);
|
|
24
22
|
const entryFilenameWithoutExtension = entryMatch[1];
|
|
25
|
-
|
|
23
|
+
const name = entryFilenameWithoutExtension === 'index' && groupFullDirectory !== fullDirectory ? directory : entryFilenameWithoutExtension;
|
|
26
24
|
return { name, path: fullPath, group: groupFullDirectory };
|
|
27
25
|
}
|
|
28
26
|
async function loadEntry(name, entryPath) {
|
|
29
|
-
oox.config.name = name
|
|
30
|
-
|
|
31
|
-
const methods = await eval(`import('file://${entryPath.replace(/\\/g, '/')}')`);
|
|
27
|
+
// oox.config.name = name
|
|
28
|
+
const methods = await import(`file://${entryPath.replace(/\\/g, '/')}`);
|
|
32
29
|
oox.setMethods(methods.default || methods);
|
|
33
30
|
}
|
|
34
|
-
async function
|
|
31
|
+
export async function registLoader() {
|
|
32
|
+
register(import.meta.resolve('oox/loader'), import.meta.url, {
|
|
33
|
+
data: {
|
|
34
|
+
ooxConfig: oox.config
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export async function configure(env, entryFilename) {
|
|
35
39
|
// 加载环境变量
|
|
36
|
-
env = await (
|
|
40
|
+
env = await buildConfig(env);
|
|
37
41
|
Object.assign(oox.config, env);
|
|
38
42
|
// 获取服务入口地址
|
|
39
|
-
const
|
|
40
|
-
oox.config.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
const entryInfo = getEntryInfo(env, entryFilename);
|
|
44
|
+
oox.config.name = entryInfo.name;
|
|
45
|
+
oox.config.entryInfo = {
|
|
46
|
+
path: entryInfo.path.replace(/\\/g, '/'),
|
|
47
|
+
group: entryInfo.group.replace(/\\/g, '/'),
|
|
43
48
|
};
|
|
44
49
|
// 模块配置
|
|
45
50
|
oox.modules.setConfig(oox.config);
|
|
46
51
|
oox.emit('app:configured');
|
|
47
|
-
|
|
52
|
+
return oox.config;
|
|
53
|
+
}
|
|
54
|
+
export async function startup() {
|
|
55
|
+
const { config } = oox;
|
|
48
56
|
// 代理<服务间调用>
|
|
49
|
-
if (
|
|
50
|
-
const excludes = [
|
|
51
|
-
if (Array.isArray(
|
|
52
|
-
excludes.push(...
|
|
53
|
-
|
|
57
|
+
if (config.entryInfo.group) {
|
|
58
|
+
const excludes = [config.name];
|
|
59
|
+
if (Array.isArray(config.ignore))
|
|
60
|
+
excludes.push(...config.ignore);
|
|
61
|
+
proxyGroup(config.entryInfo.group, excludes);
|
|
54
62
|
}
|
|
63
|
+
// 加载服务
|
|
64
|
+
await loadEntry(config.name, config.entryInfo.path);
|
|
55
65
|
// 服务启动
|
|
56
66
|
await oox.serve();
|
|
57
|
-
// 加载服务
|
|
58
|
-
await loadEntry(entryFile.name, entryFile.path);
|
|
59
67
|
oox.emit('app:served');
|
|
68
|
+
const { http: { config: httpConfig }, socketio: { config: socketioConfig } } = oox.modules.builtins;
|
|
60
69
|
console.log();
|
|
61
|
-
console.log('Service',
|
|
70
|
+
console.log('Service', chalk.bold `${oox.config.name}`, 'running.');
|
|
62
71
|
if (!httpConfig.disabled)
|
|
63
|
-
console.log(' at',
|
|
72
|
+
console.log(' at', chalk.underline.green `http://${oox.config.host}:${httpConfig.port}${httpConfig.path}`);
|
|
64
73
|
if (!socketioConfig.disabled)
|
|
65
|
-
console.log(' at',
|
|
74
|
+
console.log(' at', chalk.underline.green `ws://${oox.config.host}:${socketioConfig.port}${socketioConfig.path}`);
|
|
66
75
|
console.log();
|
|
67
76
|
// 服务注册
|
|
68
|
-
if (
|
|
69
|
-
|
|
77
|
+
if (config.registry)
|
|
78
|
+
registry(config.registry);
|
|
70
79
|
}
|
|
71
|
-
exports.startup = startup;
|
package/index.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const modules_1 = require("./modules");
|
|
11
|
-
exports.modules = new modules_1.default;
|
|
12
|
-
exports.asyncStore = app.asyncStore, exports.setMethods = app.setMethods, exports.getMethods = app.getMethods, exports.kvMethods = app.kvMethods, exports.sourceKVMethods = app.sourceKVMethods, exports.call = app.call, exports.execute = app.execute, exports.logger = app.logger, exports.on = app.on, exports.once = app.once, exports.off = app.off, exports.emit = app.emit;
|
|
13
|
-
class Context extends app.Context {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import * as app from './app.js';
|
|
3
|
+
import { getIPAddress } from './utils.js';
|
|
4
|
+
import Module, { ModuleConfig } from './modules/module.js';
|
|
5
|
+
import Modules from './modules/index.js';
|
|
6
|
+
export { Module, ModuleConfig };
|
|
7
|
+
export const modules = new Modules;
|
|
8
|
+
export const { asyncStore, setMethods, getMethods, kvMethods, sourceKVMethods, call, execute, logger, on, once, off, emit, } = app;
|
|
9
|
+
export class Context extends app.Context {
|
|
14
10
|
// 请求溯源IP
|
|
15
11
|
sourceIP = '';
|
|
16
12
|
// 请求者IP
|
|
@@ -27,42 +23,42 @@ class Context extends app.Context {
|
|
|
27
23
|
return context;
|
|
28
24
|
}
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
class Config {
|
|
26
|
+
export class Config {
|
|
32
27
|
// 服务名称
|
|
33
28
|
name = 'local';
|
|
29
|
+
// 服务列表路径
|
|
30
|
+
group = '';
|
|
31
|
+
// 非服务模块
|
|
32
|
+
ignore = [];
|
|
34
33
|
// 启动文件
|
|
35
|
-
|
|
34
|
+
entryInfo = {
|
|
36
35
|
// 启动文件路径
|
|
37
36
|
path: '',
|
|
38
37
|
// 服务列表路径
|
|
39
38
|
group: '',
|
|
40
39
|
};
|
|
41
40
|
// 主机地址
|
|
42
|
-
host =
|
|
41
|
+
host = getIPAddress(4)[0];
|
|
43
42
|
// 默认监听端口
|
|
44
43
|
port = 0;
|
|
45
44
|
// 默认跨域设置
|
|
46
45
|
origin = '';
|
|
47
46
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
function setGenTraceIdFunction(fn) {
|
|
47
|
+
export const config = new Config();
|
|
48
|
+
let genTraceIdFunction = () => randomUUID();
|
|
49
|
+
export function setGenTraceIdFunction(fn) {
|
|
52
50
|
genTraceIdFunction = fn;
|
|
53
51
|
}
|
|
54
|
-
exports.setGenTraceIdFunction = setGenTraceIdFunction;
|
|
55
52
|
/**
|
|
56
53
|
* 生成随机不重复id
|
|
57
54
|
*/
|
|
58
|
-
function genTraceId() {
|
|
55
|
+
export function genTraceId() {
|
|
59
56
|
return genTraceIdFunction();
|
|
60
57
|
}
|
|
61
|
-
exports.genTraceId = genTraceId;
|
|
62
58
|
/**
|
|
63
59
|
* 获取链路跟踪上下文
|
|
64
60
|
*/
|
|
65
|
-
function genContext(context) {
|
|
61
|
+
export function genContext(context) {
|
|
66
62
|
const newContext = Object.assign(new Context(), context);
|
|
67
63
|
if (!newContext.traceId)
|
|
68
64
|
newContext.traceId = genTraceId();
|
|
@@ -70,21 +66,17 @@ function genContext(context) {
|
|
|
70
66
|
newContext.sourceIP = newContext.ip;
|
|
71
67
|
return newContext;
|
|
72
68
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const context = exports.asyncStore.getStore();
|
|
69
|
+
export function getContext() {
|
|
70
|
+
const context = asyncStore.getStore();
|
|
76
71
|
return context || genContext();
|
|
77
72
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
await exports.modules.serve();
|
|
73
|
+
export async function serve() {
|
|
74
|
+
await modules.serve();
|
|
81
75
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await exports.modules.stop();
|
|
76
|
+
export async function stop() {
|
|
77
|
+
await modules.stop();
|
|
85
78
|
}
|
|
86
|
-
|
|
87
|
-
class RPCKeepAliveConnection {
|
|
79
|
+
export class RPCKeepAliveConnection {
|
|
88
80
|
data;
|
|
89
81
|
nativeConnection = null;
|
|
90
82
|
adapter = null;
|
|
@@ -95,60 +87,54 @@ class RPCKeepAliveConnection {
|
|
|
95
87
|
this.data = data;
|
|
96
88
|
}
|
|
97
89
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return exports.keepAliveConnections.get(name) || new Map();
|
|
90
|
+
export const keepAliveConnections = new Map();
|
|
91
|
+
export function getKeepAliveConnections(name) {
|
|
92
|
+
return keepAliveConnections.get(name) || new Map();
|
|
102
93
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const connections = exports.keepAliveConnections.get(name);
|
|
94
|
+
export function getKeepAliveConnection(name, id) {
|
|
95
|
+
const connections = keepAliveConnections.get(name);
|
|
106
96
|
if (!connections)
|
|
107
97
|
return null;
|
|
108
98
|
return connections.get(id);
|
|
109
99
|
}
|
|
110
|
-
|
|
111
|
-
function addKeepAliveConnection(connection) {
|
|
100
|
+
export function addKeepAliveConnection(connection) {
|
|
112
101
|
const { name, id } = connection.data;
|
|
113
|
-
if (
|
|
114
|
-
|
|
102
|
+
if (keepAliveConnections.has(name)) {
|
|
103
|
+
keepAliveConnections.get(name).set(id, connection);
|
|
115
104
|
}
|
|
116
105
|
else {
|
|
117
|
-
|
|
106
|
+
keepAliveConnections.set(name, new Map([[id, connection]]));
|
|
118
107
|
}
|
|
119
108
|
}
|
|
120
|
-
|
|
121
|
-
function removeKeepAliveConnection(name, id) {
|
|
109
|
+
export function removeKeepAliveConnection(name, id) {
|
|
122
110
|
if (name instanceof RPCKeepAliveConnection) {
|
|
123
111
|
id = name.data.id;
|
|
124
112
|
name = name.data.name;
|
|
125
113
|
}
|
|
126
|
-
if (
|
|
127
|
-
const group =
|
|
114
|
+
if (keepAliveConnections.has(name)) {
|
|
115
|
+
const group = keepAliveConnections.get(name);
|
|
128
116
|
group.delete(id);
|
|
129
117
|
if (!group.size)
|
|
130
|
-
|
|
118
|
+
keepAliveConnections.delete(name);
|
|
131
119
|
}
|
|
132
120
|
}
|
|
133
|
-
exports.removeKeepAliveConnection = removeKeepAliveConnection;
|
|
134
121
|
/**
|
|
135
122
|
* random connection select for default load balance policy
|
|
136
123
|
* @param name service name
|
|
137
124
|
* @returns selected connection
|
|
138
125
|
*/
|
|
139
126
|
let loadBalancePolicy = (name) => {
|
|
140
|
-
const connections =
|
|
127
|
+
const connections = keepAliveConnections.get(name);
|
|
141
128
|
if (!connections || !connections.size)
|
|
142
129
|
return null;
|
|
143
130
|
const arrayConnections = Array.from(connections.values());
|
|
144
131
|
const index = Math.floor(Math.random() * arrayConnections.length);
|
|
145
132
|
return arrayConnections[index];
|
|
146
133
|
};
|
|
147
|
-
function setLoadBalancePolicy(policy) {
|
|
134
|
+
export function setLoadBalancePolicy(policy) {
|
|
148
135
|
loadBalancePolicy = policy;
|
|
149
136
|
}
|
|
150
|
-
|
|
151
|
-
async function rpc(arg1, action, params, context) {
|
|
137
|
+
export async function rpc(arg1, action, params, context) {
|
|
152
138
|
if (!context || !context.traceId) {
|
|
153
139
|
context = getContext();
|
|
154
140
|
}
|
|
@@ -165,4 +151,3 @@ async function rpc(arg1, action, params, context) {
|
|
|
165
151
|
throw new Error(`Unknown rpc arg1<${arg1}>`);
|
|
166
152
|
return connection.adapter.rpc(connection.nativeConnection, action, params, context);
|
|
167
153
|
}
|
|
168
|
-
exports.rpc = rpc;
|
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import * as oox from './index.js'
|
|
3
|
-
|
|
4
|
-
export * from './index.js'
|
|
1
|
+
|
|
2
|
+
import * as oox from './index.js'
|
|
3
|
+
|
|
4
|
+
export * from './index.js'
|
|
5
5
|
export default oox
|
package/logger.js
CHANGED
|
@@ -1,40 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const app_1 = require("./app");
|
|
5
|
-
function info(...msgs) {
|
|
6
|
-
const context = app_1.asyncStore.getStore();
|
|
1
|
+
import { eventHub, asyncStore } from './app.js';
|
|
2
|
+
export function info(...msgs) {
|
|
3
|
+
const context = asyncStore.getStore();
|
|
7
4
|
if (context)
|
|
8
|
-
|
|
5
|
+
eventHub.emit('log', context, 'info', msgs);
|
|
9
6
|
else
|
|
10
7
|
console.info('[INFO]', ...msgs);
|
|
11
8
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const context = app_1.asyncStore.getStore();
|
|
9
|
+
export function warn(...msgs) {
|
|
10
|
+
const context = asyncStore.getStore();
|
|
15
11
|
if (context)
|
|
16
|
-
|
|
12
|
+
eventHub.emit('log', context, 'warn', msgs);
|
|
17
13
|
else
|
|
18
14
|
console.warn('[WARN]', ...msgs);
|
|
19
15
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const context = app_1.asyncStore.getStore();
|
|
16
|
+
export function error(...msgs) {
|
|
17
|
+
const context = asyncStore.getStore();
|
|
23
18
|
if (context)
|
|
24
|
-
|
|
19
|
+
eventHub.emit('log', context, 'error', msgs);
|
|
25
20
|
else
|
|
26
21
|
console.error('[ERROR]', ...msgs);
|
|
27
22
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const context = app_1.asyncStore.getStore();
|
|
23
|
+
export function trace(name) {
|
|
24
|
+
const context = asyncStore.getStore();
|
|
31
25
|
const trace = { stack: '' };
|
|
32
26
|
Error.captureStackTrace(trace);
|
|
33
27
|
const stack = trace.stack
|
|
34
28
|
.replace(/.*\n.*logger.js.*\n/, name || 'Untitle\n');
|
|
35
29
|
if (context)
|
|
36
|
-
|
|
30
|
+
eventHub.emit('log', context, 'trace', stack);
|
|
37
31
|
else
|
|
38
32
|
console.log('[TRACE]', stack);
|
|
39
33
|
}
|
|
40
|
-
exports.trace = trace;
|
package/modules/http/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const oox = require("../../index");
|
|
8
|
-
const module_1 = require("../module");
|
|
9
|
-
class HTTPConfig extends module_1.ModuleConfig {
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
import { parse as parseQueryString } from 'node:querystring';
|
|
3
|
+
import { httpRequest, parseHTTPBody } from './utils.js';
|
|
4
|
+
import * as oox from '../../index.js';
|
|
5
|
+
import Module, { ModuleConfig } from '../module.js';
|
|
6
|
+
export class HTTPConfig extends ModuleConfig {
|
|
10
7
|
// listen port
|
|
11
8
|
port = 0;
|
|
12
9
|
// service path
|
|
@@ -14,8 +11,7 @@ class HTTPConfig extends module_1.ModuleConfig {
|
|
|
14
11
|
// browser cross origin
|
|
15
12
|
origin = '';
|
|
16
13
|
}
|
|
17
|
-
|
|
18
|
-
class HTTPModule extends module_1.default {
|
|
14
|
+
export default class HTTPModule extends Module {
|
|
19
15
|
name = 'http';
|
|
20
16
|
config = new HTTPConfig;
|
|
21
17
|
server = null;
|
|
@@ -86,11 +82,34 @@ class HTTPModule extends module_1.default {
|
|
|
86
82
|
}
|
|
87
83
|
return true;
|
|
88
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* 从请求里获取调用的接口和参数
|
|
87
|
+
*/
|
|
88
|
+
async getCallArgsFromRequest(request) {
|
|
89
|
+
let args = Object.create(null);
|
|
90
|
+
const querys = parseQueryString(request.url.split('?').pop() || '');
|
|
91
|
+
if ('GET' === request.method) {
|
|
92
|
+
args = querys;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const postData = await parseHTTPBody(request);
|
|
96
|
+
if (querys.action) {
|
|
97
|
+
args.action = querys.action;
|
|
98
|
+
args.params = Array.isArray(postData) ? postData : [postData];
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
args = postData;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!args || 'object' !== typeof args)
|
|
105
|
+
throw new Error('Content Invalid');
|
|
106
|
+
}
|
|
89
107
|
/**
|
|
90
108
|
* HTTP-RPC服务器请求监听方法
|
|
91
109
|
*/
|
|
92
110
|
async call(request, response) {
|
|
93
|
-
|
|
111
|
+
const url = new URL(request.url, this.config.origin || 'http://127.0.0.1');
|
|
112
|
+
if (url.pathname !== this.config.path) {
|
|
94
113
|
const error = {
|
|
95
114
|
message: 'Invalid URL',
|
|
96
115
|
stack: ''
|
|
@@ -103,16 +122,9 @@ class HTTPModule extends module_1.default {
|
|
|
103
122
|
}
|
|
104
123
|
if (!this.cors(request, response))
|
|
105
124
|
return;
|
|
106
|
-
let
|
|
125
|
+
let callArgs = Object.create(null);
|
|
107
126
|
try {
|
|
108
|
-
|
|
109
|
-
body = (0, node_querystring_1.parse)(request.url.split('?').pop());
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
body = await (0, utils_1.parseHTTPBody)(request);
|
|
113
|
-
}
|
|
114
|
-
if (!body || 'object' !== typeof body)
|
|
115
|
-
throw new Error('Content Invalid');
|
|
127
|
+
callArgs = await this.getCallArgsFromRequest(request);
|
|
116
128
|
}
|
|
117
129
|
catch (error) {
|
|
118
130
|
return this.respond(request, response, {
|
|
@@ -131,7 +143,7 @@ class HTTPModule extends module_1.default {
|
|
|
131
143
|
const ip = String(request.headers['x-ip'] || request.socket.remoteAddress || '');
|
|
132
144
|
// startup client ip
|
|
133
145
|
const sourceIP = String(request.headers['x-real-ip'] || '');
|
|
134
|
-
const { action = 'index', params = [] } =
|
|
146
|
+
const { action = 'index', params = [] } = callArgs;
|
|
135
147
|
const context = oox.genContext({ traceId, caller, sourceIP, ip, callerId: '' });
|
|
136
148
|
const format = await oox.call(action, params, context);
|
|
137
149
|
this.respond(request, response, format);
|
|
@@ -174,7 +186,7 @@ class HTTPModule extends module_1.default {
|
|
|
174
186
|
if (sourceIP)
|
|
175
187
|
headers['x-real-ip'] = sourceIP;
|
|
176
188
|
// headers [ 'x-ip' ] = getIPAddress ( 4 ) [ 0 ]
|
|
177
|
-
const format = await
|
|
189
|
+
const format = await httpRequest(url, {
|
|
178
190
|
headers
|
|
179
191
|
}, JSON.stringify({ action, params }));
|
|
180
192
|
if ('string' === typeof format)
|
|
@@ -189,4 +201,3 @@ class HTTPModule extends module_1.default {
|
|
|
189
201
|
}
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
|
-
exports.default = HTTPModule;
|
package/modules/http/utils.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.httpRequest = exports.parseHTTPBody = exports.stream2buffer = void 0;
|
|
4
|
-
const http = require("node:http");
|
|
1
|
+
import * as http from 'node:http';
|
|
5
2
|
/**
|
|
6
3
|
* Stream => Buffer
|
|
7
4
|
*/
|
|
8
|
-
function stream2buffer(stream, totalLength = 0) {
|
|
5
|
+
export function stream2buffer(stream, totalLength = 0) {
|
|
9
6
|
return new Promise(function (resolve, reject) {
|
|
10
7
|
let buffers = [];
|
|
11
8
|
stream.on('error', reject);
|
|
@@ -21,11 +18,10 @@ function stream2buffer(stream, totalLength = 0) {
|
|
|
21
18
|
stream.on('end', function () { resolve(Buffer.concat(buffers, totalLength)); });
|
|
22
19
|
});
|
|
23
20
|
}
|
|
24
|
-
exports.stream2buffer = stream2buffer;
|
|
25
21
|
/**
|
|
26
22
|
* Request => JSONObject
|
|
27
23
|
*/
|
|
28
|
-
async function parseHTTPBody(request) {
|
|
24
|
+
export async function parseHTTPBody(request) {
|
|
29
25
|
if (request.method === 'GET')
|
|
30
26
|
return null;
|
|
31
27
|
let contentType = request.headers['content-type'];
|
|
@@ -36,19 +32,19 @@ async function parseHTTPBody(request) {
|
|
|
36
32
|
const buffer = await stream2buffer(request, +contentSize || 0);
|
|
37
33
|
if (contentSize && buffer.length !== +contentSize)
|
|
38
34
|
throw new Error('Content-Length Incorrect');
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
switch (contentType) {
|
|
36
|
+
case 'application/json':
|
|
37
|
+
return JSON.parse(buffer.toString());
|
|
38
|
+
case 'text/plain':
|
|
39
|
+
return buffer.toString();
|
|
40
|
+
default:
|
|
41
|
+
return buffer;
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
|
-
exports.parseHTTPBody = parseHTTPBody;
|
|
48
44
|
/**
|
|
49
45
|
* http request
|
|
50
46
|
*/
|
|
51
|
-
function httpRequest(url, options, body) {
|
|
47
|
+
export function httpRequest(url, options, body) {
|
|
52
48
|
return new Promise(function (resolve, reject) {
|
|
53
49
|
const request = http.request(url, options, async function (response) {
|
|
54
50
|
try {
|
|
@@ -70,4 +66,3 @@ function httpRequest(url, options, body) {
|
|
|
70
66
|
request.end();
|
|
71
67
|
});
|
|
72
68
|
}
|
|
73
|
-
exports.httpRequest = httpRequest;
|
package/modules/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const socketio_1 = require("./socketio");
|
|
6
|
-
class Modules extends module_1.default {
|
|
1
|
+
import Module from './module.js';
|
|
2
|
+
import HTTP from './http/index.js';
|
|
3
|
+
import SocketIO from './socketio/index.js';
|
|
4
|
+
export default class Modules extends Module {
|
|
7
5
|
/**
|
|
8
6
|
* the module unique name
|
|
9
7
|
*/
|
|
@@ -20,8 +18,8 @@ class Modules extends module_1.default {
|
|
|
20
18
|
* all builtin modules
|
|
21
19
|
*/
|
|
22
20
|
builtins = {
|
|
23
|
-
http: new
|
|
24
|
-
socketio: new
|
|
21
|
+
http: new HTTP,
|
|
22
|
+
socketio: new SocketIO,
|
|
25
23
|
};
|
|
26
24
|
constructor() {
|
|
27
25
|
super();
|
|
@@ -85,4 +83,3 @@ class Modules extends module_1.default {
|
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
|
-
exports.default = Modules;
|
package/modules/module.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ModuleConfig = void 0;
|
|
4
|
-
class ModuleConfig {
|
|
1
|
+
export class ModuleConfig {
|
|
5
2
|
disabled = false;
|
|
6
3
|
}
|
|
7
|
-
|
|
8
|
-
class Module {
|
|
4
|
+
export default class Module {
|
|
9
5
|
config;
|
|
10
6
|
name;
|
|
11
7
|
setConfig(config) { }
|
|
@@ -13,4 +9,3 @@ class Module {
|
|
|
13
9
|
async serve() { }
|
|
14
10
|
async stop() { }
|
|
15
11
|
}
|
|
16
|
-
exports.default = Module;
|