@zhin.js/http 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # @zhin.js/http
2
+
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - efdd58a: fix: init
8
+ - Updated dependencies [efdd58a]
9
+ - @zhin.js/core@1.0.1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 凉菜
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,261 @@
1
+ # @zhin.js/http
2
+
3
+ 基于 Koa 的 HTTP 服务器插件,为 Zhin 机器人框架提供 HTTP API 和 WebSocket 支持。
4
+
5
+ ## 功能特性
6
+
7
+ - 🌐 基于 Koa.js 的 HTTP 服务器
8
+ - 🔐 Basic Auth 身份验证
9
+ - 🛠️ RESTful API 支持
10
+ - 📡 WebSocket 实时通信
11
+ - 🔄 请求体解析 (JSON)
12
+ - 🌍 可配置的服务器设置
13
+ - 📊 路由管理和中间件支持
14
+ - 📋 内置 API 端点 (系统状态、插件管理、适配器信息)
15
+ - 📝 上下文描述信息支持
16
+
17
+ ## 技术架构
18
+
19
+ - **HTTP框架**: Koa.js
20
+ - **路由**: 自定义Router类扩展@koa/router
21
+ - **WebSocket**: ws 库
22
+ - **身份验证**: koa-basic-auth
23
+ - **请求解析**: koa-bodyparser
24
+
25
+ ## 安装
26
+
27
+ ```bash
28
+ npm install @zhin.js/http
29
+ ```
30
+
31
+ ## 使用
32
+
33
+ ### 基本使用
34
+
35
+ ```javascript
36
+ // 插件会自动启动HTTP服务器
37
+ import '@zhin.js/http'
38
+ ```
39
+
40
+ ### 环境变量配置
41
+
42
+ ```bash
43
+ # 服务器端口 (默认: 8086)
44
+ port=8086
45
+
46
+ # 路由前缀 (可选)
47
+ routerPrefix=/api
48
+
49
+ # 基础认证用户名 (默认: admin)
50
+ username=admin
51
+
52
+ # 基础认证密码 (默认: 123456)
53
+ password=123456
54
+ ```
55
+
56
+ ## 核心组件
57
+
58
+ ### Router 类
59
+
60
+ 扩展了 `@koa/router` 的功能:
61
+
62
+ ```typescript
63
+ class Router extends KoaRouter {
64
+ // WebSocket服务器管理
65
+ ws(path: string, options?: ServerOptions): WebSocketServer
66
+
67
+ // 销毁路由
68
+ destroy(layer: Layer): void
69
+
70
+ // 销毁WebSocket服务器
71
+ destroyWs(wsServer: WebSocketServer): void
72
+
73
+ // 白名单管理(用于历史API排除)
74
+ whiteList: Path[]
75
+ }
76
+ ```
77
+
78
+ ### 全局上下文
79
+
80
+ ```typescript
81
+ declare module '@zhin.js/types' {
82
+ interface GlobalContext {
83
+ koa: Koa, // Koa应用实例
84
+ router: Router, // 路由器实例
85
+ server: Server // HTTP服务器实例
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## API 使用
91
+
92
+ ### 内置 API 端点
93
+
94
+ 插件提供以下内置 API:
95
+
96
+ #### 适配器管理 API
97
+ - `GET /api/adapters` - 获取所有上下文列表
98
+
99
+ **响应格式:**
100
+ ```json
101
+ {
102
+ "success": true,
103
+ "data": [
104
+ {
105
+ "name": "icqq-adapter",
106
+ "desc": "ICQQ适配器,用于连接QQ平台"
107
+ },
108
+ {
109
+ "name": "web-console",
110
+ "desc": "Web控制台服务,提供管理界面"
111
+ }
112
+ ]
113
+ }
114
+ ```
115
+
116
+ #### 其他 API
117
+ - `GET /api/system/status` - 系统状态信息
118
+ - `GET /api/plugins` - 插件列表
119
+ - `GET /api/config` - 配置信息
120
+ - `POST /api/message/send` - 发送消息
121
+ - `POST /api/plugins/:name/reload` - 重载插件
122
+ - `GET /api/health` - 健康检查
123
+
124
+ ### 自定义 HTTP 路由
125
+
126
+ ```javascript
127
+ import { useContext } from 'zhin.js'
128
+
129
+ useContext('router', async (router) => {
130
+ // GET 请求
131
+ router.get('/api/status', async (ctx) => {
132
+ ctx.body = { status: 'ok' }
133
+ })
134
+
135
+ // POST 请求
136
+ router.post('/api/message', async (ctx) => {
137
+ const { message } = ctx.request.body
138
+ // 处理消息...
139
+ ctx.body = { success: true }
140
+ })
141
+ })
142
+ ```
143
+
144
+ ### WebSocket 连接
145
+
146
+ ```javascript
147
+ import { useContext } from 'zhin.js'
148
+
149
+ useContext('router', async (router) => {
150
+ const ws = router.ws('/api/realtime')
151
+
152
+ ws.on('connection', (socket) => {
153
+ socket.send('连接成功')
154
+
155
+ socket.on('message', (data) => {
156
+ console.log('收到消息:', data)
157
+ })
158
+ })
159
+ })
160
+ ```
161
+
162
+ ### Koa 中间件
163
+
164
+ ```javascript
165
+ import { useContext } from 'zhin.js'
166
+
167
+ useContext('koa', async (koa) => {
168
+ koa.use(async (ctx, next) => {
169
+ console.log('请求:', ctx.method, ctx.url)
170
+ await next()
171
+ })
172
+ })
173
+ ```
174
+
175
+ ## 服务器配置
176
+
177
+ ### 启动配置
178
+
179
+ ```javascript
180
+ {
181
+ host: '0.0.0.0', // 监听地址
182
+ port: 8086 // 监听端口
183
+ }
184
+ ```
185
+
186
+ ### 身份验证
187
+
188
+ 默认启用 Basic Auth:
189
+ - 用户名: `admin` (可通过环境变量修改)
190
+ - 密码: `123456` (可通过环境变量修改)
191
+
192
+ ## WebSocket 功能
193
+
194
+ ### 路径管理
195
+
196
+ - 支持多个WebSocket端点
197
+ - 自动路径匹配
198
+ - 连接升级处理
199
+
200
+ ### 连接处理
201
+
202
+ ```javascript
203
+ // 创建WebSocket服务器
204
+ const wsServer = router.ws('/chat')
205
+
206
+ // 处理连接
207
+ wsServer.on('connection', (ws, request) => {
208
+ ws.send('欢迎连接')
209
+ })
210
+
211
+ // 销毁服务器
212
+ router.destroyWs(wsServer)
213
+ ```
214
+
215
+ ## 开发
216
+
217
+ ### 项目结构
218
+
219
+ ```
220
+ src/
221
+ ├── index.ts # 主入口,服务器初始化
222
+ └── router.ts # Router类实现
223
+ ```
224
+
225
+ ### 构建
226
+
227
+ ```bash
228
+ npm run build # 构建插件
229
+ npm run clean # 清理构建文件
230
+ ```
231
+
232
+ ## 依赖项
233
+
234
+ ### 核心依赖
235
+ - `@koa/router` - Koa路由器
236
+ - `koa` - Koa.js框架
237
+ - `ws` - WebSocket库
238
+ - `koa-basic-auth` - 基础认证中间件
239
+ - `koa-bodyparser` - 请求体解析中间件
240
+
241
+ ### 对等依赖
242
+ - `zhin.js` - Zhin核心框架
243
+
244
+ ## 安全考虑
245
+
246
+ - 🔐 默认启用身份验证
247
+ - 🛡️ 请求体大小限制
248
+ - 🔒 WebSocket连接验证
249
+ - 📝 访问日志记录
250
+
251
+ ## 使用场景
252
+
253
+ - 🌐 HTTP API服务
254
+ - 📊 管理后台接口
255
+ - 📡 实时数据推送
256
+ - 🔧 Webhook接收
257
+ - 📱 移动应用后端
258
+
259
+ ## 许可证
260
+
261
+ MIT License
package/lib/index.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { Server } from 'http';
2
+ import Koa from 'koa';
3
+ import { Router } from './router.js';
4
+ export * from './router.js';
5
+ declare module '@zhin.js/types' {
6
+ interface GlobalContext {
7
+ koa: Koa;
8
+ router: Router;
9
+ server: Server;
10
+ }
11
+ }
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,MAAM,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,cAAc,aAAa,CAAC;AAE5B,OAAO,QAAQ,gBAAgB,CAAA;IAC7B,UAAU,aAAa;QACrB,GAAG,EAAE,GAAG,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAA;KACf;CACF"}
package/lib/index.js ADDED
@@ -0,0 +1,200 @@
1
+ import { register, useApp } from '@zhin.js/core';
2
+ import { createServer } from 'http';
3
+ import Koa from 'koa';
4
+ import auth from 'koa-basic-auth';
5
+ import KoaBodyParser from 'koa-bodyparser';
6
+ import { Router } from './router.js';
7
+ import * as process from 'process';
8
+ export * from './router.js';
9
+ const koa = new Koa();
10
+ const server = createServer(koa.callback());
11
+ const router = new Router(server, { prefix: process.env.routerPrefix || '' });
12
+ const username = process.env.username || 'admin';
13
+ const password = process.env.password || '123456';
14
+ const app = useApp();
15
+ koa.use(auth({
16
+ name: username,
17
+ pass: password,
18
+ }));
19
+ // ============================================================================
20
+ // API 路由
21
+ // ============================================================================
22
+ // 系统状态 API
23
+ router.get('/api/system/status', async (ctx) => {
24
+ try {
25
+ ctx.body = {
26
+ success: true,
27
+ data: {
28
+ uptime: process.uptime(),
29
+ memory: process.memoryUsage(),
30
+ cpu: process.cpuUsage(),
31
+ platform: process.platform,
32
+ nodeVersion: process.version,
33
+ pid: process.pid,
34
+ timestamp: new Date().toISOString()
35
+ }
36
+ };
37
+ }
38
+ catch (error) {
39
+ ctx.status = 500;
40
+ ctx.body = { success: false, error: error.message };
41
+ }
42
+ });
43
+ // 健康检查 API
44
+ router.get('/api/health', async (ctx) => {
45
+ ctx.body = {
46
+ success: true,
47
+ status: 'ok',
48
+ timestamp: new Date().toISOString()
49
+ };
50
+ });
51
+ // 插件管理 API
52
+ router.get('/api/plugins', async (ctx) => {
53
+ try {
54
+ // 获取详细的插件数据
55
+ const plugins = app.dependencyList.map(dep => {
56
+ return {
57
+ name: dep.name,
58
+ command_count: dep.commands.length,
59
+ component_count: dep.components.size,
60
+ middleware_count: dep.middlewares.length,
61
+ context_count: dep.contexts.size,
62
+ };
63
+ });
64
+ ctx.body = { success: true, data: plugins };
65
+ }
66
+ catch (error) {
67
+ ctx.status = 500;
68
+ ctx.body = { success: false, error: error.message };
69
+ }
70
+ });
71
+ // 适配器管理 API
72
+ router.get('/api/adapters', async (ctx) => {
73
+ try {
74
+ // 模拟适配器数据
75
+ const adapters = app.contextList.map(ctx => {
76
+ return {
77
+ name: ctx.name,
78
+ desc: ctx.description,
79
+ };
80
+ });
81
+ ctx.body = { success: true, data: adapters };
82
+ }
83
+ catch (error) {
84
+ ctx.status = 500;
85
+ ctx.body = { success: false, error: error.message };
86
+ }
87
+ });
88
+ // 框架配置信息 API
89
+ router.get('/api/config', async (ctx) => {
90
+ try {
91
+ const config = app.getConfig();
92
+ ctx.body = { success: true, data: config };
93
+ }
94
+ catch (error) {
95
+ ctx.status = 500;
96
+ ctx.body = { success: false, error: error.message };
97
+ }
98
+ });
99
+ // 消息发送 API
100
+ router.post('/api/message/send', async (ctx) => {
101
+ try {
102
+ const body = ctx.request.body;
103
+ const { context, bot, id, type, content } = body;
104
+ if (!context || !bot || !id || !type || !content) {
105
+ ctx.status = 400;
106
+ ctx.body = {
107
+ success: false,
108
+ error: 'Missing required fields: context, bot, id, type, content'
109
+ };
110
+ return;
111
+ }
112
+ // 模拟发送消息(实际环境中会调用应用实例的sendMessage方法)
113
+ // console.log 已替换为注释
114
+ ctx.body = {
115
+ success: true,
116
+ message: 'Message sent successfully',
117
+ data: { context, bot, id, type, content, timestamp: new Date().toISOString() }
118
+ };
119
+ }
120
+ catch (error) {
121
+ ctx.status = 500;
122
+ ctx.body = { success: false, error: error.message };
123
+ }
124
+ });
125
+ // 日志 API
126
+ router.get('/api/logs', async (ctx) => {
127
+ try {
128
+ // 模拟日志数据
129
+ const logs = [
130
+ {
131
+ level: 'info',
132
+ message: 'HTTP服务器启动成功',
133
+ timestamp: new Date(Date.now() - 60000).toISOString(),
134
+ source: 'http'
135
+ },
136
+ {
137
+ level: 'info',
138
+ message: 'Web控制台已就绪',
139
+ timestamp: new Date(Date.now() - 50000).toISOString(),
140
+ source: 'console'
141
+ },
142
+ {
143
+ level: 'warn',
144
+ message: 'KOOK适配器连接不稳定',
145
+ timestamp: new Date(Date.now() - 30000).toISOString(),
146
+ source: 'kook'
147
+ },
148
+ {
149
+ level: 'error',
150
+ message: 'ICQQ登录失败',
151
+ timestamp: new Date(Date.now() - 20000).toISOString(),
152
+ source: 'icqq'
153
+ }
154
+ ];
155
+ ctx.body = { success: true, data: logs };
156
+ }
157
+ catch (error) {
158
+ ctx.status = 500;
159
+ ctx.body = { success: false, error: error.message };
160
+ }
161
+ });
162
+ // ============================================================================
163
+ // 上下文注册
164
+ // ============================================================================
165
+ register({
166
+ name: 'server',
167
+ description: "http server",
168
+ mounted(p) {
169
+ return new Promise((resolve) => {
170
+ server.listen({
171
+ host: '0.0.0.0',
172
+ port: Number((process.env.port ||= '8086')),
173
+ }, () => {
174
+ const address = server.address();
175
+ if (!address)
176
+ return;
177
+ const visitAddress = typeof address === 'string' ? address : `${address.address}:${address.port}`;
178
+ p.logger.info(`server is running at http://${visitAddress}`);
179
+ p.logger.info('your username is:', username);
180
+ p.logger.info('your password is:', password);
181
+ resolve(server);
182
+ });
183
+ });
184
+ },
185
+ dispose(s) {
186
+ s.close();
187
+ }
188
+ });
189
+ register({
190
+ name: "koa",
191
+ description: "koa instance",
192
+ value: koa
193
+ });
194
+ register({
195
+ name: 'router',
196
+ description: "koa router",
197
+ value: router
198
+ });
199
+ koa.use(KoaBodyParser()).use(router.routes()).use(router.allowedMethods());
200
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Layer, RouterOptions } from '@koa/router';
2
+ import KoaRouter from "@koa/router";
3
+ import * as http from 'http';
4
+ import { ServerOptions, WebSocketServer } from 'ws';
5
+ type Path = string | RegExp;
6
+ export declare class Router extends KoaRouter {
7
+ server: http.Server;
8
+ wsStack: WebSocketServer[];
9
+ whiteList: Path[];
10
+ constructor(server: http.Server, options?: RouterOptions);
11
+ register(...args: Parameters<KoaRouter['register']>): Layer;
12
+ destroy(layer: Layer): void;
13
+ destroyWs(wsServer: WebSocketServer): void;
14
+ ws(path: string, options?: Omit<ServerOptions, 'noServer' | 'path'>): WebSocketServer;
15
+ }
16
+ export {};
17
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,SAAS,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAGpD,KAAK,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5B,qBAAa,MAAO,SAAQ,SAAS;IAI1B,MAAM,EAAE,IAAI,CAAC,MAAM;IAH5B,OAAO,EAAE,eAAe,EAAE,CAAM;IAChC,SAAS,EAAE,IAAI,EAAE,CAAM;gBAEd,MAAM,EAAE,IAAI,CAAC,MAAM,EAC1B,OAAO,CAAC,EAAE,aAAa;IAKzB,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAMnD,OAAO,CAAC,KAAK,EAAE,KAAK;IAIpB,SAAS,CAAC,QAAQ,EAAE,eAAe;IAKnC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,MAAM,CAAM,GAAG,eAAe;CAoB1F"}
package/lib/router.js ADDED
@@ -0,0 +1,46 @@
1
+ import { remove } from '@zhin.js/core';
2
+ import KoaRouter from "@koa/router";
3
+ import { WebSocketServer } from 'ws';
4
+ import { parse } from 'url';
5
+ export class Router extends KoaRouter {
6
+ server;
7
+ wsStack = [];
8
+ whiteList = []; //用于historyApi排除
9
+ constructor(server, options) {
10
+ super(options);
11
+ this.server = server;
12
+ }
13
+ register(...args) {
14
+ const path = args[0];
15
+ this.whiteList.push(path);
16
+ return super.register(...args);
17
+ }
18
+ destroy(layer) {
19
+ remove(this.stack, layer);
20
+ }
21
+ destroyWs(wsServer) {
22
+ wsServer.close();
23
+ remove(this.wsStack, wsServer);
24
+ }
25
+ ws(path, options = {}) {
26
+ const wsServer = new WebSocketServer({
27
+ noServer: true,
28
+ path,
29
+ ...options,
30
+ });
31
+ this.wsStack.push(wsServer);
32
+ this.server.on('upgrade', (request, socket, head) => {
33
+ const { pathname } = parse(request.url);
34
+ if (this.wsStack.findIndex(wss => wss.options.path === path) === -1) {
35
+ socket.destroy();
36
+ }
37
+ else if (pathname === path) {
38
+ wsServer.handleUpgrade(request, socket, head, ws => {
39
+ wsServer.emit('connection', ws, request);
40
+ });
41
+ }
42
+ });
43
+ return wsServer;
44
+ }
45
+ }
46
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,SAAS,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAiB,eAAe,EAAE,MAAM,IAAI,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAI5B,MAAM,OAAO,MAAO,SAAQ,SAAS;IAI1B;IAHT,OAAO,GAAsB,EAAE,CAAC;IAChC,SAAS,GAAW,EAAE,CAAC,CAAC,gBAAgB;IACxC,YACS,MAAmB,EAC1B,OAAuB;QAEvB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,WAAM,GAAN,MAAM,CAAa;IAI5B,CAAC;IAED,QAAQ,CAAC,GAAG,IAAuC;QACjD,MAAM,IAAI,GAAS,IAAI,CAAC,CAAC,CAAQ,CAAC;QAClC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,KAAY;QAClB,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,SAAS,CAAC,QAAyB;QACjC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,EAAE,CAAC,IAAY,EAAE,UAAoD,EAAE;QACrE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC;YACnC,QAAQ,EAAE,IAAI;YACd,IAAI;YACJ,GAAG,OAAO;SACX,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAI,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpE,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,CAAC;iBAAM,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC7B,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE;oBACjD,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC3C,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@zhin.js/http",
3
+ "version": "1.0.1",
4
+ "description": "Zhin机器人框架HTTP工具",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "import": "./lib/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@koa/router": "latest",
16
+ "koa": "latest",
17
+ "ws": "^8.18.3",
18
+ "koa-basic-auth": "latest",
19
+ "koa-bodyparser": "latest"
20
+ },
21
+ "peerDependencies": {
22
+ "@zhin.js/core": "^1.0.1"
23
+ },
24
+ "devDependencies": {
25
+ "@types/koa": "latest",
26
+ "@types/koa-basic-auth": "latest",
27
+ "@types/koa-bodyparser": "latest",
28
+ "@types/koa__router": "latest",
29
+ "@types/ws": "latest",
30
+ "@zhin.js/types": "^1.0.1"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc",
34
+ "clean": "rm -rf lib"
35
+ }
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1,227 @@
1
+ import {register, useApp} from '@zhin.js/core';
2
+ import { createServer, Server } from 'http';
3
+ import Koa from 'koa';
4
+ import auth from 'koa-basic-auth';
5
+ import KoaBodyParser from 'koa-bodyparser';
6
+ import { Router } from './router.js';
7
+ import * as process from 'process';
8
+
9
+ export * from './router.js';
10
+
11
+ declare module '@zhin.js/types'{
12
+ interface GlobalContext {
13
+ koa: Koa,
14
+ router: Router,
15
+ server: Server
16
+ }
17
+ }
18
+
19
+ const koa = new Koa();
20
+ const server = createServer(koa.callback())
21
+ const router = new Router(server, { prefix: process.env.routerPrefix || '' });
22
+ const username = process.env.username || 'admin';
23
+ const password = process.env.password || '123456';
24
+ const app=useApp()
25
+ koa.use(
26
+ auth({
27
+ name: username,
28
+ pass: password,
29
+ }),
30
+ );
31
+
32
+ // ============================================================================
33
+ // API 路由
34
+ // ============================================================================
35
+
36
+ // 系统状态 API
37
+ router.get('/api/system/status', async (ctx) => {
38
+ try {
39
+ ctx.body = {
40
+ success: true,
41
+ data: {
42
+ uptime: process.uptime(),
43
+ memory: process.memoryUsage(),
44
+ cpu: process.cpuUsage(),
45
+ platform: process.platform,
46
+ nodeVersion: process.version,
47
+ pid: process.pid,
48
+ timestamp: new Date().toISOString()
49
+ }
50
+ }
51
+ } catch (error) {
52
+ ctx.status = 500
53
+ ctx.body = { success: false, error: (error as Error).message }
54
+ }
55
+ })
56
+
57
+ // 健康检查 API
58
+ router.get('/api/health', async (ctx) => {
59
+ ctx.body = {
60
+ success: true,
61
+ status: 'ok',
62
+ timestamp: new Date().toISOString()
63
+ }
64
+ })
65
+
66
+ // 插件管理 API
67
+ router.get('/api/plugins', async (ctx) => {
68
+ try {
69
+ // 获取详细的插件数据
70
+ const plugins = app.dependencyList.map(dep => {
71
+ return {
72
+ name:dep.name,
73
+ command_count:dep.commands.length,
74
+ component_count:dep.components.size,
75
+ middleware_count:dep.middlewares.length,
76
+ context_count:dep.contexts.size,
77
+ }
78
+ })
79
+
80
+ ctx.body = { success: true, data: plugins }
81
+ } catch (error) {
82
+ ctx.status = 500
83
+ ctx.body = { success: false, error: (error as Error).message }
84
+ }
85
+ })
86
+
87
+ // 适配器管理 API
88
+ router.get('/api/adapters', async (ctx) => {
89
+ try {
90
+ // 模拟适配器数据
91
+ const adapters = app.contextList.map(ctx=>{
92
+ return {
93
+ name:ctx.name,
94
+ desc:ctx.description,
95
+ }
96
+ })
97
+
98
+ ctx.body = { success: true, data: adapters }
99
+ } catch (error) {
100
+ ctx.status = 500
101
+ ctx.body = { success: false, error: (error as Error).message }
102
+ }
103
+ })
104
+
105
+ // 框架配置信息 API
106
+ router.get('/api/config', async (ctx) => {
107
+ try {
108
+ const config = app.getConfig()
109
+
110
+ ctx.body = { success: true, data: config }
111
+ } catch (error) {
112
+ ctx.status = 500
113
+ ctx.body = { success: false, error: (error as Error).message }
114
+ }
115
+ })
116
+
117
+ // 消息发送 API
118
+ router.post('/api/message/send', async (ctx) => {
119
+ try {
120
+ const body = ctx.request.body as any
121
+ const { context, bot, id, type, content } = body
122
+
123
+ if (!context || !bot || !id || !type || !content) {
124
+ ctx.status = 400
125
+ ctx.body = {
126
+ success: false,
127
+ error: 'Missing required fields: context, bot, id, type, content'
128
+ }
129
+ return
130
+ }
131
+
132
+ // 模拟发送消息(实际环境中会调用应用实例的sendMessage方法)
133
+ // console.log 已替换为注释
134
+
135
+ ctx.body = {
136
+ success: true,
137
+ message: 'Message sent successfully',
138
+ data: { context, bot, id, type, content, timestamp: new Date().toISOString() }
139
+ }
140
+ } catch (error) {
141
+ ctx.status = 500
142
+ ctx.body = { success: false, error: (error as Error).message }
143
+ }
144
+ })
145
+
146
+ // 日志 API
147
+ router.get('/api/logs', async (ctx) => {
148
+ try {
149
+ // 模拟日志数据
150
+ const logs = [
151
+ {
152
+ level: 'info',
153
+ message: 'HTTP服务器启动成功',
154
+ timestamp: new Date(Date.now() - 60000).toISOString(),
155
+ source: 'http'
156
+ },
157
+ {
158
+ level: 'info',
159
+ message: 'Web控制台已就绪',
160
+ timestamp: new Date(Date.now() - 50000).toISOString(),
161
+ source: 'console'
162
+ },
163
+ {
164
+ level: 'warn',
165
+ message: 'KOOK适配器连接不稳定',
166
+ timestamp: new Date(Date.now() - 30000).toISOString(),
167
+ source: 'kook'
168
+ },
169
+ {
170
+ level: 'error',
171
+ message: 'ICQQ登录失败',
172
+ timestamp: new Date(Date.now() - 20000).toISOString(),
173
+ source: 'icqq'
174
+ }
175
+ ]
176
+
177
+ ctx.body = { success: true, data: logs }
178
+ } catch (error) {
179
+ ctx.status = 500
180
+ ctx.body = { success: false, error: (error as Error).message }
181
+ }
182
+ })
183
+
184
+ // ============================================================================
185
+ // 上下文注册
186
+ // ============================================================================
187
+
188
+ register({
189
+ name: 'server',
190
+ description:"http server",
191
+ mounted(p) {
192
+ return new Promise<Server>((resolve) => {
193
+ server.listen(
194
+ {
195
+ host: '0.0.0.0',
196
+ port: Number((process.env.port ||= '8086')),
197
+ },
198
+ () => {
199
+ const address = server.address();
200
+ if (!address) return;
201
+ const visitAddress = typeof address === 'string' ? address : `${address.address}:${address.port}`;
202
+ p.logger.info(`server is running at http://${visitAddress}`);
203
+ p.logger.info('your username is:', username);
204
+ p.logger.info('your password is:', password);
205
+ resolve(server)
206
+ },
207
+ )
208
+ })
209
+ },
210
+ dispose(s) {
211
+ s.close()
212
+ }
213
+ })
214
+
215
+ register({
216
+ name: "koa",
217
+ description:"koa instance",
218
+ value: koa
219
+ })
220
+
221
+ register({
222
+ name: 'router',
223
+ description:"koa router",
224
+ value: router
225
+ })
226
+
227
+ koa.use(KoaBodyParser()).use(router.routes()).use(router.allowedMethods());
package/src/router.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { remove } from '@zhin.js/core';
2
+ import { Layer, RouterOptions } from '@koa/router';
3
+ import KoaRouter from "@koa/router";
4
+ import * as http from 'http';
5
+ import { ServerOptions, WebSocketServer } from 'ws';
6
+ import { parse } from 'url';
7
+
8
+ type Path = string | RegExp;
9
+
10
+ export class Router extends KoaRouter {
11
+ wsStack: WebSocketServer[] = [];
12
+ whiteList: Path[] = []; //用于historyApi排除
13
+ constructor(
14
+ public server: http.Server,
15
+ options?: RouterOptions,
16
+ ) {
17
+ super(options);
18
+ }
19
+
20
+ register(...args: Parameters<KoaRouter['register']>) {
21
+ const path: Path = args[0] as any;
22
+ this.whiteList.push(path);
23
+ return super.register(...args);
24
+ }
25
+
26
+ destroy(layer: Layer) {
27
+ remove(this.stack, layer);
28
+ }
29
+
30
+ destroyWs(wsServer: WebSocketServer) {
31
+ wsServer.close();
32
+ remove(this.wsStack, wsServer);
33
+ }
34
+
35
+ ws(path: string, options: Omit<ServerOptions, 'noServer' | 'path'> = {}): WebSocketServer {
36
+ const wsServer = new WebSocketServer({
37
+ noServer: true,
38
+ path,
39
+ ...options,
40
+ });
41
+ this.wsStack.push(wsServer);
42
+
43
+ this.server!.on('upgrade', (request, socket, head) => {
44
+ const { pathname } = parse(request.url!);
45
+ if (this.wsStack.findIndex(wss => wss.options.path === path) === -1) {
46
+ socket.destroy();
47
+ } else if (pathname === path) {
48
+ wsServer.handleUpgrade(request, socket, head, ws => {
49
+ wsServer.emit('connection', ws, request);
50
+ });
51
+ }
52
+ });
53
+ return wsServer;
54
+ }
55
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "outDir": "./lib",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "allowSyntheticDefaultImports": true,
15
+ "experimentalDecorators": true,
16
+ "emitDecoratorMetadata": true,
17
+ "declaration": true,
18
+ "declarationMap": true,
19
+ "sourceMap": true
20
+ },
21
+ "include": ["src/**/*"],
22
+ "exclude": ["lib", "node_modules"]
23
+ }