Skip to content

Commit

Permalink
Merge pull request #567 from bietiaop/webapi-bietiaop
Browse files Browse the repository at this point in the history
refactor:优化WebUI后端代码格式(无新功能添加)
  • Loading branch information
MliKiowa authored Nov 27, 2024
2 parents e0fd378 + 79fd10a commit 7196e47
Show file tree
Hide file tree
Showing 25 changed files with 482 additions and 376 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
"dependencies": {
"express": "^5.0.0",
"fluent-ffmpeg": "^2.1.2",
"piscina": "^4.7.0",
"qrcode-terminal": "^0.12.0",
"silk-wasm": "^3.6.1",
"ws": "^8.18.0",
"piscina": "^4.7.0"
"ws": "^8.18.0"
}
}
79 changes: 45 additions & 34 deletions src/webui/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
/**
* @file WebUI服务入口文件
*/

import express from 'express';
import { ALLRouter } from './src/router';

import { LogWrapper } from '@/common/log';
import { NapCatPathWrapper } from '@/common/path';
import { WebUiConfigWrapper } from './src/helper/config';
import { RequestUtil } from '@/common/request';
import { isIP } from "node:net";

import { WebUiConfigWrapper } from '@webapi/helper/config';
import { ALLRouter } from '@webapi/router';
import { cors } from '@webapi/middleware/cors';
import { createUrl } from '@webapi/utils/url';
import { sendSuccess } from '@webapi/utils/response';

// 实例化Express
const app = express();

/**
Expand All @@ -26,49 +35,51 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
log('[NapCat] [WebUi] Current WebUi is not run.');
return;
}

// ------------注册中间件------------
// 使用express的json中间件
app.use(express.json());
// 初始服务

// CORS中间件
// TODO:
app.use(cors);
// ------------中间件结束------------

// ------------挂载路由------------
// 挂载静态路由(前端),路径为 [/前缀]/webui
app.use(config.prefix + '/webui', express.static(pathWrapper.staticPath));
// 挂载API接口
app.use(config.prefix + '/api', ALLRouter);

// 初始服务(先放个首页)
// WebUI只在config.prefix所示路径上提供服务,可配合Nginx挂载到子目录中
app.all(config.prefix + '/', (_req, res) => {
res.json({
msg: 'NapCat WebAPI is now running!',
});
});
// 配置静态文件服务,提供./static目录下的文件服务,访问路径为/webui
app.use(config.prefix + '/webui', express.static(pathWrapper.staticPath));
//挂载API接口
// 添加CORS支持
// TODO:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
next();
sendSuccess(res, null, 'NapCat WebAPI is now running!');
});
app.use(config.prefix + '/api', ALLRouter);
// ------------路由挂载结束------------

// ------------启动服务------------
app.listen(config.port, config.host, async () => {
const normalizeHost = (host: string) => {
if (host === '0.0.0.0') return '127.0.0.1';
if (isIP(host) === 6) return `[${host}]`;
return host;
};
const createUrl = (host: string, path: string, token: string) => {
const url = new URL(`http://${normalizeHost(host)}`);
url.port = config.port.toString();
url.pathname = `${config.prefix}${path}`;
url.searchParams.set('token', token);
return url.toString();
};
// 启动后打印出相关地址

const port = config.port.toString(),
searchParams = { token: config.token },
path = `${config.prefix}/webui`;

// 打印日志(地址、token)
log(`[NapCat] [WebUi] Current WebUi is running at http://${config.host}:${config.port}${config.prefix}`);
log(`[NapCat] [WebUi] Login Token is ${config.token}`);
log(`[NapCat] [WebUi] WebUi User Panel Url: ${createUrl(config.host, '/webui', config.token)}`);
log(`[NapCat] [WebUi] WebUi Local Panel Url: ${createUrl('127.0.0.1', '/webui', config.token)}`);
log(`[NapCat] [WebUi] WebUi User Panel Url: ${createUrl(config.host, port, path, searchParams)}`);
log(`[NapCat] [WebUi] WebUi Local Panel Url: ${createUrl('127.0.0.1', port, path, searchParams)}`);

// 获取公网地址
try {
const publishUrl = 'https://ip.011102.xyz/';
const data = await RequestUtil.HttpGetJson<{ IP: { IP: string } }>(publishUrl, 'GET', {}, {}, true, true);
log(`[NapCat] [WebUi] WebUi Publish Panel Url: ${createUrl(data.IP.IP, '/webui', config.token)}`);
log(`[NapCat] [WebUi] WebUi Publish Panel Url: ${createUrl(data.IP.IP, port, path, searchParams)}`);
} catch (err) {
logger.logError(`[NapCat] [WebUi] Get Publish Panel Url Error: ${err}`);
}
});
// ------------Over!------------
}
83 changes: 39 additions & 44 deletions src/webui/src/api/Auth.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,64 @@
import { RequestHandler } from 'express';
import { AuthHelper } from '../helper/SignToken';
import { WebUiDataRuntime } from '../helper/Data';

import { WebUiConfig } from '@/webui';

const isEmpty = (data: any) => data === undefined || data === null || data === '';
import { AuthHelper } from '@webapi/helper/SignToken';
import { WebUiDataRuntime } from '@webapi/helper/Data';
import { sendSuccess, sendError } from '@webapi/utils/response';
import { isEmpty } from '@webapi/utils/check';

// 登录
export const LoginHandler: RequestHandler = async (req, res) => {
// 获取WebUI配置
const WebUiConfigData = await WebUiConfig.GetWebUIConfig();
// 获取请求体中的token
const { token } = req.body;
// 如果token为空,返回错误信息
if (isEmpty(token)) {
res.json({
code: -1,
message: 'token is empty',
});
return;
return sendError(res, 'token is empty');
}
if (!await WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate)) {
res.json({
code: -1,
message: 'login rate limit',
});
return;
// 检查登录频率
if (!(await WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate))) {
return sendError(res, 'login rate limit');
}
//验证config.token是否等于token
if (WebUiConfigData.token !== token) {
res.json({
code: -1,
message: 'token is invalid',
});
return;
return sendError(res, 'token is invalid');
}
const signCredential = Buffer.from(JSON.stringify(await AuthHelper.signCredential(WebUiConfigData.token))).toString('base64');
res.json({
code: 0,
message: 'success',
data: {
'Credential': signCredential,
},
// 签发凭证
const signCredential = Buffer.from(JSON.stringify(await AuthHelper.signCredential(WebUiConfigData.token))).toString(
'base64'
);
// 返回成功信息
return sendSuccess(res, {
Credential: signCredential,
});
return;
};
export const LogoutHandler: RequestHandler = (req, res) => {
// 这玩意无状态销毁个灯 得想想办法
res.json({
code: 0,
message: 'success',
});
return;

// 退出登录
export const LogoutHandler: RequestHandler = (_, res) => {
// TODO: 这玩意无状态销毁个灯 得想想办法
return sendSuccess(res, null);
};

// 检查登录状态
export const checkHandler: RequestHandler = async (req, res) => {
// 获取WebUI配置
const WebUiConfigData = await WebUiConfig.GetWebUIConfig();
// 获取请求头中的Authorization
const authorization = req.headers.authorization;
// 检查凭证
try {
// 从Authorization中获取凭证
const CredentialBase64: string = authorization?.split(' ')[1] as string;
// 解析凭证
const Credential = JSON.parse(Buffer.from(CredentialBase64, 'base64').toString());
// 验证凭证是否在一小时内有效
await AuthHelper.validateCredentialWithinOneHour(WebUiConfigData.token, Credential);
res.json({
code: 0,
message: 'success',
});
return;
// 返回成功信息
return sendSuccess(res, null);
} catch (e) {
res.json({
code: -1,
message: 'failed',
});
// 返回错误信息
return sendError(res, 'Authorization Faild');
}
return;
};
23 changes: 12 additions & 11 deletions src/webui/src/api/BaseInfo.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { RequestHandler } from 'express';

export const LogFileListHandler: RequestHandler = async (req, res) => {
res.send({
code: 0,
data: {
uin: 0,
nick: 'NapCat',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=0&s=640',
status: 'online',
boottime: Date.now()
}
});
import { sendSuccess } from '@webapi/utils/response';

// TODO: Implement LogFileListHandler
export const LogFileListHandler: RequestHandler = async (_, res) => {
const fakeData = {
uin: 0,
nick: 'NapCat',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=0&s=640',
status: 'online',
boottime: Date.now(),
};
sendSuccess(res, fakeData);
};
81 changes: 30 additions & 51 deletions src/webui/src/api/OB11Config.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,58 @@
import { RequestHandler } from 'express';
import { WebUiDataRuntime } from '../helper/Data';
import { existsSync, readFileSync } from 'node:fs';
import { OneBotConfig } from '@/onebot/config/config';
import { resolve } from 'node:path';

import { OneBotConfig } from '@/onebot/config/config';

import { webUiPathWrapper } from '@/webui';
import { WebUiDataRuntime } from '@webapi/helper/Data';
import { sendError, sendSuccess } from '@webapi/utils/response';
import { isEmpty } from '@webapi/utils/check';

const isEmpty = (data: any) => data === undefined || data === null || data === '';
export const OB11GetConfigHandler: RequestHandler = async (req, res) => {
// 获取OneBot11配置
export const OB11GetConfigHandler: RequestHandler = async (_, res) => {
// 获取QQ登录状态
const isLogin = await WebUiDataRuntime.getQQLoginStatus();
// 如果未登录,返回错误
if (!isLogin) {
res.send({
code: -1,
message: 'Not Login',
});
return;
return sendError(res, 'Not Login');
}
// 获取登录的QQ号
const uin = await WebUiDataRuntime.getQQLoginUin();
// 读取配置文件
const configFilePath = resolve(webUiPathWrapper.configPath, `./onebot11_${uin}.json`);
//console.log(configFilePath);
let data: OneBotConfig;
// 尝试解析配置文件
try {
data = JSON.parse(
// 读取配置文件
const data = JSON.parse(
existsSync(configFilePath)
? readFileSync(configFilePath).toString()
: readFileSync(resolve(webUiPathWrapper.configPath, './onebot11.json')).toString()
);
) as OneBotConfig;
// 返回配置文件
return sendSuccess(res, data);
} catch (e) {
data = {} as OneBotConfig;
res.send({
code: -1,
message: 'Config Get Error',
});
return;
return sendError(res, 'Config Get Error');
}
res.send({
code: 0,
message: 'success',
data: data,
});
return;
};

// 写入OneBot11配置
export const OB11SetConfigHandler: RequestHandler = async (req, res) => {
// 获取QQ登录状态
const isLogin = await WebUiDataRuntime.getQQLoginStatus();
// 如果未登录,返回错误
if (!isLogin) {
res.send({
code: -1,
message: 'Not Login',
});
return;
return sendError(res, 'Not Login');
}
// 如果配置为空,返回错误
if (isEmpty(req.body.config)) {
res.send({
code: -1,
message: 'config is empty',
});
return;
return sendError(res, 'config is empty');
}
let SetResult;
// 写入配置
try {
await WebUiDataRuntime.setOB11Config(JSON.parse(req.body.config));
SetResult = true;
return sendSuccess(res, null);
} catch (e) {
SetResult = false;
}
if (SetResult) {
res.send({
code: 0,
message: 'success',
});
} else {
res.send({
code: -1,
message: 'Config Set Error',
});
return sendError(res, 'Config Set Error');
}

return;
};
Loading

0 comments on commit 7196e47

Please sign in to comment.