@yumerijs/core 1.2.0 → 1.3.0
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/dist/command.d.ts +1 -1
- package/dist/command.js +1 -1
- package/dist/context.d.ts +42 -10
- package/dist/context.js +84 -40
- package/dist/core.d.ts +46 -58
- package/dist/core.js +81 -146
- package/dist/hook.d.ts +39 -0
- package/dist/hook.js +51 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -3
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +3 -3
- package/dist/middleware.d.ts +5 -0
- package/dist/platform.d.ts +5 -0
- package/dist/platform.js +5 -0
- package/dist/route.d.ts +5 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.js +231 -0
- package/dist/session.d.ts +7 -3
- package/dist/session.js +10 -5
- package/package.json +1 -2
package/dist/command.d.ts
CHANGED
package/dist/command.js
CHANGED
package/dist/context.d.ts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @time: 2025/08/14 19:10
|
|
3
|
+
* @author: FireGuo
|
|
4
|
+
* WindyPear-Team All right reserved
|
|
5
|
+
**/
|
|
1
6
|
import { Core } from './core';
|
|
2
|
-
import { Command } from './command';
|
|
3
7
|
import { Route } from './route';
|
|
8
|
+
import { HookHandler } from './hook';
|
|
9
|
+
/**
|
|
10
|
+
* 插件上下文对象
|
|
11
|
+
* 每个插件一个 Context,用于管理插件注册的命令、路由、事件、组件和中间件
|
|
12
|
+
*/
|
|
4
13
|
export declare class Context {
|
|
5
14
|
private core;
|
|
15
|
+
private routes;
|
|
16
|
+
private eventlisteners;
|
|
17
|
+
private components;
|
|
18
|
+
private middlewares;
|
|
19
|
+
private hooks;
|
|
20
|
+
/**
|
|
21
|
+
* 插件名称
|
|
22
|
+
*/
|
|
6
23
|
pluginname: string;
|
|
7
24
|
/**
|
|
8
25
|
* 创建 Context 实例
|
|
@@ -10,14 +27,10 @@ export declare class Context {
|
|
|
10
27
|
* @param pluginname 插件名称
|
|
11
28
|
*/
|
|
12
29
|
constructor(core: Core, pluginname: string);
|
|
13
|
-
/**
|
|
14
|
-
* @deprecated Use route() instead.
|
|
15
|
-
*/
|
|
16
|
-
command(name: string): Command;
|
|
17
30
|
/**
|
|
18
31
|
* 注册路由
|
|
19
32
|
* @param path 路由路径
|
|
20
|
-
* @returns Route
|
|
33
|
+
* @returns Route 实例
|
|
21
34
|
*/
|
|
22
35
|
route(path: string): Route;
|
|
23
36
|
/**
|
|
@@ -33,8 +46,23 @@ export declare class Context {
|
|
|
33
46
|
*/
|
|
34
47
|
use(name: string, callback: Function): void;
|
|
35
48
|
/**
|
|
36
|
-
*
|
|
37
|
-
|
|
49
|
+
* 注册 Hook 钩子
|
|
50
|
+
* @param name Hook 点名称
|
|
51
|
+
* @param hookname 钩子名称
|
|
52
|
+
* @param callback 钩子回调函数
|
|
53
|
+
*/
|
|
54
|
+
hook(name: string, hookname: string, callback: HookHandler): void;
|
|
55
|
+
/**
|
|
56
|
+
* 执行 Hook 钩子
|
|
57
|
+
* @param name Hook 点名称
|
|
58
|
+
* @param args Hook 参数
|
|
59
|
+
* @returns Promise<any[]>
|
|
60
|
+
*/
|
|
61
|
+
executeHook(name: string, ...args: any[]): Promise<any[]>;
|
|
62
|
+
/**
|
|
63
|
+
* 获取 Core 实例
|
|
64
|
+
* @returns Core
|
|
65
|
+
*/
|
|
38
66
|
getCore(): Core;
|
|
39
67
|
/**
|
|
40
68
|
* 触发事件
|
|
@@ -45,7 +73,7 @@ export declare class Context {
|
|
|
45
73
|
emit(event: string, ...args: any[]): Promise<void>;
|
|
46
74
|
/**
|
|
47
75
|
* 获取组件实例
|
|
48
|
-
* @param name
|
|
76
|
+
* @param name 组件名称
|
|
49
77
|
* @returns 组件实例
|
|
50
78
|
*/
|
|
51
79
|
getComponent(name: string): any;
|
|
@@ -53,7 +81,11 @@ export declare class Context {
|
|
|
53
81
|
* 注册组件
|
|
54
82
|
* @param name 组件名称
|
|
55
83
|
* @param component 组件实例
|
|
56
|
-
* @returns void
|
|
57
84
|
*/
|
|
58
85
|
registerComponent(name: string, component: any): void;
|
|
86
|
+
/**
|
|
87
|
+
* 卸载插件时清理注册的所有资源
|
|
88
|
+
* 包括组件、路由、中间件和事件监听器
|
|
89
|
+
*/
|
|
90
|
+
dispose(): void;
|
|
59
91
|
}
|
package/dist/context.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Context = void 0;
|
|
4
|
-
const
|
|
4
|
+
const route_1 = require("./route");
|
|
5
|
+
/**
|
|
6
|
+
* 插件上下文对象
|
|
7
|
+
* 每个插件一个 Context,用于管理插件注册的命令、路由、事件、组件和中间件
|
|
8
|
+
*/
|
|
5
9
|
class Context {
|
|
6
10
|
core;
|
|
11
|
+
routes = [];
|
|
12
|
+
eventlisteners = [];
|
|
13
|
+
components = [];
|
|
14
|
+
middlewares = [];
|
|
15
|
+
hooks = {};
|
|
16
|
+
/**
|
|
17
|
+
* 插件名称
|
|
18
|
+
*/
|
|
7
19
|
pluginname;
|
|
8
20
|
/**
|
|
9
21
|
* 创建 Context 实例
|
|
@@ -14,33 +26,18 @@ class Context {
|
|
|
14
26
|
this.core = core;
|
|
15
27
|
this.pluginname = pluginname;
|
|
16
28
|
}
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated Use route() instead.
|
|
19
|
-
*/
|
|
20
|
-
command(name) {
|
|
21
|
-
if (this.core.commands[name]) {
|
|
22
|
-
this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register command "${name}", but it has been registered by plugin "${this.core.cmdtoplu[name]}."`);
|
|
23
|
-
return new command_1.Command(this.core, name);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
this.core.cmdtoplu[name] = this.pluginname;
|
|
27
|
-
return this.core.command(name);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
29
|
/**
|
|
31
30
|
* 注册路由
|
|
32
31
|
* @param path 路由路径
|
|
33
|
-
* @returns Route
|
|
32
|
+
* @returns Route 实例
|
|
34
33
|
*/
|
|
35
34
|
route(path) {
|
|
36
35
|
if (this.core.routes[path]) {
|
|
37
|
-
this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register route "${path}", but it has been registered
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
this.core.routetoplu[path] = this.pluginname;
|
|
42
|
-
return this.core.route(path);
|
|
36
|
+
this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register route "${path}", but it has already been registered.`);
|
|
37
|
+
return new route_1.Route(path);
|
|
43
38
|
}
|
|
39
|
+
this.routes.push(path);
|
|
40
|
+
return this.core.route(path);
|
|
44
41
|
}
|
|
45
42
|
/**
|
|
46
43
|
* 注册事件
|
|
@@ -48,14 +45,9 @@ class Context {
|
|
|
48
45
|
* @param listener 事件监听器
|
|
49
46
|
*/
|
|
50
47
|
on(name, listener) {
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
if (!this.core.evttoplu[name][this.pluginname]) {
|
|
56
|
-
this.core.evttoplu[name][this.pluginname] = [];
|
|
57
|
-
}
|
|
58
|
-
this.core.evttoplu[name][this.pluginname].push(listener);
|
|
48
|
+
// 记录插件自己的事件监听器
|
|
49
|
+
this.eventlisteners.push({ name, listener });
|
|
50
|
+
// 注册到 core 的全局事件监听器中
|
|
59
51
|
this.core.on(name, listener);
|
|
60
52
|
}
|
|
61
53
|
/**
|
|
@@ -64,14 +56,32 @@ class Context {
|
|
|
64
56
|
* @param callback 中间件回调函数
|
|
65
57
|
*/
|
|
66
58
|
use(name, callback) {
|
|
67
|
-
this.
|
|
68
|
-
this.core.use(name, async (...args) =>
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
this.middlewares.push(name);
|
|
60
|
+
this.core.use(name, async (...args) => callback(...args));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 注册 Hook 钩子
|
|
64
|
+
* @param name Hook 点名称
|
|
65
|
+
* @param hookname 钩子名称
|
|
66
|
+
* @param callback 钩子回调函数
|
|
67
|
+
*/
|
|
68
|
+
hook(name, hookname, callback) {
|
|
69
|
+
this.core.hook(name, hookname, callback);
|
|
70
|
+
this.hooks[name].push(hookname);
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
74
|
-
|
|
73
|
+
* 执行 Hook 钩子
|
|
74
|
+
* @param name Hook 点名称
|
|
75
|
+
* @param args Hook 参数
|
|
76
|
+
* @returns Promise<any[]>
|
|
77
|
+
*/
|
|
78
|
+
async executeHook(name, ...args) {
|
|
79
|
+
return await this.core.hookExecute(name, ...args);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 获取 Core 实例
|
|
83
|
+
* @returns Core
|
|
84
|
+
*/
|
|
75
85
|
getCore() {
|
|
76
86
|
return this.core;
|
|
77
87
|
}
|
|
@@ -86,7 +96,7 @@ class Context {
|
|
|
86
96
|
}
|
|
87
97
|
/**
|
|
88
98
|
* 获取组件实例
|
|
89
|
-
* @param name
|
|
99
|
+
* @param name 组件名称
|
|
90
100
|
* @returns 组件实例
|
|
91
101
|
*/
|
|
92
102
|
getComponent(name) {
|
|
@@ -96,16 +106,50 @@ class Context {
|
|
|
96
106
|
* 注册组件
|
|
97
107
|
* @param name 组件名称
|
|
98
108
|
* @param component 组件实例
|
|
99
|
-
* @returns void
|
|
100
109
|
*/
|
|
101
110
|
registerComponent(name, component) {
|
|
102
111
|
if (this.core.components[name]) {
|
|
103
|
-
this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register component "${name}", but it has been registered
|
|
112
|
+
this.core.logger.warn(`Plugin "${this.pluginname}" attempt to register component "${name}", but it has already been registered.`);
|
|
104
113
|
return;
|
|
105
114
|
}
|
|
106
|
-
this.core.comtoplu[name] = this.pluginname;
|
|
107
115
|
this.core.components[name] = component;
|
|
108
|
-
|
|
116
|
+
this.components.push(name);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 卸载插件时清理注册的所有资源
|
|
120
|
+
* 包括组件、路由、中间件和事件监听器
|
|
121
|
+
*/
|
|
122
|
+
dispose() {
|
|
123
|
+
// 删除组件
|
|
124
|
+
this.components.forEach((name) => {
|
|
125
|
+
delete this.core.components[name];
|
|
126
|
+
});
|
|
127
|
+
// 删除路由
|
|
128
|
+
this.routes.forEach((route) => {
|
|
129
|
+
delete this.core.routes[route];
|
|
130
|
+
});
|
|
131
|
+
// 删除中间件
|
|
132
|
+
this.middlewares.forEach((middleware) => {
|
|
133
|
+
delete this.core.globalMiddlewares[middleware];
|
|
134
|
+
});
|
|
135
|
+
// 删除事件监听器
|
|
136
|
+
this.eventlisteners.forEach(({ name, listener }) => {
|
|
137
|
+
if (this.core.eventListeners?.[name]) {
|
|
138
|
+
this.core.eventListeners[name] =
|
|
139
|
+
this.core.eventListeners[name].filter((l) => l !== listener);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// 删除钩子
|
|
143
|
+
for (const hook in this.hooks) {
|
|
144
|
+
this.hooks.hook.forEach((hookname) => {
|
|
145
|
+
this.core.unhook(hook, hookname);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// 清空 Context 内部记录,避免内存泄漏
|
|
149
|
+
this.components = [];
|
|
150
|
+
this.routes = [];
|
|
151
|
+
this.middlewares = [];
|
|
152
|
+
this.eventlisteners = [];
|
|
109
153
|
}
|
|
110
154
|
}
|
|
111
155
|
exports.Context = Context;
|
package/dist/core.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Config } from './config';
|
|
2
2
|
import { Logger } from './logger';
|
|
3
|
-
import { Command } from './command';
|
|
4
3
|
import { Session } from './session';
|
|
5
|
-
import { Platform } from './platform';
|
|
6
4
|
import { Middleware } from './middleware';
|
|
7
5
|
import { Route } from './route';
|
|
8
6
|
import { Context } from './context';
|
|
7
|
+
import { HookHandler, Hook } from './hook';
|
|
8
|
+
import { Server as CoreServer } from './server';
|
|
9
9
|
interface Plugin {
|
|
10
10
|
apply: (ctx: Context, config: Config) => Promise<void>;
|
|
11
11
|
disable: (ctx: Context) => Promise<void>;
|
|
@@ -19,6 +19,13 @@ interface PluginLoader {
|
|
|
19
19
|
installPluginDependencies(pluginName: string): Promise<void>;
|
|
20
20
|
logger: Logger;
|
|
21
21
|
}
|
|
22
|
+
interface CoreOptions {
|
|
23
|
+
port: number;
|
|
24
|
+
host: string;
|
|
25
|
+
staticDir: string;
|
|
26
|
+
enableCors: boolean;
|
|
27
|
+
enableWs: boolean;
|
|
28
|
+
}
|
|
22
29
|
/**
|
|
23
30
|
* 定义插件状态枚举
|
|
24
31
|
*/
|
|
@@ -35,60 +42,49 @@ export declare class Core {
|
|
|
35
42
|
};
|
|
36
43
|
};
|
|
37
44
|
config: any;
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
eventListeners: {
|
|
46
|
+
[event: string]: ((...args: any[]) => Promise<void>)[];
|
|
47
|
+
};
|
|
40
48
|
components: {
|
|
41
49
|
[name: string]: any;
|
|
42
50
|
};
|
|
43
|
-
commands: Record<string, Command>;
|
|
44
51
|
routes: Record<string, Route>;
|
|
45
52
|
pluginLoader: PluginLoader;
|
|
46
53
|
logger: Logger;
|
|
47
54
|
providedComponents: {
|
|
48
55
|
[name: string]: string;
|
|
49
56
|
};
|
|
57
|
+
globalMiddlewares: Record<string, Middleware>;
|
|
58
|
+
pluginStatus: Record<string, PluginStatus>;
|
|
59
|
+
hooks: Record<string, Hook>;
|
|
60
|
+
coreConfig: CoreOptions;
|
|
61
|
+
server: CoreServer;
|
|
62
|
+
private pluginWatchers;
|
|
50
63
|
private pluginModules;
|
|
51
64
|
private configPath;
|
|
52
|
-
private globalMiddlewares;
|
|
53
65
|
/**
|
|
54
|
-
*
|
|
66
|
+
* 插件名 -> Context 映射
|
|
55
67
|
*/
|
|
56
|
-
|
|
68
|
+
private pluginContexts;
|
|
69
|
+
constructor(pluginLoader?: PluginLoader, coreConfig?: CoreOptions);
|
|
57
70
|
/**
|
|
58
|
-
*
|
|
71
|
+
* 获取或创建插件对应 Context
|
|
59
72
|
*/
|
|
60
|
-
|
|
73
|
+
getContext(pluginName: string): Context;
|
|
61
74
|
/**
|
|
62
|
-
*
|
|
63
|
-
*/
|
|
64
|
-
comtoplu: Record<string, string>;
|
|
65
|
-
/**
|
|
66
|
-
* 事件监听器与插件对应关系
|
|
67
|
-
*/
|
|
68
|
-
evttoplu: Record<string, Record<string, ((...args: any[]) => Promise<void>)[]>>;
|
|
69
|
-
/**
|
|
70
|
-
* 中间件与插件对应关系
|
|
71
|
-
*/
|
|
72
|
-
mdwtoplu: Record<string, string>;
|
|
73
|
-
plftoplu: Record<string, string>;
|
|
74
|
-
/**
|
|
75
|
-
* 插件状态
|
|
76
|
-
*/
|
|
77
|
-
pluginStatus: Record<string, PluginStatus>;
|
|
78
|
-
/**
|
|
79
|
-
* 插件监听器
|
|
80
|
-
*/
|
|
81
|
-
private pluginWatchers;
|
|
82
|
-
/**
|
|
83
|
-
* 初始化核心
|
|
84
|
-
* @param pluginLoader 插件加载器
|
|
75
|
+
* 清理指定插件注册的所有内容
|
|
85
76
|
*/
|
|
86
|
-
|
|
77
|
+
unregall(pluginName: string): void;
|
|
87
78
|
/**
|
|
88
79
|
* 加载配置文件
|
|
89
80
|
* @param configPath 配置文件的路径
|
|
90
81
|
*/
|
|
91
82
|
loadConfig(configPath: string): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* 启动应用
|
|
85
|
+
* @returns Promise<void>
|
|
86
|
+
*/
|
|
87
|
+
runCore(): Promise<void>;
|
|
92
88
|
/**
|
|
93
89
|
* 监听配置文件变化,实现热重载
|
|
94
90
|
* @param configPath 配置文件的路径
|
|
@@ -175,10 +171,6 @@ export declare class Core {
|
|
|
175
171
|
* @returns Core 实例
|
|
176
172
|
*/
|
|
177
173
|
use(name: string, middleware: Middleware): Core;
|
|
178
|
-
/**
|
|
179
|
-
* @deprecated 已更改为路由
|
|
180
|
-
*/
|
|
181
|
-
command(name: string): Command;
|
|
182
174
|
/**
|
|
183
175
|
* 注册路由
|
|
184
176
|
* @param path 路由路径
|
|
@@ -186,10 +178,23 @@ export declare class Core {
|
|
|
186
178
|
*/
|
|
187
179
|
route(path: string): Route;
|
|
188
180
|
/**
|
|
189
|
-
*
|
|
190
|
-
* @
|
|
181
|
+
* 注册 Hook 钩子
|
|
182
|
+
* @param name Hook 点名称
|
|
183
|
+
* @param hookname 钩子名称
|
|
184
|
+
* @param callback 钩子函数
|
|
185
|
+
*/
|
|
186
|
+
hook(name: string, hookname: string, callback: HookHandler): any;
|
|
187
|
+
/**
|
|
188
|
+
* 消除 Hook 钩子
|
|
189
|
+
*/
|
|
190
|
+
unhook(name: string, hookname: string): any;
|
|
191
|
+
/**
|
|
192
|
+
* 执行 Hook 钩子
|
|
193
|
+
* @param name Hook 点名称
|
|
194
|
+
* @param args 参数
|
|
195
|
+
* @return Promise<any[]>
|
|
191
196
|
*/
|
|
192
|
-
|
|
197
|
+
hookExecute(name: string, ...args: any[]): Promise<any[]>;
|
|
193
198
|
/**
|
|
194
199
|
* 执行路由
|
|
195
200
|
* @param pathname 需要匹配的URL
|
|
@@ -198,23 +203,6 @@ export declare class Core {
|
|
|
198
203
|
* @returns 是否匹配成功
|
|
199
204
|
*/
|
|
200
205
|
executeRoute(pathname: string, session: Session, queryParams: URLSearchParams): Promise<boolean>;
|
|
201
|
-
/**
|
|
202
|
-
* 注册平台
|
|
203
|
-
* @param platform 平台实例
|
|
204
|
-
* @returns 平台启动结果
|
|
205
|
-
*/
|
|
206
|
-
registerPlatform(platform: Platform): any;
|
|
207
|
-
/**
|
|
208
|
-
* 清理指定插件注册的所有内容
|
|
209
|
-
* @param pluginname 插件名称
|
|
210
|
-
*/
|
|
211
|
-
unregall(pluginname: string): void;
|
|
212
|
-
/**
|
|
213
|
-
* 获取命令
|
|
214
|
-
* @param name 命令名称
|
|
215
|
-
* @returns Command 实例或 null
|
|
216
|
-
*/
|
|
217
|
-
getCommand(name: string): Command | null;
|
|
218
206
|
/**
|
|
219
207
|
* 获取路由
|
|
220
208
|
* @param path 匹配路径
|
package/dist/core.js
CHANGED
|
@@ -35,8 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.Core = void 0;
|
|
37
37
|
/**
|
|
38
|
-
* @time: 2025/
|
|
39
|
-
* @author: FireGuo
|
|
38
|
+
* @time: 2025/08/14 09:48
|
|
39
|
+
* @author: FireGuo
|
|
40
40
|
* WindyPear-Team All right reserved
|
|
41
41
|
**/
|
|
42
42
|
const yaml = __importStar(require("js-yaml"));
|
|
@@ -44,59 +44,54 @@ const fs = __importStar(require("fs"));
|
|
|
44
44
|
const path = __importStar(require("path"));
|
|
45
45
|
const config_1 = require("./config");
|
|
46
46
|
const logger_1 = require("./logger");
|
|
47
|
-
const command_1 = require("./command");
|
|
48
47
|
const chokidar = __importStar(require("chokidar"));
|
|
49
48
|
const route_1 = require("./route");
|
|
50
49
|
const context_1 = require("./context");
|
|
50
|
+
const hook_1 = require("./hook");
|
|
51
|
+
const server_1 = require("./server");
|
|
51
52
|
class Core {
|
|
52
53
|
plugins = {};
|
|
53
54
|
config = null;
|
|
54
|
-
platforms = [];
|
|
55
55
|
eventListeners = {};
|
|
56
56
|
components = {};
|
|
57
|
-
commands = {};
|
|
58
57
|
routes = {};
|
|
59
58
|
pluginLoader;
|
|
60
59
|
logger = new logger_1.Logger('core');
|
|
61
60
|
providedComponents = {};
|
|
61
|
+
globalMiddlewares = {};
|
|
62
|
+
pluginStatus = {};
|
|
63
|
+
hooks = {};
|
|
64
|
+
coreConfig;
|
|
65
|
+
server;
|
|
66
|
+
pluginWatchers = {};
|
|
62
67
|
pluginModules = {};
|
|
63
68
|
configPath = '';
|
|
64
|
-
globalMiddlewares = {};
|
|
65
|
-
/**
|
|
66
|
-
* @deprecated 命令与插件对应关系
|
|
67
|
-
*/
|
|
68
|
-
cmdtoplu = {};
|
|
69
|
-
/**
|
|
70
|
-
* 路由与插件对应关系
|
|
71
|
-
*/
|
|
72
|
-
routetoplu = {};
|
|
73
69
|
/**
|
|
74
|
-
*
|
|
70
|
+
* 插件名 -> Context 映射
|
|
75
71
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 中间件与插件对应关系
|
|
83
|
-
*/
|
|
84
|
-
mdwtoplu = {};
|
|
85
|
-
plftoplu = {};
|
|
86
|
-
/**
|
|
87
|
-
* 插件状态
|
|
88
|
-
*/
|
|
89
|
-
pluginStatus = {};
|
|
72
|
+
pluginContexts = {};
|
|
73
|
+
constructor(pluginLoader, coreConfig) {
|
|
74
|
+
this.coreConfig = coreConfig;
|
|
75
|
+
this.pluginLoader = pluginLoader;
|
|
76
|
+
}
|
|
90
77
|
/**
|
|
91
|
-
*
|
|
78
|
+
* 获取或创建插件对应 Context
|
|
92
79
|
*/
|
|
93
|
-
|
|
80
|
+
getContext(pluginName) {
|
|
81
|
+
if (!this.pluginContexts[pluginName]) {
|
|
82
|
+
this.pluginContexts[pluginName] = new context_1.Context(this, pluginName);
|
|
83
|
+
}
|
|
84
|
+
return this.pluginContexts[pluginName];
|
|
85
|
+
}
|
|
94
86
|
/**
|
|
95
|
-
*
|
|
96
|
-
* @param pluginLoader 插件加载器
|
|
87
|
+
* 清理指定插件注册的所有内容
|
|
97
88
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
unregall(pluginName) {
|
|
90
|
+
const ctx = this.pluginContexts[pluginName];
|
|
91
|
+
if (ctx) {
|
|
92
|
+
ctx.dispose();
|
|
93
|
+
delete this.pluginContexts[pluginName];
|
|
94
|
+
}
|
|
100
95
|
}
|
|
101
96
|
/**
|
|
102
97
|
* 加载配置文件
|
|
@@ -111,12 +106,28 @@ class Core {
|
|
|
111
106
|
if (process.env.NODE_ENV === 'development') {
|
|
112
107
|
this.watchConfig(configPath);
|
|
113
108
|
}
|
|
109
|
+
this.coreConfig = this.config.core || {};
|
|
114
110
|
}
|
|
115
111
|
catch (e) {
|
|
116
112
|
this.logger.error('Failed to load config:', e);
|
|
117
113
|
throw e;
|
|
118
114
|
}
|
|
119
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* 启动应用
|
|
118
|
+
* @returns Promise<void>
|
|
119
|
+
*/
|
|
120
|
+
async runCore() {
|
|
121
|
+
this.server = new server_1.Server(this, {
|
|
122
|
+
port: this.coreConfig.port || 14510,
|
|
123
|
+
host: this.coreConfig.host || '0.0.0.0',
|
|
124
|
+
enableCors: this.coreConfig.enableCors || false,
|
|
125
|
+
enableWs: this.coreConfig.enableWs || false,
|
|
126
|
+
staticDir: this.coreConfig.staticDir || 'public',
|
|
127
|
+
});
|
|
128
|
+
await this.server.start();
|
|
129
|
+
this.logger.info(`Yumeri server started at ${this.coreConfig.host}:${this.coreConfig.port}`);
|
|
130
|
+
}
|
|
120
131
|
/**
|
|
121
132
|
* 监听配置文件变化,实现热重载
|
|
122
133
|
* @param configPath 配置文件的路径
|
|
@@ -255,7 +266,7 @@ class Core {
|
|
|
255
266
|
this.plugins[pluginName] = pluginInstance;
|
|
256
267
|
if (pluginInstance.apply) {
|
|
257
268
|
this.pluginLoader.logger.info(`Apply plugin "${pluginName}"`);
|
|
258
|
-
await pluginInstance.apply(
|
|
269
|
+
await pluginInstance.apply(this.getContext(pluginName), await this.getPluginConfig(pluginName));
|
|
259
270
|
}
|
|
260
271
|
// 注册提供的组件
|
|
261
272
|
if (pluginInstance.provide) {
|
|
@@ -365,9 +376,8 @@ class Core {
|
|
|
365
376
|
this.logger.info(`Unloading plugin "${pluginName}"...`);
|
|
366
377
|
try {
|
|
367
378
|
const plugin = this.plugins[pluginName];
|
|
368
|
-
if (plugin && plugin.disable)
|
|
369
|
-
await plugin.disable(
|
|
370
|
-
}
|
|
379
|
+
if (plugin && plugin.disable)
|
|
380
|
+
await plugin.disable(this.getContext(pluginName));
|
|
371
381
|
await this.pluginLoader.unloadPlugin(pluginName);
|
|
372
382
|
this.unregall(pluginName); // 清理该插件注册的所有内容
|
|
373
383
|
delete this.plugins[pluginName];
|
|
@@ -465,7 +475,6 @@ class Core {
|
|
|
465
475
|
unregisterComponent(name) {
|
|
466
476
|
delete this.components[name];
|
|
467
477
|
delete this.providedComponents[name];
|
|
468
|
-
delete this.comtoplu[name];
|
|
469
478
|
}
|
|
470
479
|
/**
|
|
471
480
|
* 注册事件监听器
|
|
@@ -505,14 +514,6 @@ class Core {
|
|
|
505
514
|
this.globalMiddlewares[name] = middleware;
|
|
506
515
|
return this;
|
|
507
516
|
}
|
|
508
|
-
/**
|
|
509
|
-
* @deprecated 已更改为路由
|
|
510
|
-
*/
|
|
511
|
-
command(name) {
|
|
512
|
-
const command = new command_1.Command(this, name);
|
|
513
|
-
this.commands[name] = command;
|
|
514
|
-
return command;
|
|
515
|
-
}
|
|
516
517
|
/**
|
|
517
518
|
* 注册路由
|
|
518
519
|
* @param path 路由路径
|
|
@@ -524,29 +525,36 @@ class Core {
|
|
|
524
525
|
return route;
|
|
525
526
|
}
|
|
526
527
|
/**
|
|
527
|
-
*
|
|
528
|
-
* @
|
|
528
|
+
* 注册 Hook 钩子
|
|
529
|
+
* @param name Hook 点名称
|
|
530
|
+
* @param hookname 钩子名称
|
|
531
|
+
* @param callback 钩子函数
|
|
529
532
|
*/
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
533
|
+
hook(name, hookname, callback) {
|
|
534
|
+
if (!this.hooks[name]) {
|
|
535
|
+
this.hooks[name] = new hook_1.Hook(name);
|
|
536
|
+
}
|
|
537
|
+
this.hooks[name].add(hookname, callback);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* 消除 Hook 钩子
|
|
541
|
+
*/
|
|
542
|
+
unhook(name, hookname) {
|
|
543
|
+
if (this.hooks[name]) {
|
|
544
|
+
this.hooks[name].remove(hookname);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* 执行 Hook 钩子
|
|
549
|
+
* @param name Hook 点名称
|
|
550
|
+
* @param args 参数
|
|
551
|
+
* @return Promise<any[]>
|
|
552
|
+
*/
|
|
553
|
+
async hookExecute(name, ...args) {
|
|
554
|
+
if (this.hooks[name]) {
|
|
555
|
+
return await this.hooks[name].trigger(...args);
|
|
548
556
|
}
|
|
549
|
-
return
|
|
557
|
+
return [];
|
|
550
558
|
}
|
|
551
559
|
/**
|
|
552
560
|
* 执行路由
|
|
@@ -560,18 +568,13 @@ class Core {
|
|
|
560
568
|
const route = this.routes[routePath];
|
|
561
569
|
const result = route.match(pathname);
|
|
562
570
|
if (result) {
|
|
563
|
-
const
|
|
564
|
-
const routeMiddlewareList = route.middlewares || [];
|
|
565
|
-
const middlewares = [...globalMiddlewareList, ...routeMiddlewareList];
|
|
571
|
+
const middlewares = [...Object.values(this.globalMiddlewares), ...(route.middlewares || [])];
|
|
566
572
|
let index = 0;
|
|
567
573
|
const runner = async () => {
|
|
568
|
-
if (index < middlewares.length)
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
}
|
|
572
|
-
else {
|
|
574
|
+
if (index < middlewares.length)
|
|
575
|
+
await middlewares[index++](session, runner);
|
|
576
|
+
else
|
|
573
577
|
await route.executeHandler(session, queryParams, result.pathParams);
|
|
574
|
-
}
|
|
575
578
|
};
|
|
576
579
|
await runner();
|
|
577
580
|
return true;
|
|
@@ -579,74 +582,6 @@ class Core {
|
|
|
579
582
|
}
|
|
580
583
|
return false;
|
|
581
584
|
}
|
|
582
|
-
/**
|
|
583
|
-
* 注册平台
|
|
584
|
-
* @param platform 平台实例
|
|
585
|
-
* @returns 平台启动结果
|
|
586
|
-
*/
|
|
587
|
-
registerPlatform(platform) {
|
|
588
|
-
this.platforms.push(platform);
|
|
589
|
-
return platform.startPlatform(this);
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* 清理指定插件注册的所有内容
|
|
593
|
-
* @param pluginname 插件名称
|
|
594
|
-
*/
|
|
595
|
-
unregall(pluginname) {
|
|
596
|
-
// 清理 commands
|
|
597
|
-
Object.keys(this.cmdtoplu)
|
|
598
|
-
.filter(cmd => this.cmdtoplu[cmd] === pluginname)
|
|
599
|
-
.forEach(cmd => {
|
|
600
|
-
delete this.cmdtoplu[cmd];
|
|
601
|
-
delete this.commands[cmd];
|
|
602
|
-
});
|
|
603
|
-
// 清理 routes
|
|
604
|
-
Object.keys(this.routetoplu)
|
|
605
|
-
.filter(path => this.routetoplu[path] === pluginname)
|
|
606
|
-
.forEach(path => {
|
|
607
|
-
delete this.routetoplu[path];
|
|
608
|
-
delete this.routes[path];
|
|
609
|
-
});
|
|
610
|
-
// 清理 components 和 providedComponents
|
|
611
|
-
Object.keys(this.comtoplu)
|
|
612
|
-
.filter(comp => this.comtoplu[comp] === pluginname)
|
|
613
|
-
.forEach(comp => {
|
|
614
|
-
delete this.comtoplu[comp];
|
|
615
|
-
delete this.components[comp];
|
|
616
|
-
delete this.providedComponents[comp];
|
|
617
|
-
});
|
|
618
|
-
// 清理由 provide 声明的组件提供关系
|
|
619
|
-
Object.keys(this.providedComponents)
|
|
620
|
-
.filter(prov => this.providedComponents[prov] === pluginname)
|
|
621
|
-
.forEach(prov => {
|
|
622
|
-
delete this.providedComponents[prov];
|
|
623
|
-
});
|
|
624
|
-
// 清理 event listeners
|
|
625
|
-
for (const evt in this.evttoplu) {
|
|
626
|
-
if (this.evttoplu[evt][pluginname]) {
|
|
627
|
-
const pluginListeners = this.evttoplu[evt][pluginname] || [];
|
|
628
|
-
if (this.eventListeners[evt]) {
|
|
629
|
-
this.eventListeners[evt] = this.eventListeners[evt].filter(l => !pluginListeners.includes(l));
|
|
630
|
-
}
|
|
631
|
-
delete this.evttoplu[evt][pluginname];
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
// 清理 middlewares
|
|
635
|
-
Object.keys(this.mdwtoplu)
|
|
636
|
-
.filter(mdw => this.mdwtoplu[mdw] === pluginname)
|
|
637
|
-
.forEach(mdw => {
|
|
638
|
-
delete this.mdwtoplu[mdw];
|
|
639
|
-
delete this.globalMiddlewares[mdw];
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* 获取命令
|
|
644
|
-
* @param name 命令名称
|
|
645
|
-
* @returns Command 实例或 null
|
|
646
|
-
*/
|
|
647
|
-
getCommand(name) {
|
|
648
|
-
return this.commands[name] || null;
|
|
649
|
-
}
|
|
650
585
|
/**
|
|
651
586
|
* 获取路由
|
|
652
587
|
* @param path 匹配路径
|
package/dist/hook.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @time: 2025/08/14 18:33
|
|
3
|
+
* @author: FireGuo
|
|
4
|
+
* WindyPear-Team All right reserved
|
|
5
|
+
**/
|
|
6
|
+
/**
|
|
7
|
+
* Hook 处理器
|
|
8
|
+
*/
|
|
9
|
+
export type HookHandler = (...args: any[]) => Promise<any>;
|
|
10
|
+
/**
|
|
11
|
+
* Hook 类
|
|
12
|
+
*/
|
|
13
|
+
export declare class Hook {
|
|
14
|
+
name: string;
|
|
15
|
+
handlers: Record<string, HookHandler>;
|
|
16
|
+
/**
|
|
17
|
+
* 创建 Hook 实例
|
|
18
|
+
* @param name Hook 名称
|
|
19
|
+
*/
|
|
20
|
+
constructor(name: string);
|
|
21
|
+
/**
|
|
22
|
+
* 添加 Hook 函数
|
|
23
|
+
* @param name Hook 函数名称
|
|
24
|
+
* @param handler Hook 函数
|
|
25
|
+
*/
|
|
26
|
+
add(name: string, handler: HookHandler): void;
|
|
27
|
+
/**
|
|
28
|
+
* 删除 Hook 函数
|
|
29
|
+
* @param name Hook 函数名称
|
|
30
|
+
*/
|
|
31
|
+
remove(name: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* 触发 Hook 函数
|
|
34
|
+
* @param session 会话
|
|
35
|
+
* @param args 参数
|
|
36
|
+
* @returns 执行结果
|
|
37
|
+
*/
|
|
38
|
+
trigger(...args: any[]): Promise<any[]>;
|
|
39
|
+
}
|
package/dist/hook.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @time: 2025/08/14 18:33
|
|
4
|
+
* @author: FireGuo
|
|
5
|
+
* WindyPear-Team All right reserved
|
|
6
|
+
**/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.Hook = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* Hook 类
|
|
11
|
+
*/
|
|
12
|
+
class Hook {
|
|
13
|
+
name;
|
|
14
|
+
handlers = {};
|
|
15
|
+
/**
|
|
16
|
+
* 创建 Hook 实例
|
|
17
|
+
* @param name Hook 名称
|
|
18
|
+
*/
|
|
19
|
+
constructor(name) {
|
|
20
|
+
this.name = name;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 添加 Hook 函数
|
|
24
|
+
* @param name Hook 函数名称
|
|
25
|
+
* @param handler Hook 函数
|
|
26
|
+
*/
|
|
27
|
+
add(name, handler) {
|
|
28
|
+
this.handlers[name] = handler;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 删除 Hook 函数
|
|
32
|
+
* @param name Hook 函数名称
|
|
33
|
+
*/
|
|
34
|
+
remove(name) {
|
|
35
|
+
delete this.handlers[name];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 触发 Hook 函数
|
|
39
|
+
* @param session 会话
|
|
40
|
+
* @param args 参数
|
|
41
|
+
* @returns 执行结果
|
|
42
|
+
*/
|
|
43
|
+
async trigger(...args) {
|
|
44
|
+
let result;
|
|
45
|
+
for (const handler of Object.values(this.handlers)) {
|
|
46
|
+
result.push(handler(...args));
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.Hook = Hook;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @time: 2025/
|
|
2
|
+
* @time: 2025/08/14 09:48
|
|
3
3
|
* @author: FireGuo
|
|
4
4
|
* WindyPear-Team All right reserved
|
|
5
5
|
**/
|
|
6
6
|
export * from './core';
|
|
7
7
|
export * from './session';
|
|
8
|
-
export * from './command';
|
|
9
8
|
export * from './route';
|
|
10
9
|
export * from './config';
|
|
11
10
|
export * from './logger';
|
|
12
|
-
export * from './platform';
|
|
13
11
|
export * from './context';
|
|
12
|
+
export * from './hook';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* @time: 2025/
|
|
3
|
+
* @time: 2025/08/14 09:48
|
|
4
4
|
* @author: FireGuo
|
|
5
5
|
* WindyPear-Team All right reserved
|
|
6
6
|
**/
|
|
@@ -21,9 +21,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
22
|
__exportStar(require("./core"), exports);
|
|
23
23
|
__exportStar(require("./session"), exports);
|
|
24
|
-
__exportStar(require("./command"), exports);
|
|
25
24
|
__exportStar(require("./route"), exports);
|
|
26
25
|
__exportStar(require("./config"), exports);
|
|
27
26
|
__exportStar(require("./logger"), exports);
|
|
28
|
-
__exportStar(require("./platform"), exports);
|
|
29
27
|
__exportStar(require("./context"), exports);
|
|
28
|
+
__exportStar(require("./hook"), exports);
|
package/dist/logger.d.ts
CHANGED
package/dist/logger.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* @time: 2025/
|
|
3
|
+
* @time: 2025/08/14 09:48
|
|
4
4
|
* @author: FireGuo
|
|
5
5
|
* WindyPear-Team All right reserved
|
|
6
|
-
|
|
6
|
+
**/
|
|
7
7
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
8
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
9
|
};
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.Logger = void 0;
|
|
12
|
-
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
13
13
|
class Logger {
|
|
14
14
|
title;
|
|
15
15
|
titleColor;
|
package/dist/middleware.d.ts
CHANGED
package/dist/platform.d.ts
CHANGED
package/dist/platform.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Platform = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @time: 2025/08/14 09:48
|
|
6
|
+
* @author: FireGuo
|
|
7
|
+
* WindyPear-Team All right reserved
|
|
8
|
+
**/
|
|
4
9
|
const session_1 = require("./session");
|
|
5
10
|
/**
|
|
6
11
|
* Platform 基类
|
package/dist/route.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @time: 2025/08/14 09:48
|
|
3
|
+
* @author: FireGuo
|
|
4
|
+
* WindyPear-Team All right reserved
|
|
5
|
+
**/
|
|
1
6
|
import { Session } from './session';
|
|
2
7
|
import { Middleware } from './middleware';
|
|
3
8
|
export type RouteHandler = (session: Session, queryParams: URLSearchParams, ...pathParams: string[]) => Promise<void> | void;
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Core } from './core';
|
|
2
|
+
export interface ServerConfig {
|
|
3
|
+
port: number;
|
|
4
|
+
host: string;
|
|
5
|
+
enableCors: boolean;
|
|
6
|
+
staticDir: string;
|
|
7
|
+
enableWs: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class Server {
|
|
10
|
+
private core;
|
|
11
|
+
private port;
|
|
12
|
+
private host;
|
|
13
|
+
private enableCors;
|
|
14
|
+
private staticDir;
|
|
15
|
+
private enableWs;
|
|
16
|
+
private httpServer;
|
|
17
|
+
private wsServer;
|
|
18
|
+
constructor(core: Core, config?: Partial<ServerConfig>);
|
|
19
|
+
private createSession;
|
|
20
|
+
private parseCookies;
|
|
21
|
+
private getClientIP;
|
|
22
|
+
private parseRequestBody;
|
|
23
|
+
private serveStaticFile;
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
stop(): void;
|
|
26
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Server = void 0;
|
|
40
|
+
const logger_1 = require("./logger");
|
|
41
|
+
const session_1 = require("./session");
|
|
42
|
+
const http_1 = __importDefault(require("http"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const url_1 = require("url");
|
|
46
|
+
const ws_1 = __importDefault(require("ws"));
|
|
47
|
+
const formidable = __importStar(require("formidable"));
|
|
48
|
+
const mime = __importStar(require("mime-types"));
|
|
49
|
+
const logger = new logger_1.Logger('server');
|
|
50
|
+
class Server {
|
|
51
|
+
core;
|
|
52
|
+
port;
|
|
53
|
+
host;
|
|
54
|
+
enableCors;
|
|
55
|
+
staticDir;
|
|
56
|
+
enableWs;
|
|
57
|
+
httpServer = null;
|
|
58
|
+
wsServer = null;
|
|
59
|
+
constructor(core, config = {}) {
|
|
60
|
+
this.core = core;
|
|
61
|
+
this.port = config.port ?? 14510;
|
|
62
|
+
this.host = config.host ?? '0.0.0.0';
|
|
63
|
+
this.enableCors = config.enableCors ?? true;
|
|
64
|
+
this.staticDir = config.staticDir ?? 'static';
|
|
65
|
+
this.enableWs = config.enableWs ?? true;
|
|
66
|
+
}
|
|
67
|
+
createSession(ip, cookies, res, req, extra = {}) {
|
|
68
|
+
const session = new session_1.Session(ip, cookies, this, req, res);
|
|
69
|
+
Object.assign(session.properties, extra);
|
|
70
|
+
session.protocol = extra.protocol ?? 'http';
|
|
71
|
+
return session;
|
|
72
|
+
}
|
|
73
|
+
parseCookies(req) {
|
|
74
|
+
const cookieHeader = req.headers.cookie;
|
|
75
|
+
if (!cookieHeader)
|
|
76
|
+
return {};
|
|
77
|
+
const cookies = {};
|
|
78
|
+
cookieHeader.split(';').forEach(c => {
|
|
79
|
+
const [k, ...v] = c.split('=');
|
|
80
|
+
cookies[k.trim()] = v.join('=').trim();
|
|
81
|
+
});
|
|
82
|
+
return cookies;
|
|
83
|
+
}
|
|
84
|
+
getClientIP(req) {
|
|
85
|
+
const xff = req.headers['x-forwarded-for'];
|
|
86
|
+
return xff ? xff.split(',')[0].trim() : req.socket.remoteAddress || '127.0.0.1';
|
|
87
|
+
}
|
|
88
|
+
async parseRequestBody(req) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const contentType = (req.headers['content-type'] || '').toLowerCase();
|
|
91
|
+
if (contentType.includes('application/json') || contentType.includes('application/x-www-form-urlencoded')) {
|
|
92
|
+
let body = '';
|
|
93
|
+
req.on('data', chunk => body += chunk.toString());
|
|
94
|
+
req.on('end', () => {
|
|
95
|
+
try {
|
|
96
|
+
if (contentType.includes('application/json'))
|
|
97
|
+
resolve(JSON.parse(body));
|
|
98
|
+
else {
|
|
99
|
+
const params = new URLSearchParams(body);
|
|
100
|
+
const parsed = {};
|
|
101
|
+
params.forEach((v, k) => parsed[k] = v);
|
|
102
|
+
resolve(parsed);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
reject(e);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else if (contentType.includes('multipart/form-data')) {
|
|
111
|
+
const form = formidable.formidable({});
|
|
112
|
+
form.parse(req, (err, fields) => {
|
|
113
|
+
if (err)
|
|
114
|
+
return reject(err);
|
|
115
|
+
const parsed = {};
|
|
116
|
+
Object.keys(fields).forEach(k => {
|
|
117
|
+
const val = fields[k];
|
|
118
|
+
parsed[k] = Array.isArray(val) && val.length === 1 ? val[0] : val;
|
|
119
|
+
});
|
|
120
|
+
resolve(parsed);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
resolve({});
|
|
125
|
+
req.on('error', reject);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
serveStaticFile(pathname, res) {
|
|
129
|
+
const fullPath = path.join(process.cwd(), this.staticDir, pathname);
|
|
130
|
+
fs.readFile(fullPath, (err, data) => {
|
|
131
|
+
if (err) {
|
|
132
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
133
|
+
res.end(`<html><body><h1>404 Not Found</h1></body></html>`);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
res.writeHead(200, { 'Content-Type': mime.lookup(fullPath) || 'text/plain' });
|
|
137
|
+
res.end(data);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async start() {
|
|
142
|
+
this.httpServer = http_1.default.createServer(async (req, res) => {
|
|
143
|
+
if (req.method === 'OPTIONS' && this.enableCors) {
|
|
144
|
+
res.writeHead(204, {
|
|
145
|
+
'Access-Control-Allow-Origin': '*',
|
|
146
|
+
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS',
|
|
147
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
148
|
+
});
|
|
149
|
+
res.end();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const url = new url_1.URL(req.url || '/', `http://${req.headers.host}`);
|
|
153
|
+
const pathname = url.pathname;
|
|
154
|
+
const queryParams = url.searchParams;
|
|
155
|
+
const ip = this.getClientIP(req);
|
|
156
|
+
const cookies = this.parseCookies(req);
|
|
157
|
+
const session = this.createSession(ip, cookies, res, req, { protocol: 'http', header: req.headers });
|
|
158
|
+
if (req.method?.toLowerCase() === 'post') {
|
|
159
|
+
try {
|
|
160
|
+
const body = await this.parseRequestBody(req);
|
|
161
|
+
Object.entries(body).forEach(([k, v]) => {
|
|
162
|
+
if (typeof v === 'string')
|
|
163
|
+
queryParams.set(k, v);
|
|
164
|
+
else if (Array.isArray(v))
|
|
165
|
+
v.forEach(val => queryParams.append(k, val));
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
170
|
+
res.end('Invalid request body');
|
|
171
|
+
logger.error('Request body parse error:', err);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const route = this.core.getRoute(pathname);
|
|
176
|
+
if (route && route.allowedMethods.includes(req.method ?? 'GET')) {
|
|
177
|
+
const matched = await this.core.executeRoute(pathname, session, queryParams);
|
|
178
|
+
if (!matched) {
|
|
179
|
+
this.serveStaticFile(pathname, res);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
let head = session.head;
|
|
183
|
+
head['Set-Cookie'] = Object.entries(session.newCookie).map(([k, v]) => `${k}=${v}`);
|
|
184
|
+
if (this.enableCors) {
|
|
185
|
+
head['Access-Control-Allow-Origin'] = '*';
|
|
186
|
+
}
|
|
187
|
+
res.writeHead(session.status ?? 200, head);
|
|
188
|
+
res.end(session.body);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
this.serveStaticFile(pathname, res);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (this.enableWs) {
|
|
196
|
+
this.wsServer = new ws_1.default.Server({ server: this.httpServer });
|
|
197
|
+
this.wsServer.on('connection', (ws, req) => {
|
|
198
|
+
const url = new url_1.URL(req.url || '/', `http://${req.headers.host}`);
|
|
199
|
+
const pathname = url.pathname;
|
|
200
|
+
const queryParams = url.searchParams;
|
|
201
|
+
const ip = this.getClientIP(req);
|
|
202
|
+
const cookies = this.parseCookies(req);
|
|
203
|
+
const session = this.createSession(ip, cookies, undefined, req, { ws, protocol: 'ws' });
|
|
204
|
+
ws.on('message', async (msg) => {
|
|
205
|
+
try {
|
|
206
|
+
const data = JSON.parse(msg.toString());
|
|
207
|
+
Object.entries(data).forEach(([k, v]) => queryParams.set(k, v));
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
queryParams.set('message', msg.toString());
|
|
211
|
+
}
|
|
212
|
+
await this.core.executeRoute(pathname, session, queryParams);
|
|
213
|
+
});
|
|
214
|
+
this.core.executeRoute(pathname, session, queryParams).catch(err => {
|
|
215
|
+
logger.error(`WS initial route error for ${pathname}:`, err);
|
|
216
|
+
ws.close(1011, 'Internal error');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
this.httpServer.listen(this.port, this.host, () => {
|
|
221
|
+
logger.info(`Server listening on ${this.host}:${this.port}`);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
stop() {
|
|
225
|
+
if (this.wsServer)
|
|
226
|
+
this.wsServer.close();
|
|
227
|
+
if (this.httpServer)
|
|
228
|
+
this.httpServer.close(() => logger.info('Server stopped'));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
exports.Server = Server;
|
package/dist/session.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* @author: FireGuo
|
|
4
4
|
* WindyPear-Team All right reserved
|
|
5
5
|
**/
|
|
6
|
-
import {
|
|
6
|
+
import { Server } from './server';
|
|
7
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
7
8
|
export declare class Session {
|
|
8
9
|
ip: string;
|
|
9
10
|
cookie: Record<string, string>;
|
|
@@ -14,9 +15,12 @@ export declare class Session {
|
|
|
14
15
|
head: Record<string, any>;
|
|
15
16
|
status: number;
|
|
16
17
|
body: any;
|
|
17
|
-
platform: Platform;
|
|
18
18
|
properties?: Record<string, any>;
|
|
19
|
-
|
|
19
|
+
res: any;
|
|
20
|
+
req: any;
|
|
21
|
+
server: Server;
|
|
22
|
+
protocol: string;
|
|
23
|
+
constructor(ip: string, cookie: Record<string, string>, server: Server, req?: IncomingMessage, res?: ServerResponse, query?: Record<string, string>);
|
|
20
24
|
private generateId;
|
|
21
25
|
private md5;
|
|
22
26
|
setData(key: string, value: any): void;
|
package/dist/session.js
CHANGED
|
@@ -20,18 +20,23 @@ class Session {
|
|
|
20
20
|
head = {};
|
|
21
21
|
status = 200;
|
|
22
22
|
body;
|
|
23
|
-
platform;
|
|
24
23
|
properties = {};
|
|
24
|
+
res = null;
|
|
25
|
+
req = null;
|
|
26
|
+
server;
|
|
27
|
+
protocol = 'http';
|
|
25
28
|
/*
|
|
26
29
|
* @ip: string,用户IP
|
|
27
30
|
* @cookie: string,会话cookie
|
|
28
31
|
* @query: string,请求字符串
|
|
29
32
|
*/
|
|
30
|
-
constructor(ip, cookie,
|
|
33
|
+
constructor(ip, cookie, server, req, res, query) {
|
|
31
34
|
this.ip = ip;
|
|
32
35
|
this.cookie = cookie;
|
|
33
36
|
this.query = query;
|
|
34
|
-
this.
|
|
37
|
+
this.server = server;
|
|
38
|
+
this.req = req;
|
|
39
|
+
this.res = res;
|
|
35
40
|
this.head['Content-Type'] = 'text/plain';
|
|
36
41
|
if (cookie.sessionid) {
|
|
37
42
|
this.sessionid = cookie.sessionid;
|
|
@@ -102,10 +107,10 @@ class Session {
|
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
send(data) {
|
|
105
|
-
return this.
|
|
110
|
+
return this.res.send(data);
|
|
106
111
|
}
|
|
107
112
|
endsession(message) {
|
|
108
|
-
return this.
|
|
113
|
+
return this.res.end(message);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
exports.Session = Session;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yumerijs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Core module for yumeri",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@yumerijs/loader": "^1.2.0",
|
|
35
35
|
"chokidar": "^4.0.3",
|
|
36
|
-
"js-sha256": "^0.11.0",
|
|
37
36
|
"js-yaml": "^4.1.0",
|
|
38
37
|
"picocolors": "^1.1.1"
|
|
39
38
|
},
|