mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
refactor: base server & setting ui
This commit is contained in:
parent
5094ba724a
commit
c1dd309b21
@ -5,7 +5,7 @@
|
|||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"postinstall": "set ELECTRON_SKIP_BINARY_DOWNLOAD=1 && npm install electron --no-save",
|
"postinstall": "ELECTRON_SKIP_BINARY_DOWNLOAD=1 && npm install electron --no-save",
|
||||||
"build": "npm run build-main && npm run build-preload && npm run build-renderer",
|
"build": "npm run build-main && npm run build-preload && npm run build-renderer",
|
||||||
"build-main": "webpack --config webpack.main.config.js",
|
"build-main": "webpack --config webpack.main.config.js",
|
||||||
"build-preload": "webpack --config webpack.preload.config.js",
|
"build-preload": "webpack --config webpack.preload.config.js",
|
||||||
@ -19,7 +19,6 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-ws": "^5.0.2",
|
|
||||||
"json-bigint": "^1.0.0",
|
"json-bigint": "^1.0.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {Config} from "./types";
|
import {Config, OB11Config} from "./types";
|
||||||
|
import {mergeNewProperties} from "./utils";
|
||||||
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
@ -8,13 +9,25 @@ export class ConfigUtil {
|
|||||||
constructor(configPath: string) {
|
constructor(configPath: string) {
|
||||||
this.configPath = configPath;
|
this.configPath = configPath;
|
||||||
}
|
}
|
||||||
|
getConfig(){
|
||||||
getConfig(): Config {
|
try {
|
||||||
let defaultConfig: Config = {
|
return this._getConfig()
|
||||||
|
}catch (e) {
|
||||||
|
console.log("获取配置文件出错", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_getConfig(): Config {
|
||||||
|
let ob11Default: OB11Config = {
|
||||||
httpPort: 3000,
|
httpPort: 3000,
|
||||||
httpHosts: [],
|
httpHosts: [],
|
||||||
wsPort: 3001,
|
wsPort: 3001,
|
||||||
wsHosts: [],
|
wsHosts: [],
|
||||||
|
enableWs: true,
|
||||||
|
enableWsReverse: true
|
||||||
|
}
|
||||||
|
let defaultConfig: Config = {
|
||||||
|
ob11: ob11Default,
|
||||||
|
heartInterval: 5000,
|
||||||
token: "",
|
token: "",
|
||||||
enableBase64: false,
|
enableBase64: false,
|
||||||
debug: false,
|
debug: false,
|
||||||
@ -28,28 +41,29 @@ export class ConfigUtil {
|
|||||||
let jsonData: Config = defaultConfig;
|
let jsonData: Config = defaultConfig;
|
||||||
try {
|
try {
|
||||||
jsonData = JSON.parse(data)
|
jsonData = JSON.parse(data)
|
||||||
|
} catch (e) {
|
||||||
}
|
}
|
||||||
catch (e) {}
|
mergeNewProperties(defaultConfig, jsonData);
|
||||||
if (!jsonData.httpHosts) {
|
this.checkOldConfig(jsonData.ob11, jsonData, "httpPort", "port");
|
||||||
jsonData.httpHosts = []
|
this.checkOldConfig(jsonData.ob11, jsonData, "httpHosts", "hosts");
|
||||||
}
|
this.checkOldConfig(jsonData.ob11, jsonData, "wsPort", "wsPort");
|
||||||
if (!jsonData.wsHosts) {
|
console.log("get config", jsonData);
|
||||||
jsonData.wsHosts = []
|
|
||||||
}
|
|
||||||
if (!jsonData.wsPort) {
|
|
||||||
jsonData.wsPort = 3001
|
|
||||||
}
|
|
||||||
if (!jsonData.httpPort) {
|
|
||||||
jsonData.httpPort = 3000
|
|
||||||
}
|
|
||||||
if (!jsonData.token) {
|
|
||||||
jsonData.token = ""
|
|
||||||
}
|
|
||||||
return jsonData;
|
return jsonData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfig(config: Config) {
|
setConfig(config: Config) {
|
||||||
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8")
|
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), "utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkOldConfig(currentConfig: Config | OB11Config,
|
||||||
|
oldConfig: Config | OB11Config,
|
||||||
|
currentKey: string, oldKey: string) {
|
||||||
|
// 迁移旧的配置到新配置,避免用户重新填写配置
|
||||||
|
const oldValue = oldConfig[oldKey];
|
||||||
|
if (oldValue) {
|
||||||
|
currentConfig[currentKey] = oldValue;
|
||||||
|
delete oldConfig[oldKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,4 +88,3 @@ export function getStrangerByUin(uin: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const version = "v3.4.0"
|
export const version = "v3.4.0"
|
||||||
export const heartInterval = 15000 // 毫秒
|
|
@ -1,4 +1,4 @@
|
|||||||
export interface Config {
|
export interface OB11Config {
|
||||||
httpPort: number
|
httpPort: number
|
||||||
httpHosts: string[]
|
httpHosts: string[]
|
||||||
wsPort: number
|
wsPort: number
|
||||||
@ -7,7 +7,12 @@ export interface Config {
|
|||||||
enableHttpPost?: boolean
|
enableHttpPost?: boolean
|
||||||
enableWs?: boolean
|
enableWs?: boolean
|
||||||
enableWsReverse?: boolean
|
enableWsReverse?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
ob11: OB11Config
|
||||||
token?: string
|
token?: string
|
||||||
|
heartInterval?: number // ms
|
||||||
enableBase64?: boolean
|
enableBase64?: boolean
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
reportSelfMessage?: boolean
|
reportSelfMessage?: boolean
|
||||||
|
@ -97,3 +97,22 @@ export async function file2base64(path: string){
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 在保证老对象已有的属性不变化的情况下将新对象的属性复制到老对象
|
||||||
|
export function mergeNewProperties(newObj: any, oldObj: any) {
|
||||||
|
Object.keys(newObj).forEach(key => {
|
||||||
|
// 如果老对象不存在当前属性,则直接复制
|
||||||
|
if (!oldObj.hasOwnProperty(key)) {
|
||||||
|
oldObj[key] = newObj[key];
|
||||||
|
} else {
|
||||||
|
// 如果老对象和新对象的当前属性都是对象,则递归合并
|
||||||
|
if (typeof oldObj[key] === 'object' && typeof newObj[key] === 'object') {
|
||||||
|
mergeNewProperties(newObj[key], oldObj[key]);
|
||||||
|
} else if(typeof oldObj[key] === 'object' || typeof newObj[key] === 'object'){
|
||||||
|
// 属性冲突,有一方不是对象,直接覆盖
|
||||||
|
oldObj[key] = newObj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
import {BrowserWindow, ipcMain} from 'electron';
|
import {BrowserWindow, ipcMain} from 'electron';
|
||||||
|
|
||||||
import {Config} from "../common/types";
|
import {Config} from "../common/types";
|
||||||
import {postMsg, setToken, startHTTPServer, initWebsocket} from "../onebot11/server";
|
import {postMsg, initWebsocket} from "../onebot11/server";
|
||||||
import {CHANNEL_GET_CONFIG, CHANNEL_LOG, CHANNEL_SET_CONFIG,} from "../common/channels";
|
import {CHANNEL_GET_CONFIG, CHANNEL_LOG, CHANNEL_SET_CONFIG,} from "../common/channels";
|
||||||
import {CONFIG_DIR, getConfigUtil, log} from "../common/utils";
|
import {CONFIG_DIR, getConfigUtil, log} from "../common/utils";
|
||||||
import {addHistoryMsg, getGroupMember, msgHistory, selfInfo} from "../common/data";
|
import {addHistoryMsg, getGroupMember, msgHistory, selfInfo} from "../common/data";
|
||||||
@ -13,6 +13,7 @@ import {NTQQApi} from "../ntqqapi/ntcall";
|
|||||||
import {ChatType, RawMessage} from "../ntqqapi/types";
|
import {ChatType, RawMessage} from "../ntqqapi/types";
|
||||||
import {OB11FriendRecallNoticeEvent} from "../onebot11/event/notice/OB11FriendRecallNoticeEvent";
|
import {OB11FriendRecallNoticeEvent} from "../onebot11/event/notice/OB11FriendRecallNoticeEvent";
|
||||||
import {OB11GroupRecallNoticeEvent} from "../onebot11/event/notice/OB11GroupRecallNoticeEvent";
|
import {OB11GroupRecallNoticeEvent} from "../onebot11/event/notice/OB11GroupRecallNoticeEvent";
|
||||||
|
import {ob11HTTPServer} from "../onebot11/server/http";
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
@ -29,19 +30,26 @@ function onLoad() {
|
|||||||
fs.mkdirSync(CONFIG_DIR, {recursive: true});
|
fs.mkdirSync(CONFIG_DIR, {recursive: true});
|
||||||
}
|
}
|
||||||
ipcMain.handle(CHANNEL_GET_CONFIG, (event: any, arg: any) => {
|
ipcMain.handle(CHANNEL_GET_CONFIG, (event: any, arg: any) => {
|
||||||
return getConfigUtil().getConfig();
|
try {
|
||||||
|
return getConfigUtil().getConfig();
|
||||||
|
}catch (e) {
|
||||||
|
console.log("获取配置文件出错", e)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
ipcMain.on(CHANNEL_SET_CONFIG, (event: any, arg: Config) => {
|
ipcMain.on(CHANNEL_SET_CONFIG, (event: any, arg: Config) => {
|
||||||
let oldConfig = getConfigUtil().getConfig();
|
let oldConfig = getConfigUtil().getConfig();
|
||||||
getConfigUtil().setConfig(arg)
|
getConfigUtil().setConfig(arg)
|
||||||
if (arg.httpPort != oldConfig.httpPort) {
|
if (arg.ob11.httpPort != oldConfig.ob11.httpPort && arg.ob11.enableHttp) {
|
||||||
startHTTPServer(arg.httpPort)
|
ob11HTTPServer.restart(arg.ob11.httpPort);
|
||||||
}
|
}
|
||||||
if (arg.wsPort != oldConfig.wsPort) {
|
if (!arg.ob11.enableHttp){
|
||||||
initWebsocket(arg.wsPort)
|
ob11HTTPServer.stop()
|
||||||
}
|
}
|
||||||
if (arg.token != oldConfig.token) {
|
else{
|
||||||
setToken(arg.token);
|
ob11HTTPServer.start(arg.ob11.httpPort);
|
||||||
|
}
|
||||||
|
if (arg.ob11.wsPort != oldConfig.ob11.wsPort) {
|
||||||
|
initWebsocket(arg.ob11.wsPort)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -125,11 +133,13 @@ function onLoad() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
NTQQApi.getGroups(true).then()
|
NTQQApi.getGroups(true).then()
|
||||||
|
|
||||||
const config = getConfigUtil().getConfig()
|
const config = getConfigUtil().getConfig()
|
||||||
startHTTPServer(config.httpPort)
|
try {
|
||||||
initWebsocket(config.wsPort);
|
ob11HTTPServer.start(config.ob11.httpPort)
|
||||||
setToken(config.token)
|
initWebsocket(config.ob11.wsPort);
|
||||||
|
}catch (e) {
|
||||||
|
console.log("start failed", e)
|
||||||
|
}
|
||||||
log("LLOneBot start")
|
log("LLOneBot start")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,41 @@ import BaseAction from "./BaseAction";
|
|||||||
import {ActionName} from "./types";
|
import {ActionName} from "./types";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
||||||
|
function checkUri(uri: string): boolean {
|
||||||
|
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/;
|
||||||
|
return pattern.test(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let msg of sendMsgList) {
|
||||||
|
if (msg["type"] && msg["data"]) {
|
||||||
|
let type = msg["type"];
|
||||||
|
let data = msg["data"];
|
||||||
|
if (type === "text" && !data["text"]) {
|
||||||
|
return 400;
|
||||||
|
} else if (["image", "voice", "record"].includes(type)) {
|
||||||
|
if (!data["file"]) {
|
||||||
|
return 400;
|
||||||
|
} else {
|
||||||
|
if (checkUri(data["file"])) {
|
||||||
|
return 200;
|
||||||
|
} else {
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (type === "at" && !data["qq"]) {
|
||||||
|
return 400;
|
||||||
|
} else if (type === "reply" && !data["id"]) {
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ReturnDataType {
|
export interface ReturnDataType {
|
||||||
message_id: number
|
message_id: number
|
||||||
}
|
}
|
@ -7,7 +7,6 @@ export class OB11GroupRecallNoticeEvent extends OB11GroupNoticeEvent {
|
|||||||
|
|
||||||
constructor(groupId: number, userId: number, operatorId: number, messageId: number) {
|
constructor(groupId: number, userId: number, operatorId: number, messageId: number) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.group_id = groupId;
|
this.group_id = groupId;
|
||||||
this.user_id = userId;
|
this.user_id = userId;
|
||||||
this.operator_id = operatorId;
|
this.operator_id = operatorId;
|
||||||
|
@ -1,134 +1,24 @@
|
|||||||
import * as http from "http";
|
|
||||||
import * as websocket from "ws";
|
import * as websocket from "ws";
|
||||||
import urlParse from "url";
|
import urlParse from "url";
|
||||||
import express, {Request, Response} from "express";
|
|
||||||
import {getConfigUtil, log} from "../common/utils";
|
import {getConfigUtil, log} from "../common/utils";
|
||||||
import {heartInterval, selfInfo} from "../common/data";
|
import {selfInfo} from "../common/data";
|
||||||
import {OB11Message, OB11MessageData, OB11Return} from './types';
|
import {OB11Message} from './types';
|
||||||
import {actionHandlers, actionMap} from "./actions";
|
import {actionMap} from "./action";
|
||||||
import {OB11Response, OB11WebsocketResponse} from "./actions/utils";
|
import {OB11WebsocketResponse} from "./action/utils";
|
||||||
import {callEvent, registerEventSender, unregisterEventSender} from "./event/manager";
|
import {callEvent, registerEventSender, unregisterEventSender} from "./event/manager";
|
||||||
import {ReconnectingWebsocket} from "./ReconnectingWebsocket";
|
import {ReconnectingWebsocket} from "./ReconnectingWebsocket";
|
||||||
import {ActionName} from "./actions/types";
|
import {ActionName} from "./action/types";
|
||||||
import {OB11BaseMetaEvent} from "./event/meta/OB11BaseMetaEvent";
|
import {OB11BaseMetaEvent} from "./event/meta/OB11BaseMetaEvent";
|
||||||
import {OB11BaseNoticeEvent} from "./event/notice/OB11BaseNoticeEvent";
|
import {OB11BaseNoticeEvent} from "./event/notice/OB11BaseNoticeEvent";
|
||||||
import BaseAction from "./actions/BaseAction";
|
import BaseAction from "./action/BaseAction";
|
||||||
import {LifeCycleSubType, OB11LifeCycleEvent} from "./event/meta/OB11LifeCycleEvent";
|
import {LifeCycleSubType, OB11LifeCycleEvent} from "./event/meta/OB11LifeCycleEvent";
|
||||||
import {OB11HeartbeatEvent} from "./event/meta/OB11HeartbeatEvent";
|
import {OB11HeartbeatEvent} from "./event/meta/OB11HeartbeatEvent";
|
||||||
|
|
||||||
let accessToken = "";
|
|
||||||
let heartbeatRunning = false;
|
let heartbeatRunning = false;
|
||||||
|
|
||||||
// @SiberianHusky 2021-08-15
|
|
||||||
|
|
||||||
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
|
||||||
function checkUri(uri: string): boolean {
|
|
||||||
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/;
|
|
||||||
return pattern.test(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let msg of sendMsgList) {
|
|
||||||
if (msg["type"] && msg["data"]) {
|
|
||||||
let type = msg["type"];
|
|
||||||
let data = msg["data"];
|
|
||||||
if (type === "text" && !data["text"]) {
|
|
||||||
return 400;
|
|
||||||
} else if (["image", "voice", "record"].includes(type)) {
|
|
||||||
if (!data["file"]) {
|
|
||||||
return 400;
|
|
||||||
} else {
|
|
||||||
if (checkUri(data["file"])) {
|
|
||||||
return 200;
|
|
||||||
} else {
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (type === "at" && !data["qq"]) {
|
|
||||||
return 400;
|
|
||||||
} else if (type === "reply" && !data["id"]) {
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 400
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==end==
|
|
||||||
|
|
||||||
const JSONbig = require('json-bigint')({storeAsString: true});
|
|
||||||
|
|
||||||
const expressAPP = express();
|
|
||||||
expressAPP.use(express.urlencoded({extended: true, limit: "500mb"}));
|
|
||||||
|
|
||||||
let httpServer: http.Server = null;
|
|
||||||
|
|
||||||
let websocketServer = null;
|
let websocketServer = null;
|
||||||
|
|
||||||
expressAPP.use((req, res, next) => {
|
|
||||||
let data = '';
|
|
||||||
req.on('data', chunk => {
|
|
||||||
data += chunk.toString();
|
|
||||||
});
|
|
||||||
req.on('end', () => {
|
|
||||||
if (data) {
|
|
||||||
try {
|
|
||||||
// log("receive raw", data)
|
|
||||||
req.body = JSONbig.parse(data);
|
|
||||||
} catch (e) {
|
|
||||||
return next(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const expressAuthorize = (req: Request, res: Response, next: () => void) => {
|
|
||||||
let token = ""
|
|
||||||
const authHeader = req.get("authorization")
|
|
||||||
if (authHeader) {
|
|
||||||
token = authHeader.split("Bearer ").pop()
|
|
||||||
log("receive http header token", token)
|
|
||||||
} else if (req.query.access_token) {
|
|
||||||
if (Array.isArray(req.query.access_token)) {
|
|
||||||
token = req.query.access_token[0].toString();
|
|
||||||
} else {
|
|
||||||
token = req.query.access_token.toString();
|
|
||||||
}
|
|
||||||
log("receive http url token", token)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
if (token != accessToken) {
|
|
||||||
return res.status(403).send(JSON.stringify({message: 'token verify failed!'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export function setToken(token: string) {
|
|
||||||
accessToken = token
|
|
||||||
}
|
|
||||||
|
|
||||||
export function startHTTPServer(port: number) {
|
|
||||||
if (httpServer) {
|
|
||||||
httpServer.close();
|
|
||||||
}
|
|
||||||
expressAPP.get('/', (req: Request, res: Response) => {
|
|
||||||
res.send('LLOneBot已启动');
|
|
||||||
})
|
|
||||||
|
|
||||||
if (getConfigUtil().getConfig().enableHttp) {
|
|
||||||
httpServer = expressAPP.listen(port, "0.0.0.0", () => {
|
|
||||||
console.log(`llonebot http service started 0.0.0.0:${port}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initWebsocket(port: number) {
|
export function initWebsocket(port: number) {
|
||||||
|
const {heartInterval, ob11: {enableWs}, token} = getConfigUtil().getConfig()
|
||||||
if (!heartbeatRunning) {
|
if (!heartbeatRunning) {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
callEvent(new OB11HeartbeatEvent(true, true, heartInterval));
|
callEvent(new OB11HeartbeatEvent(true, true, heartInterval));
|
||||||
@ -136,8 +26,7 @@ export function initWebsocket(port: number) {
|
|||||||
|
|
||||||
heartbeatRunning = true;
|
heartbeatRunning = true;
|
||||||
}
|
}
|
||||||
|
if (enableWs) {
|
||||||
if (getConfigUtil().getConfig().enableWs) {
|
|
||||||
if (websocketServer) {
|
if (websocketServer) {
|
||||||
websocketServer.close((err) => {
|
websocketServer.close((err) => {
|
||||||
log("ws server close failed!", err)
|
log("ws server close failed!", err)
|
||||||
@ -150,28 +39,26 @@ export function initWebsocket(port: number) {
|
|||||||
websocketServer.on("connection", (ws, req) => {
|
websocketServer.on("connection", (ws, req) => {
|
||||||
const url = req.url.split("?").shift();
|
const url = req.url.split("?").shift();
|
||||||
log("receive ws connect", url)
|
log("receive ws connect", url)
|
||||||
let token: string = ""
|
let clientToken: string = ""
|
||||||
const authHeader = req.headers['authorization'];
|
const authHeader = req.headers['authorization'];
|
||||||
if (authHeader) {
|
if (authHeader) {
|
||||||
token = authHeader.split("Bearer ").pop()
|
clientToken = authHeader.split("Bearer ").pop()
|
||||||
log("receive ws header token", token);
|
log("receive ws header token", clientToken);
|
||||||
} else {
|
} else {
|
||||||
const parsedUrl = urlParse.parse(req.url, true);
|
const parsedUrl = urlParse.parse(req.url, true);
|
||||||
const urlToken = parsedUrl.query.access_token;
|
const urlToken = parsedUrl.query.access_token;
|
||||||
if (urlToken) {
|
if (urlToken) {
|
||||||
if (Array.isArray(urlToken)) {
|
if (Array.isArray(urlToken)) {
|
||||||
token = urlToken[0]
|
clientToken = urlToken[0]
|
||||||
} else {
|
} else {
|
||||||
token = urlToken
|
clientToken = urlToken
|
||||||
}
|
}
|
||||||
log("receive ws url token", token);
|
log("receive ws url token", clientToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (accessToken) {
|
if (token && clientToken != token) {
|
||||||
if (token != accessToken) {
|
ws.send(JSON.stringify(OB11WebsocketResponse.res(null, "failed", 1403, "token验证失败")))
|
||||||
ws.send(JSON.stringify(OB11WebsocketResponse.res(null, "failed", 1403, "token验证失败")))
|
return ws.close()
|
||||||
return ws.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url == "/api" || url == "/api/" || url == "/") {
|
if (url == "/api" || url == "/api/" || url == "/") {
|
||||||
@ -204,7 +91,7 @@ export function initWebsocket(port: number) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
wsReply(ws, new OB11LifeCycleEvent(LifeCycleSubType.CONNECT))
|
wsReply(ws, new OB11LifeCycleEvent(LifeCycleSubType.CONNECT))
|
||||||
} catch (e){
|
} catch (e) {
|
||||||
log("发送生命周期失败", e)
|
log("发送生命周期失败", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,11 +105,12 @@ export function initWebsocket(port: number) {
|
|||||||
|
|
||||||
initReverseWebsocket();
|
initReverseWebsocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initReverseWebsocket() {
|
function initReverseWebsocket() {
|
||||||
const config = getConfigUtil().getConfig();
|
const config = getConfigUtil().getConfig();
|
||||||
if (config.enableWsReverse) {
|
if (config.ob11.enableWsReverse) {
|
||||||
console.log("Prepare to connect all reverse websockets...");
|
console.log("Prepare to connect all reverse websockets...");
|
||||||
for (const url of config.wsHosts) {
|
for (const url of config.ob11.wsHosts) {
|
||||||
new Promise(() => {
|
new Promise(() => {
|
||||||
try {
|
try {
|
||||||
let wsClient = new ReconnectingWebsocket(url);
|
let wsClient = new ReconnectingWebsocket(url);
|
||||||
@ -239,7 +127,7 @@ function initReverseWebsocket() {
|
|||||||
wsClient.onmessage = async function (msg) {
|
wsClient.onmessage = async function (msg) {
|
||||||
let receiveData: { action: ActionName, params: any, echo?: string } = {action: null, params: {}}
|
let receiveData: { action: ActionName, params: any, echo?: string } = {action: null, params: {}}
|
||||||
let echo = ""
|
let echo = ""
|
||||||
log("收到正向Websocket消息", msg.toString())
|
log("收到反向Websocket消息", msg.toString())
|
||||||
try {
|
try {
|
||||||
receiveData = JSON.parse(msg.toString())
|
receiveData = JSON.parse(msg.toString())
|
||||||
echo = receiveData.echo
|
echo = receiveData.echo
|
||||||
@ -257,8 +145,7 @@ function initReverseWebsocket() {
|
|||||||
wsReply(wsClient, OB11WebsocketResponse.error(`api处理出错:${e}`, 1200, echo))
|
wsReply(wsClient, OB11WebsocketResponse.error(`api处理出错:${e}`, 1200, echo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
log(e.stack);
|
log(e.stack);
|
||||||
}
|
}
|
||||||
}).then();
|
}).then();
|
||||||
@ -292,7 +179,7 @@ export function postMsg(msg: PostMsgType) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const host of config.httpHosts) {
|
for (const host of config.ob11.httpHosts) {
|
||||||
fetch(host, {
|
fetch(host, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@ -310,33 +197,3 @@ export function postMsg(msg: PostMsgType) {
|
|||||||
log("新消息事件ws上报", msg);
|
log("新消息事件ws上报", msg);
|
||||||
callEvent(msg);
|
callEvent(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function registerRouter(action: string, handle: (payload: any) => Promise<any>) {
|
|
||||||
let url = action.toString()
|
|
||||||
if (!action.startsWith("/")) {
|
|
||||||
url = "/" + action
|
|
||||||
}
|
|
||||||
|
|
||||||
async function _handle(res: Response, payload: any) {
|
|
||||||
log("receive post data", url, payload)
|
|
||||||
try {
|
|
||||||
const result = await handle(payload)
|
|
||||||
res.send(result)
|
|
||||||
} catch (e) {
|
|
||||||
log(e.stack);
|
|
||||||
res.send(OB11Response.error(e.stack.toString(), 200))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expressAPP.post(url, expressAuthorize, (req: Request, res: Response) => {
|
|
||||||
_handle(res, req.body || {}).then()
|
|
||||||
});
|
|
||||||
expressAPP.get(url, expressAuthorize, (req: Request, res: Response) => {
|
|
||||||
_handle(res, req.query as any || {}).then()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const action of actionHandlers) {
|
|
||||||
registerRouter(action.actionName, (payload) => action.handle(payload))
|
|
||||||
}
|
|
26
src/onebot11/server/http.ts
Normal file
26
src/onebot11/server/http.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import {Response} from "express";
|
||||||
|
import {getConfigUtil} from "../../common/utils";
|
||||||
|
import {OB11Response} from "../action/utils";
|
||||||
|
import {HttpServerBase} from "../../server/http";
|
||||||
|
import {actionHandlers} from "../action";
|
||||||
|
|
||||||
|
class OB11HTTPServer extends HttpServerBase {
|
||||||
|
name = "OneBot V11 server"
|
||||||
|
handleFailed(res: Response, payload: any, e: any) {
|
||||||
|
res.send(OB11Response.error(e.stack.toString(), 200))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected listen(port: number) {
|
||||||
|
if (getConfigUtil().getConfig().ob11.enableHttp) {
|
||||||
|
super.listen(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ob11HTTPServer = new OB11HTTPServer();
|
||||||
|
|
||||||
|
for (const action of actionHandlers) {
|
||||||
|
for(const method of ["post", "get"]){
|
||||||
|
ob11HTTPServer.registerRouter(method, action.actionName, (res, payload) => action.handle(payload))
|
||||||
|
}
|
||||||
|
}
|
164
src/renderer.ts
164
src/renderer.ts
@ -5,40 +5,42 @@
|
|||||||
async function onSettingWindowCreated(view: Element) {
|
async function onSettingWindowCreated(view: Element) {
|
||||||
window.llonebot.log("setting window created");
|
window.llonebot.log("setting window created");
|
||||||
let config = await window.llonebot.getConfig()
|
let config = await window.llonebot.getConfig()
|
||||||
|
const httpClass = "http";
|
||||||
|
const httpPostClass = "http-post";
|
||||||
|
const wsClass = "ws";
|
||||||
|
const reverseWSClass = "reverse-ws";
|
||||||
|
|
||||||
function createHttpHostEleStr(host: string) {
|
function createHttpHostEleStr(host: string) {
|
||||||
let eleStr = `
|
let eleStr = `
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
<setting-item data-direction="row" class="hostItem vertical-list-item ${httpPostClass}">
|
||||||
<h2>事件上报地址(http)</h2>
|
<h2>HTTP事件上报地址(http)</h2>
|
||||||
<input class="httpHost input-text" type="text" value="${host}"
|
<input class="httpHost input-text" type="text" value="${host}"
|
||||||
style="width:60%;padding: 5px"
|
style="width:60%;padding: 5px"
|
||||||
placeholder="如果localhost上报失败试试局域网ip"/>
|
placeholder="如果localhost上报失败试试局域网ip"/>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
|
|
||||||
`
|
`
|
||||||
return eleStr
|
return eleStr
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWsHostEleStr(host: string) {
|
function createWsHostEleStr(host: string) {
|
||||||
let eleStr = `
|
let eleStr = `
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
<setting-item data-direction="row" class="hostItem vertical-list-item ${reverseWSClass}">
|
||||||
<h2>事件上报地址(反向websocket)</h2>
|
<h2>事件上报地址(反向websocket)</h2>
|
||||||
<input class="wsHost input-text" type="text" value="${host}"
|
<input class="wsHost input-text" type="text" value="${host}"
|
||||||
style="width:60%;padding: 5px"
|
style="width:60%;padding: 5px"
|
||||||
placeholder="如果localhost上报失败试试局域网ip"/>
|
placeholder="如果localhost上报失败试试局域网ip"/>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
|
|
||||||
`
|
`
|
||||||
return eleStr
|
return eleStr
|
||||||
}
|
}
|
||||||
|
|
||||||
let httpHostsEleStr = ""
|
let httpHostsEleStr = ""
|
||||||
for (const host of config.httpHosts) {
|
for (const host of config.ob11.httpHosts) {
|
||||||
httpHostsEleStr += createHttpHostEleStr(host);
|
httpHostsEleStr += createHttpHostEleStr(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wsHostsEleStr = ""
|
let wsHostsEleStr = ""
|
||||||
for (const host of config.wsHosts) {
|
for (const host of config.ob11.wsHosts) {
|
||||||
wsHostsEleStr += createWsHostEleStr(host);
|
wsHostsEleStr += createWsHostEleStr(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,63 +49,63 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
<setting-section>
|
<setting-section>
|
||||||
<setting-panel>
|
<setting-panel>
|
||||||
<setting-list class="wrap">
|
<setting-list class="wrap">
|
||||||
<setting-item class="vertical-list-item" data-direction="row">
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
|
<div>
|
||||||
|
<div>启用HTTP服务</div>
|
||||||
|
</div>
|
||||||
|
<setting-switch id="http" ${config.ob11.enableHttp ? "is-active" : ""}></setting-switch>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item class="vertical-list-item ${httpClass}" data-direction="row" style="display: ${config.ob11.enableHttp ? '' : 'none'}">
|
||||||
<setting-text>HTTP监听端口</setting-text>
|
<setting-text>HTTP监听端口</setting-text>
|
||||||
<input id="httpPort" type="number" value="${config.httpPort}"/>
|
<input id="httpPort" type="number" value="${config.ob11.httpPort}"/>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
<div>
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
<button id="addHttpHost" class="q-button">添加HTTP POST上报地址</button>
|
<div>
|
||||||
|
<div>启用HTTP事件上报</div>
|
||||||
|
</div>
|
||||||
|
<setting-switch id="httpPost" ${config.ob11.enableHttpPost ? "is-active" : ""}></setting-switch>
|
||||||
|
</setting-item>
|
||||||
|
<div class="${httpPostClass}" style="display: ${config.ob11.enableHttpPost ? '' : 'none'}">
|
||||||
|
<div >
|
||||||
|
<button id="addHttpHost" class="q-button">添加HTTP POST上报地址</button>
|
||||||
|
</div>
|
||||||
|
<div id="httpHostItems">
|
||||||
|
${httpHostsEleStr}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="httpHostItems">
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
${httpHostsEleStr}
|
<div>
|
||||||
</div>
|
<div>启用正向Websocket协议</div>
|
||||||
|
</div>
|
||||||
<setting-item class="vertical-list-item" data-direction="row">
|
<setting-switch id="websocket" ${config.ob11.enableWs ? "is-active" : ""}></setting-switch>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item class="vertical-list-item ${wsClass}" data-direction="row" style="display: ${config.ob11.enableWs ? '' : 'none'}">
|
||||||
<setting-text>正向Websocket监听端口</setting-text>
|
<setting-text>正向Websocket监听端口</setting-text>
|
||||||
<input id="wsPort" type="number" value="${config.wsPort}"/>
|
<input id="wsPort" type="number" value="${config.ob11.wsPort}"/>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
|
|
||||||
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
|
<div>
|
||||||
|
<div>启用反向Websocket协议</div>
|
||||||
|
</div>
|
||||||
|
<setting-switch id="websocketReverse" ${config.ob11.enableWsReverse ? "is-active" : ""}></setting-switch>
|
||||||
|
</setting-item>
|
||||||
|
<div class="${reverseWSClass}" style="display: ${config.ob11.enableWsReverse ? '' : 'none'}">
|
||||||
|
<div>
|
||||||
|
<button id="addWsHost" class="q-button">添加反向Websocket上报地址</button>
|
||||||
|
</div>
|
||||||
|
<div id="wsHostItems">
|
||||||
|
${wsHostsEleStr}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<setting-item class="vertical-list-item" data-direction="row">
|
<setting-item class="vertical-list-item" data-direction="row">
|
||||||
<setting-text>Access Token</setting-text>
|
<setting-text>Access Token</setting-text>
|
||||||
<input id="token" type="text" placeholder="可为空" value="${config.token}"/>
|
<input id="token" type="text" placeholder="可为空" value="${config.token}"/>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
<div>
|
|
||||||
<button id="addWsHost" class="q-button">添加反向Websocket上报地址</button>
|
|
||||||
</div>
|
|
||||||
<div id="wsHostItems">
|
|
||||||
${wsHostsEleStr}
|
|
||||||
</div>
|
|
||||||
<button id="save" class="q-button">保存</button>
|
<button id="save" class="q-button">保存</button>
|
||||||
</setting-list>
|
</setting-list>
|
||||||
</setting-panel>
|
</setting-panel>
|
||||||
<setting-panel>
|
<setting-panel>
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
|
||||||
<div>
|
|
||||||
<div>启用HTTP支持</div>
|
|
||||||
<div class="tips">修改后须重启QQ生效</div>
|
|
||||||
</div>
|
|
||||||
<setting-switch id="http" ${config.enableHttp ? "is-active" : ""}></setting-switch>
|
|
||||||
</setting-item>
|
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
|
||||||
<div>
|
|
||||||
<div>启用HTTP POST支持</div>
|
|
||||||
<div class="tips">修改后须重启QQ生效</div>
|
|
||||||
</div>
|
|
||||||
<setting-switch id="httpPost" ${config.enableHttpPost ? "is-active" : ""}></setting-switch>
|
|
||||||
</setting-item>
|
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
|
||||||
<div>
|
|
||||||
<div>启用正向Websocket支持</div>
|
|
||||||
<div class="tips">修改后须重启QQ生效</div>
|
|
||||||
</div>
|
|
||||||
<setting-switch id="websocket" ${config.enableWs ? "is-active" : ""}></setting-switch>
|
|
||||||
</setting-item>
|
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
|
||||||
<div>
|
|
||||||
<div>启用反向Websocket支持</div>
|
|
||||||
<div class="tips">修改后须重启QQ生效</div>
|
|
||||||
</div>
|
|
||||||
<setting-switch id="websocketReverse" ${config.enableWsReverse ? "is-active" : ""}></setting-switch>
|
|
||||||
</setting-item>
|
|
||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
<div>
|
<div>
|
||||||
<div>上报文件进行base64编码</div>
|
<div>上报文件进行base64编码</div>
|
||||||
@ -128,7 +130,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||||
<div>
|
<div>
|
||||||
<div>日志</div>
|
<div>日志</div>
|
||||||
<div class="tips">日志目录:${window.LiteLoader.plugins["LLOneBot"].path.data}</div>
|
<div class="tips">目录:${window.LiteLoader.plugins["LLOneBot"].path.data}</div>
|
||||||
</div>
|
</div>
|
||||||
<setting-switch id="log" ${config.log ? "is-active" : ""}></setting-switch>
|
<setting-switch id="log" ${config.log ? "is-active" : ""}></setting-switch>
|
||||||
</setting-item>
|
</setting-item>
|
||||||
@ -160,8 +162,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
let addressDoc = parser.parseFromString(createWsHostEleStr(initValue), "text/html");
|
let addressDoc = parser.parseFromString(createWsHostEleStr(initValue), "text/html");
|
||||||
addressEle = addressDoc.querySelector("setting-item")
|
addressEle = addressDoc.querySelector("setting-item")
|
||||||
hostItemsEle = document.getElementById("wsHostItems");
|
hostItemsEle = document.getElementById("wsHostItems");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let addressDoc = parser.parseFromString(createHttpHostEleStr(initValue), "text/html");
|
let addressDoc = parser.parseFromString(createHttpHostEleStr(initValue), "text/html");
|
||||||
addressEle = addressDoc.querySelector("setting-item")
|
addressEle = addressDoc.querySelector("setting-item")
|
||||||
hostItemsEle = document.getElementById("httpHostItems");
|
hostItemsEle = document.getElementById("httpHostItems");
|
||||||
@ -174,24 +175,38 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
doc.getElementById("addHttpHost").addEventListener("click", () => addHostEle("http"))
|
doc.getElementById("addHttpHost").addEventListener("click", () => addHostEle("http"))
|
||||||
doc.getElementById("addWsHost").addEventListener("click", () => addHostEle("ws"))
|
doc.getElementById("addWsHost").addEventListener("click", () => addHostEle("ws"))
|
||||||
|
|
||||||
function switchClick(eleId: string, configKey: string) {
|
function switchClick(eleId: string, configKey: string, _config=null) {
|
||||||
|
if (!_config){
|
||||||
|
_config = config
|
||||||
|
}
|
||||||
doc.getElementById(eleId)?.addEventListener("click", (e) => {
|
doc.getElementById(eleId)?.addEventListener("click", (e) => {
|
||||||
const switchEle = e.target as HTMLInputElement
|
const switchEle = e.target as HTMLInputElement
|
||||||
if (config[configKey]) {
|
if (_config[configKey]) {
|
||||||
config[configKey] = false
|
_config[configKey] = false
|
||||||
switchEle.removeAttribute("is-active")
|
switchEle.removeAttribute("is-active")
|
||||||
} else {
|
} else {
|
||||||
config[configKey] = true
|
_config[configKey] = true
|
||||||
switchEle.setAttribute("is-active", "")
|
switchEle.setAttribute("is-active", "")
|
||||||
}
|
}
|
||||||
|
// 妈蛋,手动操作DOM越写越麻烦,要不用vue算了
|
||||||
|
const keyClassMap = {
|
||||||
|
"enableHttp": httpClass,
|
||||||
|
"enableHttpPost": httpPostClass,
|
||||||
|
"enableWs": wsClass,
|
||||||
|
"enableWsReverse": reverseWSClass,
|
||||||
|
}
|
||||||
|
for (let e of document.getElementsByClassName(keyClassMap[configKey])) {
|
||||||
|
e["style"].display = _config[configKey] ? "" : "none"
|
||||||
|
}
|
||||||
|
|
||||||
window.llonebot.setConfig(config)
|
window.llonebot.setConfig(config)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
switchClick("http", "enableHttp");
|
switchClick("http", "enableHttp", config.ob11);
|
||||||
switchClick("httpPost", "enableHttpPost");
|
switchClick("httpPost", "enableHttpPost", config.ob11);
|
||||||
switchClick("websocket", "enableWs");
|
switchClick("websocket", "enableWs", config.ob11);
|
||||||
switchClick("websocketReverse", "enableWsReverse");
|
switchClick("websocketReverse", "enableWsReverse", config.ob11);
|
||||||
switchClick("debug", "debug");
|
switchClick("debug", "debug");
|
||||||
switchClick("switchBase64", "enableBase64");
|
switchClick("switchBase64", "enableBase64");
|
||||||
switchClick("reportSelfMessage", "reportSelfMessage");
|
switchClick("reportSelfMessage", "reportSelfMessage");
|
||||||
@ -210,27 +225,24 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
let httpHosts: string[] = [];
|
let httpHosts: string[] = [];
|
||||||
|
|
||||||
for (const hostEle of httpHostEles) {
|
for (const hostEle of httpHostEles) {
|
||||||
if (hostEle.value) {
|
const value = hostEle.value.trim();
|
||||||
httpHosts.push(hostEle.value);
|
value && httpHosts.push(value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wsPort = wsPortEle.value
|
const wsPort = wsPortEle.value;
|
||||||
const token = tokenEle.value
|
const token = tokenEle.value.trim();
|
||||||
let wsHosts: string[] = [];
|
let wsHosts: string[] = [];
|
||||||
|
|
||||||
for (const hostEle of wsHostEles) {
|
for (const hostEle of wsHostEles) {
|
||||||
if (hostEle.value) {
|
const value = hostEle.value.trim();
|
||||||
wsHosts.push(hostEle.value);
|
value && wsHosts.push(value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.ob11.httpPort = parseInt(httpPort);
|
||||||
config.httpPort = parseInt(httpPort);
|
config.ob11.httpHosts = httpHosts;
|
||||||
config.httpHosts = httpHosts;
|
config.ob11.wsPort = parseInt(wsPort);
|
||||||
config.wsPort = parseInt(wsPort);
|
config.ob11.wsHosts = wsHosts;
|
||||||
config.wsHosts = wsHosts;
|
config.token = token;
|
||||||
config.token = token.trim();
|
|
||||||
window.llonebot.setConfig(config);
|
window.llonebot.setConfig(config);
|
||||||
alert("保存成功");
|
alert("保存成功");
|
||||||
})
|
})
|
||||||
|
6
src/server/base.ts
Normal file
6
src/server/base.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export abstract class ServerBase{
|
||||||
|
abstract start: () => void
|
||||||
|
abstract restart: ()=>void
|
||||||
|
}
|
106
src/server/http.ts
Normal file
106
src/server/http.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import express, {Express, Request, Response} from "express";
|
||||||
|
import {getConfigUtil, log} from "../common/utils";
|
||||||
|
import http from "http";
|
||||||
|
|
||||||
|
const JSONbig = require('json-bigint')({storeAsString: true});
|
||||||
|
|
||||||
|
type RegisterHandler = (res: Response, payload: any) => Promise<any>
|
||||||
|
|
||||||
|
export abstract class HttpServerBase {
|
||||||
|
name: string = "LLOneBot";
|
||||||
|
private readonly expressAPP: Express;
|
||||||
|
private server: http.Server = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.expressAPP = express();
|
||||||
|
this.expressAPP.use(express.urlencoded({extended: true, limit: "500mb"}));
|
||||||
|
this.expressAPP.use((req, res, next) => {
|
||||||
|
let data = '';
|
||||||
|
req.on('data', chunk => {
|
||||||
|
data += chunk.toString();
|
||||||
|
});
|
||||||
|
req.on('end', () => {
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
// log("receive raw", data)
|
||||||
|
req.body = JSONbig.parse(data);
|
||||||
|
} catch (e) {
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
authorize(req: Request, res: Response, next: () => void) {
|
||||||
|
let serverToken = getConfigUtil().getConfig().token;
|
||||||
|
let clientToken = ""
|
||||||
|
const authHeader = req.get("authorization")
|
||||||
|
if (authHeader) {
|
||||||
|
clientToken = authHeader.split("Bearer ").pop()
|
||||||
|
log("receive http header token", clientToken)
|
||||||
|
} else if (req.query.access_token) {
|
||||||
|
if (Array.isArray(req.query.access_token)) {
|
||||||
|
clientToken = req.query.access_token[0].toString();
|
||||||
|
} else {
|
||||||
|
clientToken = req.query.access_token.toString();
|
||||||
|
}
|
||||||
|
log("receive http url token", clientToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverToken && clientToken != serverToken) {
|
||||||
|
return res.status(403).send(JSON.stringify({message: 'token verify failed!'}));
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
start(port: number) {
|
||||||
|
this.expressAPP.get('/', (req: Request, res: Response) => {
|
||||||
|
res.send(`${this.name}已启动`);
|
||||||
|
})
|
||||||
|
this.listen(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if (this.server){
|
||||||
|
this.server.close()
|
||||||
|
this.server = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restart(port: number){
|
||||||
|
this.stop()
|
||||||
|
this.start(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract handleFailed(res: Response, payload: any, err: any): void
|
||||||
|
|
||||||
|
registerRouter(method: string, url: string, handler: RegisterHandler) {
|
||||||
|
if (!url.startsWith("/")) {
|
||||||
|
url = "/" + url
|
||||||
|
}
|
||||||
|
const methodFunc = this.expressAPP[method]
|
||||||
|
if (!methodFunc){
|
||||||
|
const err = `${this.name} register router failed,${method} not exist`;
|
||||||
|
log(err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
this.expressAPP[method](url, this.authorize, async (req: Request, res: Response) => {
|
||||||
|
const payload = req.body || req.query || {}
|
||||||
|
try{
|
||||||
|
res.send(await handler(res, payload))
|
||||||
|
}catch (e) {
|
||||||
|
this.handleFailed(res, payload, e.stack.toString())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected listen(port: number) {
|
||||||
|
this.server = this.expressAPP.listen(port, "0.0.0.0", () => {
|
||||||
|
const info = `${this.name} started 0.0.0.0:${port}`
|
||||||
|
console.log(info);
|
||||||
|
log(info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user