mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 08:09:19 +00:00
✨feat: 修复部分电脑无法看到 Bot 状态问题
This commit is contained in:
parent
618982e865
commit
caf1d7e550
56
apps/webUI.js
Normal file
56
apps/webUI.js
Normal file
@ -0,0 +1,56 @@
|
||||
import { REDIS_YUNZAI_WEBUI } from "../constants/constant.js";
|
||||
import config from "../model/config.js";
|
||||
import { redisSetKey } from "../utils/redis-util.js";
|
||||
import { getBotLoginInfo, getBotStatus, getBotVersionInfo } from "../utils/yunzai-util.js";
|
||||
|
||||
export class WebUI extends plugin {
|
||||
constructor() {
|
||||
super({
|
||||
name: "R插件 WebUI 开关",
|
||||
dsc: "R插件 WebUI 开关",
|
||||
event: "message",
|
||||
priority: 4000,
|
||||
rule: [
|
||||
{
|
||||
reg: "^#(r|R)wss$",
|
||||
fnc: "rWebSwitch",
|
||||
permission: "master",
|
||||
},
|
||||
{
|
||||
reg: "^#(r|R)ws$",
|
||||
fnc: "rWebStatus",
|
||||
permission: "master",
|
||||
}
|
||||
]
|
||||
});
|
||||
// 配置文件
|
||||
this.toolsConfig = config.getConfig("tools");
|
||||
// 加载WebUI开关
|
||||
this.isOpenWebUI = this.toolsConfig.isOpenWebUI;
|
||||
}
|
||||
|
||||
async rWebSwitch(e) {
|
||||
config.updateField("tools", "isOpenWebUI", !this.isOpenWebUI);
|
||||
const realIsOpenWebUI = config.getConfig("tools").isOpenWebUI;
|
||||
if (realIsOpenWebUI) {
|
||||
Promise.all([getBotStatus(e), getBotVersionInfo(e), getBotLoginInfo(e)]).then(values => {
|
||||
const status = values[0].data;
|
||||
const versionInfo = values[1].data;
|
||||
const loginInfo = values[2].data;
|
||||
redisSetKey(REDIS_YUNZAI_WEBUI, {
|
||||
...status,
|
||||
...versionInfo,
|
||||
...loginInfo
|
||||
})
|
||||
})
|
||||
}
|
||||
// 这里有点延迟,需要写反
|
||||
e.reply(`R插件 WebUI:${ realIsOpenWebUI ? "开启\n🚀 请重启以启动 WebUI" : "关闭" }`);
|
||||
return true;
|
||||
}
|
||||
|
||||
async rWebStatus(e) {
|
||||
e.reply(`R插件 WebUI:${ this.toolsConfig.isOpenWebUI ? "开启" : "关闭" }`);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -93,10 +93,10 @@ export const REDIS_YUNZAI_CLOUDSONGLIST = "Yz:rconsole:tools:cloudsonglist";
|
||||
export const REDIS_YUNZAI_WHITELIST = "Yz:rconsole:tools:whitelist";
|
||||
|
||||
/**
|
||||
* 番剧列表缓存
|
||||
* WEBUI需要数据的缓存
|
||||
* @type {string}
|
||||
*/
|
||||
export const REDIS_YUNZAI_ANIMELIST = "Yz:rconsole:tools:anime";
|
||||
export const REDIS_YUNZAI_WEBUI = "Yz:rconsole:tools:webui";
|
||||
|
||||
export const TWITTER_BEARER_TOKEN = "";
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
"axios": "^1.3.4",
|
||||
"chart.js": "^4.4.6",
|
||||
"form-data": "^4.0.1",
|
||||
"ioredis": "^5.4.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"next": "^14.2.16",
|
||||
"node-id3": "^0.2.6",
|
||||
|
@ -1,3 +1,12 @@
|
||||
import Header from "../components/header.jsx";
|
||||
import Sidebar from "../components/sidebar.jsx";
|
||||
import { DrawerProvider } from "../contexts/drawer-context.js";
|
||||
|
||||
export default function Page() {
|
||||
return <h1><a href="/r">进入控制面板</a></h1>
|
||||
return (
|
||||
<DrawerProvider>
|
||||
<Header/>
|
||||
<Sidebar />
|
||||
</DrawerProvider>
|
||||
)
|
||||
}
|
||||
|
12
server/app/r/api/bot/route.js
Normal file
12
server/app/r/api/bot/route.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { REDIS_YUNZAI_WEBUI } from "../../../../../constants/constant.js";
|
||||
import { redis } from "../../../../utils/redis.js";
|
||||
|
||||
|
||||
export async function GET(req, res) {
|
||||
const botInfo = JSON.parse(await redis.get(REDIS_YUNZAI_WEBUI));
|
||||
|
||||
return new Response(JSON.stringify(botInfo), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import axiosInstance from "../../../../../utils/axiosInstance.js";
|
||||
|
||||
export async function GET(request, { params }) {
|
||||
const { pid } = params;
|
||||
const napcatResp = await axiosInstance.get(`/${ pid }`);
|
||||
return new Response(JSON.stringify(napcatResp), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import Sidebar from "../../components/sidebar.jsx";
|
||||
import Header from "../../components/header.jsx";
|
||||
import { DrawerProvider } from "../../contexts/drawer-context.js";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<DrawerProvider>
|
||||
<Header/>
|
||||
<Sidebar />
|
||||
</DrawerProvider>
|
||||
)
|
||||
}
|
@ -1,17 +1,21 @@
|
||||
"use client"
|
||||
import { useState, useEffect } from 'react';
|
||||
import { BOT_INFO_URL } from "../constants/api.js";
|
||||
import { useDrawer } from "../contexts/drawer-context.js";
|
||||
import { getUserInfo } from "../utils/napact.js";
|
||||
import ThemeToggle from "./ThemeToggle.jsx";
|
||||
|
||||
export default function Header () {
|
||||
|
||||
const { toggleDrawer } = useDrawer();
|
||||
|
||||
const [user, setUser] = useState({ user_id: null, nickname: '' });
|
||||
const [user, setUser] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getUserInfo().then(setUser);
|
||||
fetch(BOT_INFO_URL)
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(data => setUser(data))
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -49,12 +53,12 @@ export default function Header () {
|
||||
<div className="w-10 rounded-full">
|
||||
<img
|
||||
alt="头像"
|
||||
src={`http://q1.qlogo.cn/g?b=qq&nk=${user.user_id}&s=100`}/>
|
||||
src={`http://q1.qlogo.cn/g?b=qq&nk=${user?.user_id}&s=100`}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1.5">
|
||||
<div className="font-bold">{user.nickname || "未获取"}</div>
|
||||
<div className="text-sm opacity-50">{user.user_id || "NaN"}</div>
|
||||
<div className="font-bold">{user?.nickname || "未获取"}</div>
|
||||
<div className="text-sm opacity-50">{user?.user_id || "NaN"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,18 +1,16 @@
|
||||
import { getStatus, getUserInfo, getVersionInfo } from "../../utils/napact.js";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BOT_INFO_URL } from "../../constants/api.js";
|
||||
|
||||
export function BotItem() {
|
||||
|
||||
const [user, setUser] = useState({ user_id: null, nickname: '' });
|
||||
|
||||
const [status, setStatus] = useState({ online: false, good: false, stat: {} });
|
||||
|
||||
const [versionInfo, setVersionInfo] = useState({ app_name: "", app_version: "", protocol_version: "" });
|
||||
const [user, setUser] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
getUserInfo().then(setUser);
|
||||
getStatus().then(setStatus);
|
||||
getVersionInfo().then(setVersionInfo);
|
||||
fetch(BOT_INFO_URL)
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(data => setUser(data))
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -20,22 +18,22 @@ export function BotItem() {
|
||||
<div className="card-body">
|
||||
<h2 className="card-title">🐔状态</h2>
|
||||
<div className="flex flex-row pt-5 justify-between items-center">
|
||||
<div className={ `avatar ${ status.online ? "online" : "offline" }` }>
|
||||
<div className={ `avatar ${ user?.online ? "online" : "offline" }` }>
|
||||
<div className="w-24 rounded-full">
|
||||
<img src={ `http://q1.qlogo.cn/g?b=qq&nk=${ user.user_id }&s=100` }/>
|
||||
<img src={ `http://q1.qlogo.cn/g?b=qq&nk=${ user?.user_id }&s=100` }/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col ml-12 space-y-2">
|
||||
<div className="space-y-2">
|
||||
<div className="font-bold">昵称:{ user.nickname || "未获取" }</div>
|
||||
<div className="text-sm opacity-50">QQ号:{ user.user_id || "NaN" }</div>
|
||||
<div className="font-bold">昵称:{ user?.nickname || "未获取" }</div>
|
||||
<div className="text-sm opacity-50">QQ号:{ user?.user_id || "NaN" }</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="font-bold">协议信息:</div>
|
||||
<div className="space-x-1">
|
||||
<div className="badge badge-ghost">{ versionInfo.app_name }</div>
|
||||
<div className="badge badge-ghost">{ versionInfo.app_version }</div>
|
||||
<div className="badge badge-ghost">{ versionInfo.protocol_version }</div>
|
||||
<div className="badge badge-ghost">{ user?.app_name }</div>
|
||||
<div className="badge badge-ghost">{ user?.app_version }</div>
|
||||
<div className="badge badge-ghost">{ user?.protocol_version }</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { NETWORK_BASE_URL } from "../../constants/system.js";
|
||||
import { NETWORK_BASE_URL } from "../../constants/api.js";
|
||||
|
||||
// 测试链接配置
|
||||
const TESTING_LINKS = [
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { CircularProgressbar, buildStyles } from 'react-circular-progressbar';
|
||||
import 'react-circular-progressbar/dist/styles.css';
|
||||
import { SYSTEM_BASE_URL } from "../../constants/system.js";
|
||||
import { SYSTEM_BASE_URL } from "../../constants/api.js";
|
||||
|
||||
export default function System() {
|
||||
const [systemInfo, setSystemInfo] = useState(null);
|
||||
|
@ -3,3 +3,5 @@ const BASE_URL = "/r/api";
|
||||
export const SYSTEM_BASE_URL = `${BASE_URL}/system`;
|
||||
|
||||
export const NETWORK_BASE_URL = `${BASE_URL}/network?url=`;
|
||||
|
||||
export const BOT_INFO_URL = `${ BASE_URL }/bot`;
|
@ -1,11 +0,0 @@
|
||||
export const NAPCAT_BASE_URL = "/r/api/napcat";
|
||||
|
||||
/**
|
||||
* 获取登录号信息
|
||||
* @type {string}
|
||||
*/
|
||||
export const NAPCAT_GET_LOGIN_INFO = `${NAPCAT_BASE_URL}/get_login_info`;
|
||||
|
||||
export const NAPCAT_GET_STATUS = `${ NAPCAT_BASE_URL }/get_status`;
|
||||
|
||||
export const NAPCAT_GET_VERSION_INFO = `${ NAPCAT_BASE_URL }/get_version_info`;
|
@ -1,50 +0,0 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// 创建 Axios 实例
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: 'http://192.168.31.230:2537', // 基础请求地址
|
||||
timeout: 5000, // 设置请求超时时间,可根据需要调整
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
axiosInstance.interceptors.request.use(
|
||||
(config) => {
|
||||
// 这里可以添加请求前的处理逻辑,例如添加 token
|
||||
// const token = localStorage.getItem('token');
|
||||
// if (token) {
|
||||
// config.headers.Authorization = `Bearer ${token}`;
|
||||
// }
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 请求错误处理
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => {
|
||||
// 响应成功处理
|
||||
return response.data;
|
||||
},
|
||||
(error) => {
|
||||
// 响应错误处理
|
||||
if (error.response) {
|
||||
// 服务器返回的错误
|
||||
console.error('Error:', error.response.status, error.response.data);
|
||||
} else if (error.request) {
|
||||
// 请求未收到服务器响应
|
||||
console.error('No response received:', error.request);
|
||||
} else {
|
||||
// 设置请求时发生的错误
|
||||
console.error('Request setup error:', error.message);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default axiosInstance;
|
@ -1,17 +0,0 @@
|
||||
import { NAPCAT_GET_LOGIN_INFO, NAPCAT_GET_STATUS, NAPCAT_GET_VERSION_INFO } from "../constants/napcat.js";
|
||||
|
||||
export async function getUserInfo() {
|
||||
const userInfo = await fetch(NAPCAT_GET_LOGIN_INFO).then(resp => resp.json());
|
||||
const { user_id, nickname } = userInfo.data;
|
||||
return { user_id, nickname }
|
||||
}
|
||||
|
||||
export async function getStatus() {
|
||||
const status = await fetch(NAPCAT_GET_STATUS).then(resp => resp.json());
|
||||
return status.data;
|
||||
}
|
||||
|
||||
export async function getVersionInfo() {
|
||||
const versionInfo = await fetch(NAPCAT_GET_VERSION_INFO).then(resp => resp.json());
|
||||
return versionInfo.data;
|
||||
}
|
17
server/utils/redis.js
Normal file
17
server/utils/redis.js
Normal file
@ -0,0 +1,17 @@
|
||||
import fs from "fs";
|
||||
import Redis from "ioredis";
|
||||
import yaml from "js-yaml";
|
||||
import path from "path";
|
||||
|
||||
const configPath = path.join(process.cwd(), "../../../", "config", 'config', 'redis.yaml');
|
||||
|
||||
const yamlContent = await fs.promises.readFile(configPath, 'utf8');
|
||||
const config = yaml.load(yamlContent);
|
||||
|
||||
export const redis = new Redis({
|
||||
port: config.port,
|
||||
host: config.host,
|
||||
username: config.username,
|
||||
password: config.password,
|
||||
db: config.db,
|
||||
})
|
@ -1,8 +1,10 @@
|
||||
import { spawn } from 'child_process';
|
||||
import child_process from "node:child_process";
|
||||
import { getBotLoginInfo, getBotStatus, getBotVersionInfo } from "./utils/yunzai-util.js";
|
||||
|
||||
logger.info(`[R插件][Next.js监测], 父进程 PID: ${process.pid}`);
|
||||
|
||||
let childProcess = null;
|
||||
let nextjsProcess = null;
|
||||
|
||||
// 构建应用程序
|
||||
export const buildNextJs = () => {
|
||||
@ -10,7 +12,7 @@ export const buildNextJs = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buildProcess = spawn('pnpm', ['run', 'build'], {
|
||||
cwd: './plugins/rconsole-plugin/server',
|
||||
stdio: 'inherit',
|
||||
stdio: 'ignore',
|
||||
shell: true,
|
||||
});
|
||||
|
||||
@ -32,24 +34,24 @@ export const startNextJs = (mode = 'start') => {
|
||||
|
||||
logger.info(logger.yellow(`[R插件][Next.js监测],启动 Next.js ${mode} 进程...`));
|
||||
|
||||
childProcess = spawn('pnpm', ['run', script], {
|
||||
nextjsProcess = spawn('pnpm', ['run', script], {
|
||||
cwd: './plugins/rconsole-plugin', // 指定工作目录
|
||||
stdio: 'inherit', // 继承父进程的标准输入输出
|
||||
stdio: ['ignore', 'ignore', 'ignore', 'ipc'], // 继承父进程的标准输入输出
|
||||
shell: true,
|
||||
});
|
||||
|
||||
// 子进程异常退出时捕获信号
|
||||
childProcess.on('close', (code) => {
|
||||
nextjsProcess.on('close', (code) => {
|
||||
logger.error(`[R插件][Next.js监测],Next.js 进程发生异常 ${code}`);
|
||||
childProcess = null;
|
||||
nextjsProcess = null;
|
||||
});
|
||||
};
|
||||
|
||||
// 捕获父进程退出信号
|
||||
const cleanup = () => {
|
||||
logger.info(logger.yellow('[R插件][Next.js监测] 父进程退出,终止子进程...'));
|
||||
if (childProcess) {
|
||||
childProcess.kill(); // 终止子进程
|
||||
if (nextjsProcess) {
|
||||
nextjsProcess.kill(); // 终止子进程
|
||||
}
|
||||
process.exit();
|
||||
};
|
||||
|
@ -86,51 +86,3 @@ export async function redisExistAndUpdateObject(key, updateKey, updateObj) {
|
||||
await redisSetKey(key, objs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某个key
|
||||
* @param key
|
||||
* @returns {Promise<number>}
|
||||
* @example
|
||||
* const result = await redisDeleteKey('myKey');
|
||||
* console.log(result); // 1 if key was deleted, 0 if key did not exist
|
||||
*/
|
||||
export async function redisDeleteKey(key) {
|
||||
return redis.del(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的key
|
||||
* @returns {Promise<Array<string>>}
|
||||
* @example
|
||||
* const keys = await redisGetAllKeys();
|
||||
* console.log(keys); // ['key1', 'key2', ...]
|
||||
*/
|
||||
export async function redisGetAllKeys() {
|
||||
return redis.keys('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置某个key的过期时间
|
||||
* @param key
|
||||
* @param seconds
|
||||
* @returns {Promise<boolean>}
|
||||
* @example
|
||||
* const result = await redisExpireKey('myKey', 3600);
|
||||
* console.log(result); // true if timeout was set, false if key does not exist
|
||||
*/
|
||||
export async function redisExpireKey(key, seconds) {
|
||||
return redis.expire(key, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个key的剩余生存时间
|
||||
* @param key
|
||||
* @returns {Promise<number>}
|
||||
* @example
|
||||
* const ttl = await redisTTLKey('myKey');
|
||||
* console.log(ttl); // time to live in seconds, -1 if key does not have timeout, -2 if key does not exist
|
||||
*/
|
||||
export async function redisTTLKey(key) {
|
||||
return redis.ttl(key);
|
||||
}
|
@ -125,3 +125,30 @@ export async function getReplyMsg(e) {
|
||||
})
|
||||
return msg.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取机器人信息
|
||||
* @param e
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export async function getBotLoginInfo(e) {
|
||||
return await e.bot.sendApi("get_login_info");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运行状态
|
||||
* @param e
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export async function getBotStatus(e) {
|
||||
return await e.bot.sendApi("get_status");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本信息
|
||||
* @param e
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export async function getBotVersionInfo(e) {
|
||||
return await e.bot.sendApi("get_version_info");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user