refactor: 重构 Onebot 配置格式,增强可读性

This commit is contained in:
SherkeyXD 2024-05-14 20:17:53 +08:00
parent 652bfb93cc
commit c82f346dd0
9 changed files with 259 additions and 230 deletions

View File

@ -1,63 +1,76 @@
import fs from 'node:fs'; import fs from "node:fs";
import path from 'node:path'; import path from "node:path";
import { selfInfo } from '@/core/data'; import { selfInfo } from "@/core/data";
import { logDebug, logError } from '@/common/utils/log'; import { logDebug, logError } from "@/common/utils/log";
import { ConfigBase } from '@/common/utils/ConfigBase'; import { ConfigBase } from "@/common/utils/ConfigBase";
import { json } from "stream/consumers";
export interface OB11Config { export interface OB11Config {
httpHost: string; http: {
httpPort: number; enable: boolean;
httpPostUrls: string[]; host: string;
httpSecret: string; port: number;
wsHost: string; secret: string;
wsPort: number; enableHeart: boolean;
wsReverseUrls: string[]; enablePost: boolean;
enableHttp: boolean; postUrls: string[];
enableHttpHeart: boolean; };
enableHttpPost: boolean; ws: {
enableWs: boolean; enable: boolean;
enableWsReverse: boolean; host: string;
messagePostFormat: 'array' | 'string'; port: number;
reportSelfMessage: boolean; };
enableLocalFile2Url: boolean; reverseWs: {
enable: boolean;
urls: string[];
};
debug: boolean; debug: boolean;
heartInterval: number; heartInterval: number;
token: string; messagePostFormat: "array" | "string";
enableLocalFile2Url: boolean;
musicSignUrl: string; musicSignUrl: string;
reportSelfMessage: boolean;
token: string;
read(): OB11Config; read(): OB11Config;
save(config: OB11Config): void; save(config: OB11Config): void;
} }
class Config extends ConfigBase<OB11Config> implements OB11Config { class Config extends ConfigBase<OB11Config> implements OB11Config {
httpHost: string = ''; http = {
httpPort: number = 3000; enable: false,
httpPostUrls: string[] = []; host: "",
httpSecret = ''; port: 3000,
wsHost: string = ''; secret: "",
wsPort = 3001; enableHeart: false,
wsReverseUrls: string[] = []; enablePost: false,
enableHttp = false; postUrls: [],
enableHttpPost = false; };
enableHttpHeart = false; ws = {
enableWs = false; enable: false,
enableWsReverse = false; host: "",
messagePostFormat: 'array' | 'string' = 'array'; port: 3001,
reportSelfMessage = false; };
reverseWs = {
enable: false,
urls: [],
};
debug = false; debug = false;
enableLocalFile2Url = true;
heartInterval = 30000; heartInterval = 30000;
token = ''; messagePostFormat: "array" | "string" = "array";
musicSignUrl = ''; enableLocalFile2Url = true;
musicSignUrl = "";
reportSelfMessage = false;
token = "";
getConfigPath() { getConfigPath() {
return path.join(this.getConfigDir(), `onebot11_${selfInfo.uin}.json`); return path.join(this.getConfigDir(), `onebot11_${selfInfo.uin}.json`);
} }
protected getKeys(): string[] { protected getKeys(): string[] | null {
return ['httpHost', 'enableHttp', 'httpPort', 'wsHost', 'enableWs', 'wsPort', 'enableWsReverse', 'wsReverseUrls', 'enableHttpPost', 'httpPostUrls', 'enableHttpHeart', 'httpSecret', 'messagePostFormat', 'reportSelfMessage', 'debug', 'enableLocalFile2Url', 'heartInterval', 'token', 'musicSignUrl']; return null;
} }
} }

View File

@ -43,26 +43,26 @@ export class NapCatOnebot11 {
logDebug('ob11 ready'); logDebug('ob11 ready');
ob11Config.read(); ob11Config.read();
const serviceInfo = ` const serviceInfo = `
HTTP服务 ${ob11Config.enableHttp ? '已启动' : '未启动'}, ${ob11Config.httpHost}:${ob11Config.httpPort} HTTP服务 ${ob11Config.http.enable ? '已启动' : '未启动'}, ${ob11Config.http.host}:${ob11Config.http.port}
HTTP上报服务 ${ob11Config.enableHttpPost ? '已启动' : '未启动'}, 上报地址: ${ob11Config.httpPostUrls} HTTP上报服务 ${ob11Config.http.enablePost ? '已启动' : '未启动'}, 上报地址: ${ob11Config.http.postUrls}
WebSocket服务 ${ob11Config.enableWs ? '已启动' : '未启动'}, ${ob11Config.wsHost}:${ob11Config.wsPort} WebSocket服务 ${ob11Config.ws.enable ? '已启动' : '未启动'}, ${ob11Config.ws.host}:${ob11Config.ws.port}
WebSocket反向服务 ${ob11Config.enableWsReverse ? '已启动' : '未启动'}, 反向地址: ${ob11Config.wsReverseUrls} WebSocket反向服务 ${ob11Config.reverseWs.enable ? '已启动' : '未启动'}, 反向地址: ${ob11Config.reverseWs.urls}
`; `;
log(serviceInfo); log(serviceInfo);
NTQQUserApi.getUserDetailInfo(selfInfo.uid).then(user => { NTQQUserApi.getUserDetailInfo(selfInfo.uid).then(user => {
selfInfo.nick = user.nick; selfInfo.nick = user.nick;
setLogSelfInfo(selfInfo); setLogSelfInfo(selfInfo);
}).catch(logError); }).catch(logError);
if (ob11Config.enableHttp) { if (ob11Config.http.enable) {
ob11HTTPServer.start(ob11Config.httpPort, ob11Config.httpHost); ob11HTTPServer.start(ob11Config.http.port, ob11Config.http.host);
} }
if (ob11Config.enableWs) { if (ob11Config.ws.enable) {
ob11WebsocketServer.start(ob11Config.wsPort, ob11Config.wsHost); ob11WebsocketServer.start(ob11Config.ws.port, ob11Config.ws.host);
} }
if (ob11Config.enableWsReverse) { if (ob11Config.reverseWs.enable) {
ob11ReverseWebsockets.start(); ob11ReverseWebsockets.start();
} }
if (ob11Config.enableHttpHeart) { if (ob11Config.http.enableHeart) {
// 启动http心跳 // 启动http心跳
httpHeart.start(); httpHeart.start();
} }
@ -209,48 +209,48 @@ export class NapCatOnebot11 {
// throw new Error('Invalid configuration object'); // throw new Error('Invalid configuration object');
// } // }
const isHttpChanged = !isEqual(NewOb11.httpPort, ob11Config.httpPort) && NewOb11.enableHttp; const isHttpChanged = !isEqual(NewOb11.http.port, ob11Config.http.port) && NewOb11.http.enable;
const isWsChanged = !isEqual(NewOb11.wsPort, ob11Config.wsPort); const isWsChanged = !isEqual(NewOb11.ws.port, ob11Config.ws.port);
const isEnableWsChanged = !isEqual(NewOb11.enableWs, ob11Config.enableWs); const isEnableWsChanged = !isEqual(NewOb11.ws.enable, ob11Config.ws.enable);
const isEnableWsReverseChanged = !isEqual(NewOb11.enableWsReverse, ob11Config.enableWsReverse); const isEnableWsReverseChanged = !isEqual(NewOb11.reverseWs.enable, ob11Config.reverseWs.enable);
const isWsReverseUrlsChanged = !isEqual(NewOb11.wsReverseUrls, ob11Config.wsReverseUrls); const isWsReverseUrlsChanged = !isEqual(NewOb11.reverseWs.urls, ob11Config.reverseWs.urls);
if (isHttpChanged) { if (isHttpChanged) {
ob11HTTPServer.restart(NewOb11.httpPort, NewOb11.httpHost); ob11HTTPServer.restart(NewOb11.http.port, NewOb11.http.host);
} }
if (!NewOb11.enableHttp) { if (!NewOb11.http.enable) {
ob11HTTPServer.stop(); ob11HTTPServer.stop();
} else { } else {
ob11HTTPServer.start(NewOb11.httpPort, NewOb11.httpHost); ob11HTTPServer.start(NewOb11.http.port, NewOb11.http.host);
} }
if (isWsChanged) { if (isWsChanged) {
ob11WebsocketServer.restart(NewOb11.wsPort); ob11WebsocketServer.restart(NewOb11.ws.port);
} }
if (isEnableWsChanged) { if (isEnableWsChanged) {
if (NewOb11.enableWs) { if (NewOb11.ws.enable) {
ob11WebsocketServer.start(NewOb11.wsPort, NewOb11.wsHost); ob11WebsocketServer.start(NewOb11.ws.port, NewOb11.ws.host);
} else { } else {
ob11WebsocketServer.stop(); ob11WebsocketServer.stop();
} }
} }
if (isEnableWsReverseChanged) { if (isEnableWsReverseChanged) {
if (NewOb11.enableWsReverse) { if (NewOb11.reverseWs.enable) {
ob11ReverseWebsockets.start(); ob11ReverseWebsockets.start();
} else { } else {
ob11ReverseWebsockets.stop(); ob11ReverseWebsockets.stop();
} }
} }
if (NewOb11.enableWsReverse && isWsReverseUrlsChanged) { if (NewOb11.reverseWs.enable && isWsReverseUrlsChanged) {
logDebug('反向ws地址有变化, 重启反向ws服务'); logDebug('反向ws地址有变化, 重启反向ws服务');
ob11ReverseWebsockets.restart(); ob11ReverseWebsockets.restart();
} }
if (NewOb11.enableHttpHeart) { if (NewOb11.http.enableHeart) {
httpHeart.start(); httpHeart.start();
} else if (!NewOb11.enableHttpHeart) { } else if (!NewOb11.http.enableHeart) {
httpHeart.stop(); httpHeart.stop();
} }
ob11Config.save(NewOb11); ob11Config.save(NewOb11);

View File

@ -1,21 +1,27 @@
{ {
"httpHost": "", "http": {
"enableHttp": false, "enable": false,
"httpPort": 3000, "host": "",
"wsHost": "", "port": 3000,
"enableWs": false, "secret": "",
"wsPort": 3001, "enableHeart": false,
"enableWsReverse": false, "enablePost": false,
"wsReverseUrls": [], "postUrls": []
"enableHttpPost": false, },
"httpPostUrls": [], "ws": {
"enableHttpHeart": false, "enable": false,
"httpSecret": "", "host": "",
"messagePostFormat": "array", "port": 3001
"reportSelfMessage": false, },
"reverseWs": {
"enable": false,
"urls": []
},
"debug": false, "debug": false,
"enableLocalFile2Url": true,
"heartInterval": 30000, "heartInterval": 30000,
"token": "", "messagePostFormat": "array",
"musicSignUrl": "" "enableLocalFile2Url": true,
} "musicSignUrl": "",
"reportSelfMessage": false,
"token": ""
}

View File

@ -16,7 +16,7 @@ class OB11HTTPServer extends HttpServerBase {
} }
protected listen(port: number, host: string) { protected listen(port: number, host: string) {
if (ob11Config.enableHttp) { if (ob11Config.http.enable) {
super.listen(port, host); super.listen(port, host);
} }
} }

View File

@ -78,19 +78,19 @@ export function postOB11Event(msg: PostEventType, reportSelf = false, postWs = t
return; return;
} }
} }
if (config.enableHttpPost) { if (config.http.enablePost) {
const msgStr = JSON.stringify(msg); const msgStr = JSON.stringify(msg);
const hmac = crypto.createHmac('sha1', ob11Config.httpSecret); const hmac = crypto.createHmac('sha1', ob11Config.http.secret);
hmac.update(msgStr); hmac.update(msgStr);
const sig = hmac.digest('hex'); const sig = hmac.digest('hex');
const headers: Record<string, string> = { const headers: Record<string, string> = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-self-id': selfInfo.uin 'x-self-id': selfInfo.uin
}; };
if (config.httpSecret) { if (config.http.secret) {
headers['x-signature'] = 'sha1=' + sig; headers['x-signature'] = 'sha1=' + sig;
} }
for (const host of config.httpPostUrls) { for (const host of config.http.postUrls) {
fetch(host, { fetch(host, {
method: 'POST', method: 'POST',
headers, headers,

View File

@ -116,7 +116,7 @@ export class ReverseWebsocket {
class OB11ReverseWebsockets { class OB11ReverseWebsockets {
start() { start() {
for (const url of ob11Config.wsReverseUrls) { for (const url of ob11Config.reverseWs.urls) {
log('开始连接反向ws', url); log('开始连接反向ws', url);
new Promise(() => { new Promise(() => {
try { try {

View File

@ -3,84 +3,88 @@ import { WebUiDataRuntime } from "../helper/Data";
import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { OB11Config } from "@/webui/ui/components/WebUiApiOB11Config"; import { OB11Config } from "@/webui/ui/components/WebUiApiOB11Config";
const isEmpty = (data: any) => data === undefined || data === null || data === ''; const isEmpty = (data: any) =>
data === undefined || data === null || data === "";
export const OB11GetConfigHandler: RequestHandler = async (req, res) => { export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
let isLogin = await WebUiDataRuntime.getQQLoginStatus(); let isLogin = await WebUiDataRuntime.getQQLoginStatus();
if (!isLogin) { if (!isLogin) {
res.send({
code: -1,
message: 'Not Login'
});
return;
}
const uin = await WebUiDataRuntime.getQQLoginUin();
let configFilePath = resolve(__dirname, `./config/onebot11_${uin}.json`);
//console.log(configFilePath);
let data: OB11Config;
try {
data = JSON.parse(existsSync(configFilePath) ? readFileSync(configFilePath).toString() : readFileSync(resolve(__dirname, `./config/onebot11.json`)).toString());
}
catch (e) {
data = {} as OB11Config;
res.send({
code: -1,
message: 'Config Get Error'
});
return;
}
res.send({ res.send({
code: 0, code: -1,
message: 'success', message: "Not Login",
data: data
}); });
return; return;
} }
export const OB11SetConfigHandler: RequestHandler = async (req, res) => { const uin = await WebUiDataRuntime.getQQLoginUin();
let isLogin = await WebUiDataRuntime.getQQLoginStatus(); let configFilePath = resolve(__dirname, `./config/onebot11_${uin}.json`);
if (!isLogin) { //console.log(configFilePath);
res.send({ let data: OB11Config;
code: -1, try {
message: 'Not Login' data = JSON.parse(
}); existsSync(configFilePath)
return; ? readFileSync(configFilePath).toString()
} : readFileSync(resolve(__dirname, `./config/onebot11.json`)).toString()
if (isEmpty(req.body.config)) { );
res.send({ } catch (e) {
code: -1, data = {} as OB11Config;
message: 'config is empty' res.send({
}); code: -1,
return; message: "Config Get Error",
} });
let SetResult;
try {
await WebUiDataRuntime.setOB11Config(JSON.parse(req.body.config));
SetResult = true;
} catch (e) {
SetResult = false;
}
// let configFilePath = resolve(__dirname, `./config/onebot11_${await WebUiDataRuntime.getQQLoginUin()}.json`);
// try {
// JSON.parse(req.body.config)
// readFileSync(configFilePath);
// }
// catch (e) {
// //console.log(e);
// configFilePath = resolve(__dirname, `./config/onebot11.json`);
// }
// //console.log(configFilePath,JSON.parse(req.body.config));
// writeFileSync(configFilePath, JSON.stringify(JSON.parse(req.body.config), null, 4));
if (SetResult) {
res.send({
code: 0,
message: 'success'
});
} else {
res.send({
code: -1,
message: 'Config Set Error'
});
}
return; return;
} }
res.send({
code: 0,
message: "success",
data: data,
});
return;
};
export const OB11SetConfigHandler: RequestHandler = async (req, res) => {
let isLogin = await WebUiDataRuntime.getQQLoginStatus();
if (!isLogin) {
res.send({
code: -1,
message: "Not Login",
});
return;
}
if (isEmpty(req.body.config)) {
res.send({
code: -1,
message: "config is empty",
});
return;
}
let SetResult;
try {
await WebUiDataRuntime.setOB11Config(JSON.parse(req.body.config));
SetResult = true;
} catch (e) {
SetResult = false;
}
// let configFilePath = resolve(__dirname, `./config/onebot11_${await WebUiDataRuntime.getQQLoginUin()}.json`);
// try {
// JSON.parse(req.body.config)
// readFileSync(configFilePath);
// }
// catch (e) {
// //console.log(e);
// configFilePath = resolve(__dirname, `./config/onebot11.json`);
// }
// //console.log(configFilePath,JSON.parse(req.body.config));
// writeFileSync(configFilePath, JSON.stringify(JSON.parse(req.body.config), null, 4));
if (SetResult) {
res.send({
code: 0,
message: "success",
});
} else {
res.send({
code: -1,
message: "Config Set Error",
});
}
return;
};

View File

@ -34,36 +34,36 @@ async function onSettingWindowCreated(view: Element) {
SettingItem( SettingItem(
'启用 HTTP 服务', '启用 HTTP 服务',
undefined, undefined,
SettingSwitch('ob11.enableHttp', ob11Config.enableHttp, { 'control-display-id': 'config-ob11-httpPort' }), SettingSwitch('ob11.http.enable', ob11Config.http.enable, { 'control-display-id': 'config-ob11-httpPort' }),
), ),
SettingItem( SettingItem(
'HTTP 服务监听端口', 'HTTP 服务监听端口',
undefined, undefined,
`<div class="q-input"><input class="q-input__inner" data-config-key="ob11.httpPort" type="number" min="1" max="65534" value="${ob11Config.httpPort}" placeholder="${ob11Config.httpPort}" /></div>`, `<div class="q-input"><input class="q-input__inner" data-config-key="ob11.httpPort" type="number" min="1" max="65534" value="${ob11Config.httpPort}" placeholder="${ob11Config.httpPort}" /></div>`,
'config-ob11-httpPort', 'config-ob11-httpPort',
ob11Config.enableHttp, ob11Config.http.enable,
), ),
SettingItem( SettingItem(
'启用 HTTP 心跳', '启用 HTTP 心跳',
undefined, undefined,
SettingSwitch('ob11.enableHttpHeart', ob11Config.enableHttpHeart, { SettingSwitch('ob11.http.enableHeart', ob11Config.http.enableHeart, {
'control-display-id': 'config-ob11-enableHttpHeart', 'control-display-id': 'config-ob11-enableHttpHeart',
}), }),
), ),
SettingItem( SettingItem(
'启用 HTTP 事件上报', '启用 HTTP 事件上报',
undefined, undefined,
SettingSwitch('ob11.enableHttpPost', ob11Config.enableHttpPost, { SettingSwitch('ob11.http.enablePost', ob11Config.http.enablePost, {
'control-display-id': 'config-ob11-httpPostUrls', 'control-display-id': 'config-ob11-httpPostUrls',
}), }),
), ),
`<div class="config-host-list" id="config-ob11-httpPostUrls" ${ob11Config.enableHttpPost ? '' : 'is-hidden'}> `<div class="config-host-list" id="config-ob11-httpPostUrls" ${ob11Config.http.enablePost ? '' : 'is-hidden'}>
<setting-item data-direction="row"> <setting-item data-direction="row">
<div> <div>
<setting-text>HTTP </setting-text> <setting-text>HTTP </setting-text>
</div> </div>
<div class="q-input"> <div class="q-input">
<input id="config-ob11-httpSecret" class="q-input__inner" data-config-key="ob11.httpSecret" type="text" value="${ob11Config.httpSecret <input id="config-ob11-httpSecret" class="q-input__inner" data-config-key="ob11.http.secret" type="text" value="${ob11Config.http.secret
}" placeholder="" /> }" placeholder="" />
</div> </div>
</setting-item> </setting-item>

View File

@ -1,64 +1,70 @@
export interface OB11Config { export interface OB11Config {
[key: string]: any, [key: string]: any;
httpHost: "", http: {
httpPort: number; enable: boolean;
httpPostUrls: string[]; host: "";
httpSecret: "", port: number;
wsHost: "", secret: "";
wsPort: number; enableHeart: boolean;
wsReverseUrls: string[]; enablePost: boolean;
enableHttp: boolean; postUrls: string[];
enableHttpHeart: boolean; };
enableHttpPost: boolean; ws: {
enableWs: boolean; enable: boolean;
enableWsReverse: boolean; host: "";
messagePostFormat: 'array' | 'string'; port: number;
reportSelfMessage: boolean; };
enableLocalFile2Url: boolean; reverseWs: {
debug: boolean; enable: boolean;
heartInterval: number; urls: string[];
token: "", };
musicSignUrl: "",
debug: boolean;
heartInterval: number;
messagePostFormat: "array" | "string";
enableLocalFile2Url: boolean;
musicSignUrl: "";
reportSelfMessage: boolean;
token: "";
} }
class WebUiApiOB11ConfigWrapper { class WebUiApiOB11ConfigWrapper {
private retCredential: string = ""; private retCredential: string = "";
async Init(Credential: string) { async Init(Credential: string) {
this.retCredential = Credential; this.retCredential = Credential;
}
async GetOB11Config(): Promise<OB11Config> {
let ConfigResponse = await fetch("/api/OB11Config/GetConfig", {
method: "POST",
headers: {
Authorization: "Bearer " + this.retCredential,
"Content-Type": "application/json",
},
});
if (ConfigResponse.status == 200) {
let ConfigResponseJson = await ConfigResponse.json();
if (ConfigResponseJson.code == 0) {
return ConfigResponseJson?.data;
}
} }
async GetOB11Config(): Promise<OB11Config> { return {} as OB11Config;
let ConfigResponse = await fetch('/api/OB11Config/GetConfig', { }
method: 'POST', async SetOB11Config(config: OB11Config): Promise<Boolean> {
headers: { let ConfigResponse = await fetch("/api/OB11Config/SetConfig", {
'Authorization': "Bearer " + this.retCredential, method: "POST",
'Content-Type': 'application/json' headers: {
} Authorization: "Bearer " + this.retCredential,
}); "Content-Type": "application/json",
if (ConfigResponse.status == 200) { },
let ConfigResponseJson = await ConfigResponse.json(); body: JSON.stringify({ config: JSON.stringify(config) }),
if (ConfigResponseJson.code == 0) { });
return ConfigResponseJson?.data; if (ConfigResponse.status == 200) {
} let ConfigResponseJson = await ConfigResponse.json();
} if (ConfigResponseJson.code == 0) {
return {} as OB11Config; return true;
} }
async SetOB11Config(config: OB11Config): Promise<Boolean> {
let ConfigResponse = await fetch('/api/OB11Config/SetConfig',
{
method: 'POST',
headers: {
'Authorization': "Bearer " + this.retCredential,
'Content-Type': 'application/json'
},
body: JSON.stringify({ config: JSON.stringify(config) })
}
);
if (ConfigResponse.status == 200) {
let ConfigResponseJson = await ConfigResponse.json();
if (ConfigResponseJson.code == 0) {
return true;
}
}
return false;
} }
return false;
}
} }
export const OB11ConfigWrapper = new WebUiApiOB11ConfigWrapper(); export const OB11ConfigWrapper = new WebUiApiOB11ConfigWrapper();