Skip to content

Commit

Permalink
fix: more systemInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-cn committed Sep 6, 2023
1 parent 6ed0946 commit 5186adb
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 261 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@types/node": "latest",
"@types/node-schedule": "^2.1.0",
"@types/ws": "^8.5.4",
"@zhinjs/adapter-onebot": "^0.0.16",
"dtsc": "^2.2.3",
"less": "^4.1.3",
"prettier": "^3.0.0",
Expand All @@ -71,7 +72,7 @@
},
"dependencies": {
"@koa/router": "^12.0.0",
"@zhinjs/schema": "^0.0.5",
"@zhinjs/schema": "^0.0.11",
"@zhinjs/shared": "^0.0.10",
"axios": "^1.3.3",
"chokidar": "^3.5.3",
Expand Down
30 changes: 9 additions & 21 deletions src/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Bot, BotConstruct, BotList, BotOptions } from "./bot";
import { Zhin } from "./zhin";
import { NSession, Session } from "./session";
import { Plugin } from "@/plugin";
import { Logger } from "log4js";
import { EventEmitter } from "events";
import { Dispose } from "./dispose";
import { Context } from "@/context";
import fs from "fs";
import path from "path";
import { Dict } from "@zhinjs/shared";

interface AdapterConstruct<
K extends keyof Zhin.Adapters = keyof Zhin.Adapters,
Expand Down Expand Up @@ -45,7 +45,6 @@ export abstract class Adapter<
this.bots = new BotList();
this.logger = zhin.getLogger(protocol);
this.zhin.on("start", () => this.start());
this.zhin.on("restart", () => this.saveStatus());
this.on("message.receive", (self_id: string | number, session: NSession<K>) => {
this.zhin.logger.info(
`【${this.protocol}:${self_id}】 ↓ ( ${session.message_id} )\t${session.content}`,
Expand Down Expand Up @@ -102,13 +101,10 @@ export abstract class Adapter<

botStatus(self_id: string | number) {
return (this.status[self_id] ||= {
last_restart_time: 0,
restart_times: 0,
msg_cnt_per_min: 0,
online: false,
recv_msg_cnt: 0,
sent_msg_cnt: 0,
start_time: 0,
});
}

Expand Down Expand Up @@ -141,12 +137,6 @@ export abstract class Adapter<
this.startBot(botOptions);
}
}
saveStatus() {
fs.writeFileSync(
path.join(this.zhin.options.data_dir, this.protocol, "status.json"),
JSON.stringify(this.status),
);
}

async stop(...args: any[]) {}

Expand All @@ -155,17 +145,18 @@ export abstract class Adapter<
if (!Construct)
throw new Error(`can not find bot constructor from protocol:${this.protocol}`);
const bot = new Construct(this.zhin, this as any, options);
const plugin = this.zhin.plugin("systemInfo") as unknown as Plugin;
let config = plugin.schema("plugins.systemInfo");
if (!config) config = (c => c) as any;
const status = config(this.zhin.options?.plugins?.systemInfo || {}) as Dict;
const currentBotStatus = status.bot_status?.[`${this.protocol}:${bot.self_id}`] || {};
this.status[bot.self_id] = {
last_restart_time: 0,
restart_times: 0,
msg_cnt_per_min: 0,
recv_msg_cnt: 0,
sent_msg_cnt: 0,
start_time: 0,
recv_msg_cnt: currentBotStatus.recv_msg_cnt || 0,
sent_msg_cnt: currentBotStatus.sent_msg_cnt || 0,
online: false,
};
bot.start();
this.botStatus(bot.self_id).start_time = Date.now();
this.bots.push(bot);
}
}
Expand All @@ -190,9 +181,6 @@ export namespace Adapter {
}

export interface BotStatus {
start_time: number;
last_restart_time: number;
restart_times: number;
recv_msg_cnt: number;
sent_msg_cnt: number;
msg_cnt_per_min: number;
Expand Down
34 changes: 31 additions & 3 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isBailed, remove, Dict } from "@zhinjs/shared";
import { isBailed, remove, Dict, getValue, deepClone, deepEqual } from "@zhinjs/shared";
import { Zhin, isConstructor, ChannelId } from "./zhin";
import { Dispose, ToDispose } from "./dispose";
import { Adapter, AdapterConstructs, AdapterOptions, AdapterOptionsType } from "./adapter";
Expand All @@ -11,6 +11,8 @@ import { Plugin, PluginMap } from "@/plugin";
import { Component, FunctionalComponent } from "./component";
import { Logger } from "log4js";
import { Bot } from "./bot";
import { Schema } from "@zhinjs/schema";
import { watch } from "obj-observer";

export class Context extends EventEmitter {
/**
Expand Down Expand Up @@ -316,6 +318,7 @@ export class Context extends EventEmitter {
if (this.zhin.isReady) await callback();
return this.zhin.on("before-ready", callback);
}

/**
* 在zhin就绪后执行回调函数,如果zhin已经就绪则立即执行
* @param callback 回调函数
Expand All @@ -324,6 +327,7 @@ export class Context extends EventEmitter {
if (this.zhin.isReady) await callback();
return this.zhin.on("after-ready", callback);
}

/**
* 在zhin启动前执行回调函数,如果zhin已经启动则立即执行
* @param callback 回调函数
Expand All @@ -332,6 +336,7 @@ export class Context extends EventEmitter {
if (this.zhin.isStarted) await callback();
return this.zhin.on("before-start", callback);
}

/**
* 在zhin启动后执行回调函数,如果zhin已经启动则立即执行
* @param callback 回调函数
Expand All @@ -340,6 +345,7 @@ export class Context extends EventEmitter {
if (this.zhin.isStarted) await callback();
return this.zhin.on("after-start", callback);
}

/**
* 为当前上下文添加插件
* @param plugin 插件安装配置对象
Expand Down Expand Up @@ -457,7 +463,7 @@ export class Context extends EventEmitter {
/**
* 为当前上下文添加指令
* @param decl 指令声明
* @param config {import('zhin').Command} 指令配置
* @param config {import("zhin").Command} 指令配置
*/
command<S extends Command.Declare>(
decl: S,
Expand All @@ -467,7 +473,7 @@ export class Context extends EventEmitter {
* 为当前上下文添加指令
* @param decl 指令声明
* @param initialValue 指令初始值
* @param config {import('zhin').Command} 指令配置
* @param config {import("zhin").Command} 指令配置
*/
command<S extends Command.Declare>(
decl: S,
Expand Down Expand Up @@ -734,6 +740,7 @@ export class Context extends EventEmitter {
await listener.apply(this, args);
}
}

/**
* 执行某一event的所有listener,并获取其返回值
* @param event 事件名
Expand Down Expand Up @@ -761,6 +768,27 @@ export class Context extends EventEmitter {
if (isBailed(result)) return result;
}
}
useOptions<T>(path: string): T;
/**
* 获取当前上下文的插件配置信息
* @param path
* @param schema 插件配置信息
*/
useOptions<S, T>(path: string, schema: Schema<S, T>): T;
useOptions(path: string, schema?: Schema) {
const config = this[Context.plugin]?.schema(path, schema);
if (!config) throw new Error(`找不到插件配置:${path}`);
const result = getValue(this.zhin.options, path);
const backupData = deepClone(result);
const unwatch = watch(this.zhin.options, value => {
const newVal = getValue(value, path);
if (!deepEqual(backupData, newVal)) {
this[Context.plugin].reLoad();
}
});
this.disposes.push(unwatch);
return config(result);
}

/**
* 销毁指定上下文,如不传入插件,则销毁当前上下文,若传入插件,则销毁指定插件的上下文
Expand Down
23 changes: 0 additions & 23 deletions src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,6 @@ export function createZhinAPI() {
context.useCommand(name, command);
};

// 读取指定path的配置文件
function useOptions<K extends Keys<Zhin.Options>>(
path: K,
zhinKey = Zhin.key,
): Value<Zhin.Options, K> {
const zhin = zhinMap.get(zhinKey);
if (!zhin) throw new Error(`can't found zhin with context for key:${zhinKey.toString()}`);
const callSite = getCaller();
const pluginFullPath = callSite.getFileName();
const plugin = zhin.pluginList.find(plugin => plugin.options.fullPath === pluginFullPath);
const result = getValue(zhin.options, path);
const backupData = deepClone(result);
const unwatch = watch(zhin.options, value => {
const newVal = getValue(value, path);
if (!deepEqual(backupData, newVal)) {
plugin.reLoad();
}
});
plugin.context.disposes.push(unwatch);
return getValue(zhin.options, path);
}

type EffectReturn = () => void;
type EffectCallBack<T = any> = (value?: T, oldValue?: T) => void | EffectReturn;

Expand Down Expand Up @@ -195,6 +173,5 @@ export function createZhinAPI() {
useCommand,
useComponent,
onDispose,
useOptions,
};
}
7 changes: 5 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Dict, getPackageInfo, remove } from "@zhinjs/shared";
import { Schema } from "@zhinjs/schema";
import { Dispose } from "@/dispose";
import { Context } from "@/context";
import { Zhin } from "@/zhin";
Expand Down Expand Up @@ -44,7 +45,7 @@ export class Plugin {
public status: boolean;
public dependencies: string[] = [];
public disableBots: `${keyof Zhin.Adapters}:${string | number}`[] = [];

schemaMap: Dict<Schema> = {};
constructor(
public options: Plugin.Options,
public info: Plugin.Info,
Expand All @@ -70,7 +71,9 @@ export class Plugin {
this.options.scopes.includes(session.protocol))
);
}

schema<S, T>(path: string, schema?: Schema<S, T>): Schema<S, T> {
return (this.schemaMap[path] ||= schema);
}
// 根据指定配置挂载插件
mount(ctx: Context) {
this.context = ctx;
Expand Down
22 changes: 11 additions & 11 deletions src/plugins/daemon.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { useContext, Schema, useOptions, Bot, Zhin, NSession } from "@";
import { useContext, Schema, Bot, Zhin, NSession } from "@";
import { promisify } from "util";
import { exec } from "child_process";

export const name = "systemDaemon";
const ctx = useContext();
const config = useOptions("plugins.daemon");
const Config = Schema.object({
exitCommand: Schema.union([
Schema.boolean().default(true).description("是否添加退出指令"),
Schema.string().default("添加的指令"),
]),
autoRestart: Schema.boolean().default(true).description("是否自动重启"),
});
const { exitCommand = true, autoRestart = true } = Config(config);
const { exitCommand = true, autoRestart = true } = ctx.useOptions(
"plugins.daemon",
Schema.object({
exitCommand: Schema.union([
Schema.boolean().default(true).description("是否添加退出指令"),
Schema.string().default("添加的指令"),
]),
autoRestart: Schema.boolean().default(true).description("是否自动重启"),
}),
);

function handleSignal(signal: NodeJS.Signals) {
ctx.zhin.logger.info(`terminated by ${signal}`);
Expand Down
1 change: 0 additions & 1 deletion src/plugins/help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NSession, useContext, Zhin } from "@";

export const name = "systemHelper";
const ctx = useContext();
ctx.command("help [command:string]")
.desc("查看某个指令的帮助文档")
Expand Down
58 changes: 52 additions & 6 deletions src/plugins/systemInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,59 @@ const copyFileSync = promisify(copyFile);
const writeFileSync = promisify(writeFile);
import * as readline from "readline";
import { arch, cpus, freemem, totalmem, type } from "os";
import { NSession, Time, useContext, Zhin } from "@";
import { Adapter, NSession, onDispose, Time, useContext, Zhin } from "@";
import { version, h } from "@";
import { Schema } from "@zhinjs/schema";
import { deepClone, getValue, setValue } from "@zhinjs/shared";

export const name = "systemInfo";
const ctx = useContext();

const logFile = PathResolve(dirname(ctx.zhin.options.data_dir), "logs.log");
onDispose(
ctx.zhin.on("restart", () => {
const newOptions = deepClone(ctx.zhin.options);
const oldStatus = getValue(newOptions, `plugins.systemInfo`) || {};
setValue(newOptions, `plugins.systemInfo`, {
start_time: oldStatus.start_time || Date.now(),
restart_times: oldStatus.restart_times === undefined ? 0 : oldStatus.restart_times + 1,
last_restart_time: Date.now(),
bot_status: Object.fromEntries(
[...ctx.zhin.adapters.values()].reduce((result, adapter: Adapter) => {
result.push(
...adapter.bots.map(bot => {
return [`${adapter.protocol}:${bot.self_id}`, bot.status];
}),
);
return result;
}, []),
),
});
ctx.zhin.changeOptions(newOptions);
}),
);
const config = ctx.useOptions(
"plugins.systemInfo",
Schema.object({
start_time: Schema.number().default(0),
last_restart_time: Schema.number().default(0),
restart_times: Schema.number().default(0),
bot_status: Schema.dict(
Schema.object({
sent_msg_cnt: Schema.number().default(0),
recv_msg_cnt: Schema.number().default(0),
}).default({
sent_msg_cnt: 0,
recv_msg_cnt: 0,
}),
),
}).default({
start_time: new Date().getTime(),
last_restart_time: 0,
restart_times: 0,
bot_status: {},
}),
);

function readLogs(): Promise<string[]> {
return new Promise<string[]>(resolve => {
Expand Down Expand Up @@ -75,7 +121,6 @@ ctx.command("status")
}
return (+bytes.toFixed(0) === bytes ? bytes : bytes.toFixed(2)) + operators[0];
}

const memoryUsage = process.memoryUsage();
const totalMem = totalmem();
const usedMem = totalMem - freemem();
Expand All @@ -91,13 +136,14 @@ ctx.command("status")
`进程内存占比:${((memoryUsage.rss / usedMem) * 100).toFixed(2)}%(${format(
memoryUsage.rss,
)}/${format(usedMem)})`,
`持续运行时间:${Time.formatTime(
new Date().getTime() - session.bot.status.start_time,
)}`,
`掉线次数:${session.bot.status.lost_times}次`,
`持续运行时间:${Time.formatTime(new Date().getTime() - config.start_time)}`,
`发送消息数:${session.bot.status.sent_msg_cnt}条`,
`接收消息数:${session.bot.status.recv_msg_cnt}条`,
`消息频率:${session.bot.status.msg_cnt_per_min}条/分`,
`重启次数:${config.restart_times}次`,
`上次重启时间:${
config.last_restart_time ? Time.format(config.last_restart_time) : "无"
}`,
].join("\n");
});

Expand Down
Loading

0 comments on commit 5186adb

Please sign in to comment.