feat: 支持ipv6_patch-3

This commit is contained in:
zhiyu1998 2024-11-25 17:06:52 +08:00
parent 6b3caecbf8
commit cd0ce9a9c0
5 changed files with 117 additions and 8 deletions

View File

@ -1,6 +1,6 @@
import os from "os";
import { REDIS_YUNZAI_WEBUI } from "../constants/constant.js";
import config from "../model/config.js";
import { constructPublicIPsMsg } from "../utils/network.js";
import { redisSetKey } from "../utils/redis-util.js";
import { getBotLoginInfo, getBotStatus, getBotVersionInfo, sendPrivateMsg } from "../utils/yunzai-util.js";
@ -53,11 +53,7 @@ export class WebUI extends plugin {
// 这里有点延迟,需要写反
e.reply(`R插件可视化面板${ realIsOpenWebUI ? "✅已开启" : "❌已关闭" },重启后生效`);
if (realIsOpenWebUI) {
const networkInterfaces = os.networkInterfaces();
const ipAddress = Object.values(networkInterfaces)
.flat()
.filter(detail => detail.family === 'IPv4' && !detail.internal)[0].address;
await sendPrivateMsg(e, `R插件可视化面板地址${ ipAddress }:4016`);
await sendPrivateMsg(e, constructPublicIPsMsg());
}
return true;
}

View File

@ -1,6 +1,7 @@
import fs from "node:fs";
import path from "path";
import config from "./model/config.js";
import { constructPublicIPsMsg } from "./utils/network.js";
import { startNextJs } from "./utils/start-nextjs.js";
if (!global.segment) {
global.segment = (await import("oicq")).segment
@ -41,7 +42,8 @@ for (let i in files) {
// 检查是否启动 webui
if (isOpenWebUI) {
startNextJs('dev')
startNextJs('dev');
logger.info(constructPublicIPsMsg());
}
export { apps };

View File

@ -4,6 +4,7 @@
"type": "module",
"scripts": {
"dev": "cd server && next dev -p 4016",
"dev6": "cd server && HOST=:: next dev -p 4016",
"start": "cd server && next start -p 4016",
"build": "cd server && next build"
},

105
utils/network.js Normal file
View File

@ -0,0 +1,105 @@
import os from 'os';
/**
* 判断是否是公网地址
* @param ip
* @returns {boolean}
*/
function isPublicIP(ip) {
if (ip.includes(':')) {
// IPv6 检测
if (ip.startsWith('fe80') || ip.startsWith('fc00')) {
return false; // 本地链路或私有 IPv6
}
return true; // 其他 IPv6 认为是公网
} else {
// IPv4 检测
const parts = ip.split('.').map(Number);
if (
(parts[0] === 10) || // 10.0.0.0/8
(parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) || // 172.16.0.0/12
(parts[0] === 192 && parts[1] === 168) // 192.168.0.0/16
) {
return false; // 私有 IPv4
}
return true; // 其他 IPv4 认为是公网
}
}
/**
* 判断是否有公网 IPv6
* @returns {boolean}
*/
export function hasIPv6Only() {
const interfaces = os.networkInterfaces();
let hasPublicIPv4 = false;
let hasPublicIPv6 = false;
for (const iface of Object.values(interfaces)) {
for (const config of iface) {
if (!config.internal && isPublicIP(config.address)) {
if (config.family === 'IPv4') {
hasPublicIPv4 = true;
}
if (config.family === 'IPv6') {
hasPublicIPv6 = true;
}
}
}
}
if (hasPublicIPv6 && !hasPublicIPv4) {
logger.info('[R插件][公网检测]服务器仅拥有一个公网IPv6地址');
return true;
} else if (hasPublicIPv4 && hasPublicIPv6) {
logger.info('[R插件][公网检测]服务器同时拥有公共IPv4和IPv6地址');
return false;
} else if (hasPublicIPv4) {
logger.info('[R插件][公网检测]服务器仅拥有一个公网IPv4地址');
return false;
} else {
logger.info('[R插件][公网检测]服务器未配置公网IP地址');
return false;
}
}
/**
* 获取所有公网IP地址
* @returns {*[]}
*/
export function getPublicIPs() {
const interfaces = os.networkInterfaces();
const publicIPs = [];
for (const [name, iface] of Object.entries(interfaces)) {
for (const config of iface) {
if (!config.internal && isPublicIP(config.address)) {
publicIPs.push({
interface: name,
address: config.address,
family: config.family,
});
}
}
}
return publicIPs;
}
export function constructPublicIPsMsg() {
const networkInterfaces = os.networkInterfaces();
const ipAddress = Object.values(networkInterfaces)
.flat()
.filter(detail => detail.family === 'IPv4' && !detail.internal)[0].address;
const publicIPs = getPublicIPs();
let publicIPsStr = '';
// 如果有公网地址
if (publicIPs.length > 0) {
publicIPsStr = `\n公网地址:${ getPublicIPs().map(item => {
logger.info('[R插件][公网检测]公网IP地址', item.address);
return `#${ item.address }:4016#\n`;
}) }`;
}
publicIPsStr = `R插件可视化面板内网地址${ ipAddress }:4016${ publicIPsStr }`;
return publicIPsStr;
}

View File

@ -1,4 +1,5 @@
import { spawn } from 'child_process';
import { hasIPv6Only } from "./network.js";
logger.mark(`[R插件][WebUI], 父进程 PID: ${process.pid}`);
@ -6,10 +7,14 @@ let nextjsProcess = null;
// 启动子进程运行 Next.js
export const startNextJs = (mode = 'start') => {
const script = mode === 'start' ? 'start' : 'dev';
let script = mode === 'start' ? 'start' : 'dev';
logger.info(logger.yellow(`[R插件][WebUI监测],启动 WebUI ${mode} 进程...`));
if (hasIPv6Only()) {
script = 'dev6';
}
nextjsProcess = spawn('pnpm', ['run', script], {
cwd: './plugins/rconsole-plugin', // 指定工作目录
stdio: 'ignore',