refactor(core): ♻️ 优化配置管理与正则匹配逻辑
针对 telegram 机器人和脚本逻辑进行了重构: - 在 tg-bot.js 中新增 deleteCfg 函数,用于物理删除数据库配置并同步清除内存缓存,防止旧值误读。 - 在 sntp-rename.js 中提取了 normalizeKey 和 escapeRegex 工具函数,并改用数组展开运算符进行排序,提升了代码的健壮性和可读性。
This commit is contained in:
@@ -26,28 +26,30 @@ function operator(proxies) {
|
|||||||
// 目的:无论节点名叫 "gtm 0.5x" 还是 "GTM0.5X",都能稳定映射
|
// 目的:无论节点名叫 "gtm 0.5x" 还是 "GTM0.5X",都能稳定映射
|
||||||
const normalizedMap = {};
|
const normalizedMap = {};
|
||||||
const originalKeys = Object.keys(featureMap);
|
const originalKeys = Object.keys(featureMap);
|
||||||
|
const normalizeKey = key => key.toUpperCase().replace(/\s+/g, '');
|
||||||
|
const escapeRegex = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
for (const key of originalKeys) {
|
for (const key of originalKeys) {
|
||||||
const safeKey = key.toUpperCase().replace(/\s+/g, '');
|
normalizedMap[normalizeKey(key)] = featureMap[key];
|
||||||
normalizedMap[safeKey] = featureMap[key];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 动态构建复合正则表达式 (核心引擎)
|
// 2. 动态构建复合正则表达式 (核心引擎)
|
||||||
// 按字符串长度降序排序,彻底解决 "短路匹配" (Short-Circuit) 问题
|
// 按字符串长度降序排序,彻底解决 "短路匹配" (Short-Circuit) 问题
|
||||||
const sortedKeys = originalKeys.sort((a, b) => b.length - a.length);
|
const sortedKeys = [...originalKeys].sort((a, b) => b.length - a.length);
|
||||||
|
|
||||||
const regexParts = sortedKeys.map(key => {
|
const regexParts = sortedKeys.map(key => {
|
||||||
// 自动转义正则特殊字符 (防注入报错)
|
// 自动转义正则特殊字符 (防注入报错)
|
||||||
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
const escapedKey = key.trim().split(/\s+/).filter(Boolean).map(escapeRegex).join('\\s*');
|
||||||
|
|
||||||
// 智能边界处理:如果关键词仅由字母和数字组成 (如 S1, BGP),追加 \b 边界
|
// 智能边界处理:如果关键词首尾都是字母或数字,就追加 \b 边界
|
||||||
// 这样能防止配置的 "S1" 错误匹配到 "US1" 或 "TLS1.3"
|
// 这样能防止配置的 "S1" 错误匹配到 "US1" 或 "TLS1.3"
|
||||||
if (/^[A-Za-z0-9]+$/.test(key)) {
|
const trimmedKey = key.trim();
|
||||||
|
if (/^[A-Za-z0-9]/.test(trimmedKey) && /[A-Za-z0-9]$/.test(trimmedKey)) {
|
||||||
return `\\b${escapedKey}\\b`;
|
return `\\b${escapedKey}\\b`;
|
||||||
}
|
}
|
||||||
return escapedKey;
|
return escapedKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 动态拼接出类似: /(GTM\ 0\.5x|\bAnytls\b|\bBGP\b|...)/i
|
// 动态拼接出类似: /(GTM\s*0\.5x|\bAnytls\b|\bBGP\b|...)/i
|
||||||
const featureRegex = new RegExp(`(${regexParts.join('|')})`, 'i');
|
const featureRegex = new RegExp(`(${regexParts.join('|')})`, 'i');
|
||||||
|
|
||||||
// 缓存后缀匹配正则,避免循环内重复创建
|
// 缓存后缀匹配正则,避免循环内重复创建
|
||||||
@@ -63,7 +65,7 @@ function operator(proxies) {
|
|||||||
if (!match) return p; // 未命中配置库,直接放行
|
if (!match) return p; // 未命中配置库,直接放行
|
||||||
|
|
||||||
// B. 清洗提取到的特征词,并去 O(1) 字典中取值
|
// B. 清洗提取到的特征词,并去 O(1) 字典中取值
|
||||||
const mapKey = match[1].toUpperCase().replace(/\s+/g, '');
|
const mapKey = normalizeKey(match[1]);
|
||||||
const injectPayload = normalizedMap[mapKey];
|
const injectPayload = normalizedMap[mapKey];
|
||||||
|
|
||||||
if (!injectPayload) return p; // 兜底安全校验
|
if (!injectPayload) return p; // 兜底安全校验
|
||||||
|
|||||||
@@ -132,6 +132,14 @@ async function setCfg(key, val, env) {
|
|||||||
if (key === 'authorized_admins') CACHE.admin.ts = 0;
|
if (key === 'authorized_admins') CACHE.admin.ts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除配置项:同步失效缓存,避免旧值被 getCfg 误读
|
||||||
|
async function deleteCfg(key, env) {
|
||||||
|
await sql(env, "DELETE FROM config WHERE key=?", key);
|
||||||
|
delete CACHE.data[key];
|
||||||
|
CACHE.ts = 0;
|
||||||
|
if (key === 'authorized_admins') CACHE.admin.ts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取或初始化用户信息实体
|
// 获取或初始化用户信息实体
|
||||||
async function getUser(id, env) {
|
async function getUser(id, env) {
|
||||||
let u = await sql(env, "SELECT * FROM users WHERE user_id = ?", id, 'first');
|
let u = await sql(env, "SELECT * FROM users WHERE user_id = ?", id, 'first');
|
||||||
@@ -939,8 +947,15 @@ async function handleCallback(cb, env) {
|
|||||||
if (!msg || msg.chat.id.toString() !== env.ADMIN_GROUP_ID || !(await isAuthAdmin(from.id, env))) {
|
if (!msg || msg.chat.id.toString() !== env.ADMIN_GROUP_ID || !(await isAuthAdmin(from.id, env))) {
|
||||||
return api(env.BOT_TOKEN, "answerCallbackQuery", { callback_query_id: cb.id, text: "无操作权限", show_alert: true });
|
return api(env.BOT_TOKEN, "answerCallbackQuery", { callback_query_id: cb.id, text: "无操作权限", show_alert: true });
|
||||||
}
|
}
|
||||||
await setCfg(`admin_state:${from.id}`, JSON.stringify({ action: 'input_note', target: p2 }), env);
|
try {
|
||||||
return api(env.BOT_TOKEN, "sendMessage", { chat_id: msg.chat.id, message_thread_id: msg.message_thread_id, text: "⌨️ 请回复备注内容 (回复 /clear 清除):" });
|
await setCfg(`admin_state:${from.id}`, JSON.stringify({ action: 'input_note', target: p2 }), env);
|
||||||
|
await api(env.BOT_TOKEN, "sendMessage", { chat_id: msg.chat.id, message_thread_id: msg.message_thread_id, text: "⌨️ 请回复备注内容 (回复 /clear 清除):" });
|
||||||
|
return api(env.BOT_TOKEN, "answerCallbackQuery", { callback_query_id: cb.id, text: "请直接回复备注内容" });
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Set Note State Failed:", e);
|
||||||
|
await deleteCfg(`admin_state:${from.id}`, env).catch(() => {});
|
||||||
|
return api(env.BOT_TOKEN, "answerCallbackQuery", { callback_query_id: cb.id, text: "操作失败,请重试", show_alert: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (act === 'config') {
|
if (act === 'config') {
|
||||||
@@ -1017,7 +1032,11 @@ async function handleAdminConfig(cid, mid, type, key, val, env) {
|
|||||||
if (key === 'welcome_msg') promptText = `请发送新的欢迎语 (/cancel 取消):\n\n• 支持 <b>文字</b> 或 <b>图片/视频/GIF</b>\n• 支持占位符: {name}\n• 直接发送媒体即可`;
|
if (key === 'welcome_msg') promptText = `请发送新的欢迎语 (/cancel 取消):\n\n• 支持 <b>文字</b> 或 <b>图片/视频/GIF</b>\n• 支持占位符: {name}\n• 直接发送媒体即可`;
|
||||||
return api(env.BOT_TOKEN, "editMessageText", { chat_id: cid, message_id: mid, text: promptText, parse_mode: "HTML" });
|
return api(env.BOT_TOKEN, "editMessageText", { chat_id: cid, message_id: mid, text: promptText, parse_mode: "HTML" });
|
||||||
}
|
}
|
||||||
} catch (e) { api(env.BOT_TOKEN, "answerCallbackQuery", { callback_query_id: mid, text: "Data Fetch Error", show_alert: true }); }
|
} catch (e) {
|
||||||
|
console.error("Admin Config Failed:", e);
|
||||||
|
await deleteCfg(`admin_state:${cid}`, env).catch(() => {});
|
||||||
|
return api(env.BOT_TOKEN, "sendMessage", { chat_id: cid, text: "❌ 面板加载失败,请稍后重试" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFilterKB(env) {
|
async function getFilterKB(env) {
|
||||||
@@ -1038,7 +1057,7 @@ async function getListKB(type, env) {
|
|||||||
|
|
||||||
async function handleAdminInput(id, msg, state, env) {
|
async function handleAdminInput(id, msg, state, env) {
|
||||||
const txt = msg.text || "";
|
const txt = msg.text || "";
|
||||||
if (txt === '/cancel') { await sql(env, "DELETE FROM config WHERE key=?", `admin_state:${id}`); return handleAdminConfig(id, null, 'menu', null, null, env); }
|
if (txt === '/cancel') { await deleteCfg(`admin_state:${id}`, env); return handleAdminConfig(id, null, 'menu', null, null, env); }
|
||||||
let k = state.key, val = txt;
|
let k = state.key, val = txt;
|
||||||
try {
|
try {
|
||||||
if (k === 'welcome_msg') {
|
if (k === 'welcome_msg') {
|
||||||
@@ -1056,7 +1075,7 @@ async function handleAdminInput(id, msg, state, env) {
|
|||||||
else list.push(txt);
|
else list.push(txt);
|
||||||
val = JSON.stringify(list); k = realK;
|
val = JSON.stringify(list); k = realK;
|
||||||
} else if (k === 'authorized_admins') { val = JSON.stringify(txt.split(/[,,]/).map(s => s.trim()).filter(Boolean)); }
|
} else if (k === 'authorized_admins') { val = JSON.stringify(txt.split(/[,,]/).map(s => s.trim()).filter(Boolean)); }
|
||||||
await setCfg(k, val, env); await sql(env, "DELETE FROM config WHERE key=?", `admin_state:${id}`);
|
await setCfg(k, val, env); await deleteCfg(`admin_state:${id}`, env);
|
||||||
const displayVal = (val.startsWith('{') && k === 'welcome_msg') ? "[媒体配置组合]" : val.substring(0,100);
|
const displayVal = (val.startsWith('{') && k === 'welcome_msg') ? "[媒体配置组合]" : val.substring(0,100);
|
||||||
await api(env.BOT_TOKEN, "sendMessage", { chat_id: id, text: `✅ ${k} 规则已写入:\n${displayVal}` });
|
await api(env.BOT_TOKEN, "sendMessage", { chat_id: id, text: `✅ ${k} 规则已写入:\n${displayVal}` });
|
||||||
await handleAdminConfig(id, null, 'menu', null, null, env);
|
await handleAdminConfig(id, null, 'menu', null, null, env);
|
||||||
|
|||||||
Reference in New Issue
Block a user