@zhin.js/http 1.0.6 → 1.0.8

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/lib/index.js CHANGED
@@ -1,54 +1,61 @@
1
- import { register, defineSchema, Schema, usePlugin, useApp, useDatabase, } from "@zhin.js/core";
1
+ import { usePlugin, Adapter } from "zhin.js";
2
+ import { Schema } from "@zhin.js/schema";
2
3
  import { createServer } from "http";
3
4
  import os from "node:os";
4
5
  import Koa from "koa";
5
6
  import auth from "koa-basic-auth";
6
- import KoaBodyParser from "koa-bodyparser";
7
+ import body from "koa-body";
7
8
  import { Router } from "./router.js";
8
- import * as process from "process";
9
9
  export * from "./router.js";
10
- const plugin = usePlugin();
11
- const schema = defineSchema(Schema.object({
12
- port: Schema.number("port").default(8086).description("HTTP 服务端口"),
13
- username: Schema.string("username").description("HTTP 基本认证用户名, 默认为当前系统用户名"),
14
- password: Schema.string("password").description("HTTP 基本认证密码, 默认为随机生成的6位字符串"),
15
- base: Schema.string("base")
10
+ // Schema 定义
11
+ export const httpSchema = Schema.object({
12
+ port: Schema.number().default(8086).description("HTTP 服务端口"),
13
+ username: Schema.string().description("HTTP 基本认证用户名, 默认为当前系统用户名"),
14
+ password: Schema.string().description("HTTP 基本认证密码, 默认为随机生成的6位字符串"),
15
+ base: Schema.string()
16
16
  .default("/api")
17
17
  .description("HTTP 路由前缀, 默认为 /api"),
18
- }));
19
- const koa = new Koa();
20
- const server = createServer(koa.callback());
21
- const router = new Router(server, { prefix: process.env.routerPrefix || "" });
18
+ });
22
19
  // 获取当前计算机登录用户名
23
20
  const getCurrentUsername = () => {
24
21
  try {
25
22
  return os.userInfo().username;
26
23
  }
27
24
  catch {
28
- return "admin"; // 如果获取失败,使用默认用户名
25
+ return "admin";
29
26
  }
30
27
  };
31
28
  // 生成6位随机密码
32
29
  const generateRandomPassword = () => {
33
30
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
34
- let result = "";
35
- for (let i = 0; i < 6; i++) {
36
- result += chars.charAt(Math.floor(Math.random() * chars.length));
37
- }
38
- return result;
31
+ return Array.from({ length: 6 }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join("");
39
32
  };
40
- const { port = 8086, username = getCurrentUsername(), password = generateRandomPassword(), base = "/api", } = schema(plugin.config, "http");
41
- const app = useApp();
42
- koa.use(auth({
43
- name: username,
44
- pass: password,
45
- }));
46
- // ============================================================================
47
- // API 路由
48
- // ============================================================================
49
- // 系统状态 API
50
- router.get(`${base}/system/status`, async (ctx) => {
51
- try {
33
+ const { provide, root, useContext, logger } = usePlugin();
34
+ // 创建实例
35
+ const koa = new Koa();
36
+ const server = createServer(koa.callback());
37
+ const router = new Router(server, { prefix: process.env.routerPrefix || "" });
38
+ // 注册 server 上下文
39
+ provide({
40
+ name: "server",
41
+ description: "http server",
42
+ value: server,
43
+ dispose(s) {
44
+ s.close();
45
+ },
46
+ });
47
+ // 使用配置服务
48
+ useContext("config", (configService) => {
49
+ const appConfig = configService.get("zhin.config.yml");
50
+ const httpConfig = appConfig.http || {};
51
+ const { port = 8086, username = getCurrentUsername(), password = generateRandomPassword(), base = "/api", } = httpConfig;
52
+ // 设置基本认证
53
+ koa.use(auth({ name: username, pass: password }));
54
+ // ============================================================================
55
+ // API 路由
56
+ // ============================================================================
57
+ // 系统状态 API
58
+ router.get(`${base}/system/status`, async (ctx) => {
52
59
  ctx.body = {
53
60
  success: true,
54
61
  data: {
@@ -61,319 +68,215 @@ router.get(`${base}/system/status`, async (ctx) => {
61
68
  timestamp: new Date().toISOString(),
62
69
  },
63
70
  };
64
- }
65
- catch (error) {
66
- ctx.status = 500;
67
- ctx.body = { success: false, error: error.message };
68
- }
69
- });
70
- // 健康检查 API
71
- router.get(`${base}/health`, async (ctx) => {
72
- ctx.body = {
73
- success: true,
74
- status: "ok",
75
- timestamp: new Date().toISOString(),
76
- };
77
- });
78
- // 统计信息 API
79
- router.get(`${base}/stats`, async (ctx) => {
80
- try {
81
- // 统计插件数量
82
- const pluginCount = app.dependencyList.length;
83
- const activePluginCount = app.dependencyList.filter((dep) => dep.mounted).length;
71
+ });
72
+ // 健康检查 API
73
+ router.get(`${base}/health`, async (ctx) => {
74
+ ctx.body = {
75
+ success: true,
76
+ status: "ok",
77
+ timestamp: new Date().toISOString(),
78
+ };
79
+ });
80
+ // 统计信息 API
81
+ router.get(`${base}/stats`, async (ctx) => {
82
+ const allPlugins = root.children;
84
83
  // 统计机器人数量
85
84
  let botCount = 0;
86
85
  let onlineBotCount = 0;
87
- for (const context of app.contextList) {
88
- const adapter = app.getContext(context.name);
89
- if (adapter && typeof adapter === "object" && "bots" in adapter) {
90
- const adapterBots = adapter.bots;
91
- if (adapterBots && adapterBots instanceof Map) {
92
- botCount += adapterBots.size;
93
- for (const bot of adapterBots.values()) {
94
- if (bot.$connected)
95
- onlineBotCount++;
96
- }
86
+ for (const adapterName of root.adapters) {
87
+ const adapter = root.inject(adapterName);
88
+ if (adapter instanceof Adapter) {
89
+ botCount += adapter.bots.size;
90
+ for (const bot of adapter.bots.values()) {
91
+ if (bot.$connected)
92
+ onlineBotCount++;
97
93
  }
98
94
  }
99
95
  }
100
96
  // 统计命令和组件
101
- let commandCount = 0;
102
- let componentCount = 0;
103
- for (const dep of app.dependencyList) {
104
- commandCount += dep.commands.length;
105
- componentCount += dep.components.size;
106
- }
97
+ const commandService = root.inject("command");
98
+ const componentService = root.inject("component");
99
+ const commandCount = commandService?.items.length || 0;
100
+ const componentCount = componentService?.byName.size || 0;
107
101
  ctx.body = {
108
102
  success: true,
109
103
  data: {
110
- plugins: { total: pluginCount, active: activePluginCount },
104
+ plugins: { total: allPlugins.length, active: allPlugins.length },
111
105
  bots: { total: botCount, online: onlineBotCount },
112
106
  commands: commandCount,
113
107
  components: componentCount,
114
108
  uptime: process.uptime(),
115
- memory: process.memoryUsage().heapUsed / 1024 / 1024, // MB
109
+ memory: process.memoryUsage().heapUsed / 1024 / 1024,
116
110
  },
117
111
  };
118
- }
119
- catch (error) {
120
- ctx.status = 500;
121
- ctx.body = { success: false, error: error.message };
122
- }
123
- });
124
- // 插件管理 API
125
- router.get(`${base}/plugins`, async (ctx) => {
126
- try {
127
- // 获取详细的插件数据
128
- const plugins = app.dependencyList.map((dep) => {
112
+ });
113
+ // 插件列表 API
114
+ router.get(`${base}/plugins`, async (ctx) => {
115
+ const plugins = root.children.map((p) => {
116
+ const features = p.features;
129
117
  return {
130
- name: dep.name,
131
- status: dep.mounted ? "active" : "inactive",
132
- commandCount: dep.commands.length,
133
- componentCount: dep.components.size,
134
- middlewareCount: dep.middlewares.length,
135
- contextCount: dep.contexts.size,
136
- description: dep.description || "无描述",
118
+ name: p.name,
119
+ status: "active",
120
+ // 向后兼容:返回各项数量
121
+ commandCount: features.commands.length,
122
+ componentCount: features.components.length,
123
+ middlewareCount: features.middlewares.length,
124
+ cronCount: features.crons.length,
125
+ contextCount: p.contexts.size,
126
+ filePath: p.filePath,
127
+ description: p.name,
128
+ // 新格式:也返回 features 对象
129
+ features,
137
130
  };
138
131
  });
139
132
  ctx.body = { success: true, data: plugins, total: plugins.length };
140
- }
141
- catch (error) {
142
- ctx.status = 500;
143
- ctx.body = { success: false, error: error.message };
144
- }
145
- });
146
- // 插件详情 API
147
- router.get("/api/plugins/:name", async (ctx) => {
148
- try {
133
+ });
134
+ // 插件详情 API
135
+ router.get(`${base}/plugins/:name`, async (ctx) => {
149
136
  const pluginName = ctx.params.name;
150
- const plugin = app.dependencyList.find((dep) => dep.name === pluginName);
137
+ const plugin = root.children.find((p) => p.name === pluginName);
151
138
  if (!plugin) {
152
139
  ctx.status = 404;
153
140
  ctx.body = { success: false, error: "插件不存在" };
154
141
  return;
155
142
  }
156
- // 获取命令详情
157
- const commands = plugin.commands.map((cmd) => ({
143
+ const commandService = root.inject("command");
144
+ const commands = (commandService?.items || []).map((cmd) => ({
158
145
  name: cmd.pattern,
146
+ desc: cmd.helpInfo?.desc,
147
+ usage: cmd.helpInfo?.usage,
148
+ examples: cmd.helpInfo?.examples,
159
149
  }));
160
- // 获取组件详情
161
- const components = Array.from(plugin.components.entries()).map(([name, comp]) => ({
150
+ const contexts = Array.from(plugin.contexts.entries()).map(([name]) => ({
162
151
  name,
163
- props: comp.props || {},
164
- type: typeof comp,
165
152
  }));
166
- // 获取中间件详情
167
- const middlewares = plugin.middlewares.map((_, index) => ({
168
- id: `middleware-${index}`,
169
- type: "function",
170
- }));
171
- // 获取上下文详情
172
- const contexts = Array.from(plugin.contexts.entries()).map(([name, ctx]) => ({
153
+ const features = plugin.features;
154
+ // 构建组件列表
155
+ const components = features.components.map((name) => ({
173
156
  name,
174
- description: ctx.description || "无描述",
157
+ type: "component",
158
+ props: {},
175
159
  }));
176
- // 获取定时任务详情
177
- const crons = plugin.crons.map((cron, index) => ({
178
- id: `cron-${index}`,
179
- pattern: cron.pattern || "unknown",
180
- running: cron.running || false,
160
+ // 构建中间件列表
161
+ const middlewares = features.middlewares.map((name, index) => ({
162
+ id: `middleware-${index}`,
163
+ type: name,
181
164
  }));
182
- // 获取数据模型详情
183
- const definitions = Array.from(plugin.definitions.entries()).map(([name, definition]) => ({
184
- name,
185
- fields: Object.keys(definition),
165
+ // 构建定时任务列表
166
+ const crons = features.crons.map((expression, index) => ({
167
+ id: `cron-${index}`,
168
+ pattern: expression,
169
+ running: true,
186
170
  }));
187
171
  ctx.body = {
188
172
  success: true,
189
173
  data: {
190
174
  name: plugin.name,
191
- filename: plugin.filename,
192
- status: plugin.mounted ? "active" : "inactive",
193
- description: plugin.description || "无描述",
175
+ filename: plugin.filePath,
176
+ filePath: plugin.filePath,
177
+ status: "active",
178
+ description: plugin.name,
179
+ features,
180
+ contexts,
194
181
  commands,
195
182
  components,
196
183
  middlewares,
197
- contexts,
198
184
  crons,
199
- definitions,
185
+ definitions: [],
200
186
  statistics: {
201
- commandCount: commands.length,
202
- componentCount: components.length,
203
- middlewareCount: middlewares.length,
187
+ commandCount: features.commands.length,
188
+ componentCount: features.components.length,
204
189
  contextCount: contexts.length,
205
- cronCount: crons.length,
206
- definitionCount: definitions.length,
190
+ cronCount: features.crons.length,
191
+ middlewareCount: features.middlewares.length,
192
+ definitionCount: 0,
207
193
  },
208
194
  },
209
195
  };
210
- }
211
- catch (error) {
212
- ctx.status = 500;
213
- ctx.body = { success: false, error: error.message };
214
- }
215
- });
216
- // 适配器和机器人状态 API
217
- router.get(`${base}/bots`, async (ctx) => {
218
- try {
196
+ });
197
+ // 机器人列表 API
198
+ router.get(`${base}/bots`, async (ctx) => {
219
199
  const bots = [];
220
- // 遍历所有上下文,查找适配器
221
- for (const context of app.contextList) {
222
- const adapter = app.getContext(context.name);
223
- if (adapter && typeof adapter === "object" && "bots" in adapter) {
224
- const adapterBots = adapter.bots;
225
- if (adapterBots && adapterBots instanceof Map) {
226
- for (const [botName, bot] of adapterBots.entries()) {
227
- bots.push({
228
- name: botName,
229
- adapter: context.name,
230
- connected: bot.$connected || false,
231
- status: bot.$connected ? "online" : "offline",
232
- // 移除 config 字段以保护隐私
233
- });
234
- }
200
+ for (const name of root.adapters) {
201
+ const adapter = root.inject(name);
202
+ if (adapter instanceof Adapter) {
203
+ for (const [botName, bot] of adapter.bots.entries()) {
204
+ bots.push({
205
+ name: botName,
206
+ adapter: name,
207
+ connected: bot.$connected || false,
208
+ status: bot.$connected ? "online" : "offline",
209
+ });
235
210
  }
236
211
  }
237
212
  }
238
213
  ctx.body = { success: true, data: bots, total: bots.length };
239
- }
240
- catch (error) {
241
- ctx.status = 500;
242
- ctx.body = { success: false, error: error.message };
243
- }
244
- });
245
- // 框架配置信息 API
246
- router.get(`${base}/config`, async (ctx) => {
247
- try {
248
- const config = app.getConfig();
249
- ctx.body = { success: true, data: config };
250
- }
251
- catch (error) {
252
- ctx.status = 500;
253
- ctx.body = { success: false, error: error.message };
254
- }
255
- });
256
- // 获取所有插件的 Schema API
257
- router.get(`${base}/schemas`, async (ctx) => {
258
- try {
259
- const schemas = {};
260
- // 获取 App 的 Schema
261
- const appSchema = app.schema.toJSON();
262
- if (appSchema) {
263
- schemas["app"] = appSchema;
264
- }
265
- // 获取所有插件的 Schema
266
- for (const plugin of app.dependencyList) {
267
- const schema = plugin.schema.toJSON();
268
- if (schema) {
269
- schemas[plugin.name] = schema;
270
- }
271
- }
272
- ctx.body = {
273
- success: true,
274
- data: schemas,
275
- total: Object.keys(schemas).length,
276
- };
277
- }
278
- catch (error) {
279
- ctx.status = 500;
280
- ctx.body = { success: false, error: error.message };
281
- }
282
- });
283
- // 获取单个插件的 Schema API
284
- router.get(`${base}/schemas/:name`, async (ctx) => {
285
- try {
286
- const { name } = ctx.params;
287
- if (name === "app") {
288
- const schema = app.schema?.toJSON();
289
- if (!schema) {
290
- ctx.status = 404;
291
- ctx.body = { success: false, error: "App schema not found" };
292
- return;
293
- }
294
- ctx.body = { success: true, data: schema };
295
- return;
296
- }
297
- const plugin = app.findPluginByName(name);
298
- if (!plugin) {
299
- ctx.status = 404;
300
- ctx.body = { success: false, error: `Plugin ${name} not found` };
301
- return;
302
- }
303
- const schema = plugin.schema.toJSON();
304
- if (!schema) {
305
- ctx.status = 404;
306
- ctx.body = {
307
- success: false,
308
- error: `Schema for plugin ${name} not found`,
309
- };
310
- return;
311
- }
312
- ctx.body = { success: true, data: schema };
313
- }
314
- catch (error) {
315
- ctx.status = 500;
316
- ctx.body = { success: false, error: error.message };
317
- }
318
- });
319
- // 获取插件配置 API
320
- router.get(`${base}/config/:name`, async (ctx) => {
321
- try {
214
+ });
215
+ // 配置 API
216
+ router.get(`${base}/config`, async (ctx) => {
217
+ ctx.body = { success: true, data: configService.get("zhin.config.yml") };
218
+ });
219
+ router.get(`${base}/config/:name`, async (ctx) => {
322
220
  const { name } = ctx.params;
323
221
  if (name === "app") {
324
- const config = app.getConfig();
325
- ctx.body = { success: true, data: config };
222
+ ctx.body = { success: true, data: configService.get("zhin.config.yml") };
326
223
  return;
327
224
  }
328
- const plugin = app.findPluginByName(name);
225
+ const plugin = root.children.find((p) => p.name === name);
329
226
  if (!plugin) {
330
227
  ctx.status = 404;
331
228
  ctx.body = { success: false, error: `Plugin ${name} not found` };
332
229
  return;
333
230
  }
334
- const config = plugin.config;
335
- ctx.body = { success: true, data: config };
336
- }
337
- catch (error) {
338
- ctx.status = 500;
339
- ctx.body = { success: false, error: error.message };
340
- }
341
- });
342
- // 更新插件配置 API
343
- router.post(`${base}/config/:name`, async (ctx) => {
344
- try {
231
+ ctx.body = {
232
+ success: true,
233
+ data: { name: plugin.name, filePath: plugin.filePath },
234
+ };
235
+ });
236
+ router.post(`${base}/config/:name`, async (ctx) => {
345
237
  const { name } = ctx.params;
346
- const newConfig = ctx.request.body;
347
238
  if (name === "app") {
348
- app.config = newConfig;
349
239
  ctx.body = {
350
240
  success: true,
351
- message: "App configuration updated successfully",
352
- data: app.getConfig(),
241
+ message: "App configuration update not implemented yet",
353
242
  };
354
243
  return;
355
244
  }
356
- const plugin = app.findPluginByName(name);
245
+ const plugin = root.children.find((p) => p.name === name);
357
246
  if (!plugin) {
358
247
  ctx.status = 404;
359
248
  ctx.body = { success: false, error: `Plugin ${name} not found` };
360
249
  return;
361
250
  }
362
- plugin.config = newConfig;
363
251
  ctx.body = {
364
252
  success: true,
365
- message: `Plugin ${name} configuration updated successfully`,
366
- data: plugin.config,
253
+ message: "Plugin configuration update not implemented yet",
367
254
  };
368
- }
369
- catch (error) {
370
- ctx.status = 500;
371
- ctx.body = { success: false, error: error.message };
372
- }
373
- });
374
- // 消息发送 API
375
- router.post(`${base}/message/send`, async (ctx) => {
376
- try {
255
+ });
256
+ // Schema API - 获取所有插件 Schema
257
+ router.get(`${base}/schemas`, async (ctx) => {
258
+ const schemaService = root.inject('schema');
259
+ const schemas = {};
260
+ if (schemaService) {
261
+ for (const [name, schema] of schemaService.items.entries()) {
262
+ schemas[name] = schema.toJSON();
263
+ }
264
+ }
265
+ ctx.body = { success: true, data: schemas };
266
+ });
267
+ // Schema API - 获取单个插件 Schema
268
+ router.get(`${base}/schema/:name`, async (ctx) => {
269
+ const schemaService = root.inject('schema');
270
+ const { name } = ctx.params;
271
+ const schema = schemaService?.get(name);
272
+ if (!schema) {
273
+ ctx.body = { success: true, data: null };
274
+ return;
275
+ }
276
+ ctx.body = { success: true, data: schema.toJSON() };
277
+ });
278
+ // 消息发送 API
279
+ router.post(`${base}/message/send`, async (ctx) => {
377
280
  const body = ctx.request.body;
378
281
  const { context, bot, id, type, content } = body;
379
282
  if (!context || !bot || !id || !type || !content) {
@@ -384,8 +287,6 @@ router.post(`${base}/message/send`, async (ctx) => {
384
287
  };
385
288
  return;
386
289
  }
387
- // 模拟发送消息(实际环境中会调用应用实例的sendMessage方法)
388
- // console.log 已替换为注释
389
290
  ctx.body = {
390
291
  success: true,
391
292
  message: "Message sent successfully",
@@ -398,112 +299,85 @@ router.post(`${base}/message/send`, async (ctx) => {
398
299
  timestamp: new Date().toISOString(),
399
300
  },
400
301
  };
401
- }
402
- catch (error) {
403
- ctx.status = 500;
404
- ctx.body = { success: false, error: error.message };
405
- }
406
- });
407
- // 日志 API - 获取日志
408
- router.get(`${base}/logs`, async (ctx) => {
409
- try {
410
- const database = useDatabase();
411
- if (!database) {
412
- ctx.status = 503;
413
- ctx.body = { success: false, error: "Database not available" };
302
+ });
303
+ server.listen({ host: "127.0.0.1", port }, () => {
304
+ const address = server.address();
305
+ if (!address)
414
306
  return;
415
- }
416
- // 获取查询参数
307
+ const visitAddress = typeof address === "string"
308
+ ? address
309
+ : `localhost:${address.port}`;
310
+ const apiUrl = `http://${visitAddress}${base}`;
311
+ logger.info("╔════════════════════════════════════════╗");
312
+ logger.info("║ HTTP 服务已启动 ║");
313
+ logger.info("╠════════════════════════════════════════╣");
314
+ logger.info(`║ 监听端口: ${port.toString().padEnd(32)}║`);
315
+ logger.info(`║ API 地址: ${apiUrl.padEnd(32)}║`);
316
+ logger.info(`║ 基础认证: ${username.padEnd(32)}║`);
317
+ logger.info(`║ 密码: ${password.padEnd(32)}║`);
318
+ logger.info("╚════════════════════════════════════════╝");
319
+ });
320
+ });
321
+ // 使用数据库服务(可选)
322
+ useContext("database", (database) => {
323
+ const configService = root.inject("config");
324
+ const appConfig = configService.get("zhin.config.yml");
325
+ const base = appConfig.http?.base || "/api";
326
+ // 日志 API - 获取日志
327
+ router.get(`${base}/logs`, async (ctx) => {
417
328
  const limit = parseInt(ctx.query.limit) || 100;
418
329
  const level = ctx.query.level;
419
- const LogModel = database.model("SystemLog");
330
+ const LogModel = database.models.get("SystemLog");
420
331
  if (!LogModel) {
421
332
  ctx.status = 500;
422
333
  ctx.body = { success: false, error: "SystemLog model not found" };
423
334
  return;
424
335
  }
425
- // 查询日志
426
336
  let selection = LogModel.select();
427
- // 按级别过滤
428
337
  if (level && level !== "all") {
429
338
  selection = selection.where({ level });
430
339
  }
431
- // 按时间倒序,限制数量
432
340
  const logs = await selection.orderBy("timestamp", "DESC").limit(limit);
433
- // 格式化返回数据
434
- const formattedLogs = logs.map((log) => ({
435
- level: log.level,
436
- name: log.name,
437
- message: log.message,
438
- source: log.source,
439
- timestamp: log.timestamp instanceof Date
440
- ? log.timestamp.toISOString()
441
- : log.timestamp,
442
- }));
443
341
  ctx.body = {
444
342
  success: true,
445
- data: formattedLogs,
446
- total: formattedLogs.length,
343
+ data: logs.map((log) => ({
344
+ level: log.level,
345
+ name: log.name,
346
+ message: log.message,
347
+ source: log.source,
348
+ timestamp: log.timestamp instanceof Date
349
+ ? log.timestamp.toISOString()
350
+ : log.timestamp,
351
+ })),
352
+ total: logs.length,
447
353
  };
448
- }
449
- catch (error) {
450
- ctx.status = 500;
451
- ctx.body = { success: false, error: error.message };
452
- }
453
- });
454
- // 日志 API - 清空日志
455
- router.delete(`${base}/logs`, async (ctx) => {
456
- try {
457
- const database = useDatabase();
458
- if (!database) {
459
- ctx.status = 503;
460
- ctx.body = { success: false, error: "Database not available" };
461
- return;
462
- }
463
- const LogModel = database.model("SystemLog");
354
+ });
355
+ // 日志 API - 清空日志
356
+ router.delete(`${base}/logs`, async (ctx) => {
357
+ const LogModel = database.models.get("SystemLog");
464
358
  if (!LogModel) {
465
359
  ctx.status = 500;
466
360
  ctx.body = { success: false, error: "SystemLog model not found" };
467
361
  return;
468
362
  }
469
- // 删除所有日志
470
363
  await LogModel.delete({});
471
- ctx.body = {
472
- success: true,
473
- message: "日志已清空",
474
- };
475
- }
476
- catch (error) {
477
- ctx.status = 500;
478
- ctx.body = { success: false, error: error.message };
479
- }
480
- });
481
- // 日志 API - 获取日志统计
482
- router.get(`${base}/logs/stats`, async (ctx) => {
483
- try {
484
- const database = useDatabase();
485
- if (!database) {
486
- ctx.status = 503;
487
- ctx.body = { success: false, error: "Database not available" };
488
- return;
489
- }
490
- const LogModel = database.model("SystemLog");
364
+ ctx.body = { success: true, message: "日志已清空" };
365
+ });
366
+ // 日志统计 API
367
+ router.get(`${base}/logs/stats`, async (ctx) => {
368
+ const LogModel = database.models.get("SystemLog");
491
369
  if (!LogModel) {
492
370
  ctx.status = 500;
493
371
  ctx.body = { success: false, error: "SystemLog model not found" };
494
372
  return;
495
373
  }
496
- // 获取总日志数
497
374
  const total = await LogModel.select();
498
- const totalCount = total.length;
499
- // 获取各级别日志数
500
375
  const levels = ["info", "warn", "error"];
501
376
  const levelCounts = {};
502
377
  for (const level of levels) {
503
378
  const count = await LogModel.select().where({ level });
504
379
  levelCounts[level] = count.length;
505
380
  }
506
- // 获取最旧日志时间
507
381
  const oldestLog = await LogModel.select("timestamp")
508
382
  .orderBy("timestamp", "ASC")
509
383
  .limit(1);
@@ -514,28 +388,12 @@ router.get(`${base}/logs/stats`, async (ctx) => {
514
388
  : null;
515
389
  ctx.body = {
516
390
  success: true,
517
- data: {
518
- total: totalCount,
519
- byLevel: levelCounts,
520
- oldestTimestamp,
521
- },
391
+ data: { total: total.length, byLevel: levelCounts, oldestTimestamp },
522
392
  };
523
- }
524
- catch (error) {
525
- ctx.status = 500;
526
- ctx.body = { success: false, error: error.message };
527
- }
528
- });
529
- // 日志 API - 清理旧日志(手动触发)
530
- router.post(`${base}/logs/cleanup`, async (ctx) => {
531
- try {
532
- const database = useDatabase();
533
- if (!database) {
534
- ctx.status = 503;
535
- ctx.body = { success: false, error: "Database not available" };
536
- return;
537
- }
538
- const LogModel = database.model("SystemLog");
393
+ });
394
+ // 日志清理 API
395
+ router.post(`${base}/logs/cleanup`, async (ctx) => {
396
+ const LogModel = database.models.get("SystemLog");
539
397
  if (!LogModel) {
540
398
  ctx.status = 500;
541
399
  ctx.body = { success: false, error: "SystemLog model not found" };
@@ -543,27 +401,25 @@ router.post(`${base}/logs/cleanup`, async (ctx) => {
543
401
  }
544
402
  const { days, maxRecords } = ctx.request.body || {};
545
403
  let deletedCount = 0;
546
- // 按天数清理
547
404
  if (days && typeof days === "number" && days > 0) {
548
405
  const cutoffDate = new Date();
549
406
  cutoffDate.setDate(cutoffDate.getDate() - days);
550
407
  const deleted = await LogModel.delete({ timestamp: { $lt: cutoffDate } });
551
- deletedCount += deleted || 0;
408
+ deletedCount +=
409
+ typeof deleted === "number" ? deleted : deleted?.length || 0;
552
410
  }
553
- // 按数量清理
554
411
  if (maxRecords && typeof maxRecords === "number" && maxRecords > 0) {
555
- const totalCount = await LogModel.select();
556
- if (totalCount.length > maxRecords) {
557
- const excessCount = totalCount - maxRecords;
412
+ const totalLogs = await LogModel.select();
413
+ if (totalLogs.length > maxRecords) {
414
+ const excessCount = totalLogs.length - maxRecords;
558
415
  const oldestLogs = await LogModel.select("id", "timestamp")
559
416
  .orderBy("timestamp", "ASC")
560
417
  .limit(excessCount);
561
418
  const idsToDelete = oldestLogs.map((log) => log.id);
562
419
  if (idsToDelete.length > 0) {
563
- const deleted = await LogModel
564
- .delete()
565
- .where({ id: { $in: idsToDelete } });
566
- deletedCount += deleted || 0;
420
+ const deleted = await LogModel.delete({ id: { $in: idsToDelete } });
421
+ deletedCount +=
422
+ typeof deleted === "number" ? deleted : deleted?.length || 0;
567
423
  }
568
424
  }
569
425
  }
@@ -572,50 +428,19 @@ router.post(`${base}/logs/cleanup`, async (ctx) => {
572
428
  message: `已清理 ${deletedCount} 条日志`,
573
429
  deletedCount,
574
430
  };
575
- }
576
- catch (error) {
577
- ctx.status = 500;
578
- ctx.body = { success: false, error: error.message };
579
- }
580
- });
581
- // ============================================================================
582
- // 上下文注册
583
- // ============================================================================
584
- register({
585
- name: "server",
586
- description: "http server",
587
- mounted(p) {
588
- return new Promise((resolve) => {
589
- server.listen({
590
- host: "0.0.0.0",
591
- port: port,
592
- }, () => {
593
- const address = server.address();
594
- if (!address)
595
- return;
596
- const visitAddress = typeof address === "string"
597
- ? address
598
- : `${address.address}:${address.port}`;
599
- p.logger.info(`server is running at http://${visitAddress}`);
600
- p.logger.info("your username is:", username);
601
- p.logger.info("your password is:", password);
602
- resolve(server);
603
- });
604
- });
605
- },
606
- dispose(s) {
607
- s.close();
608
- },
431
+ });
609
432
  });
610
- register({
433
+ // 注册 koa 和 router 上下文
434
+ provide({
611
435
  name: "koa",
612
436
  description: "koa instance",
613
437
  value: koa,
614
438
  });
615
- register({
439
+ provide({
616
440
  name: "router",
617
441
  description: "koa router",
618
442
  value: router,
619
443
  });
620
- koa.use(KoaBodyParser()).use(router.routes()).use(router.allowedMethods());
444
+ // 应用中间件
445
+ koa.use(body()).use(router.routes()).use(router.allowedMethods());
621
446
  //# sourceMappingURL=index.js.map