@@ -367,6 +367,9 @@ function view_settings_menu(token, chat_id, msg_id) {
[ { text : "🔗 Подписки" , callback _data : "/set_list subscription_url" } ] ,
[ { text : "🖥 Кастомные серверы" , callback _data : "/set_list server" } ] ,
[ { text : "🌐 DNS Серверы (Пресеты)" , callback _data : "/dns_presets" } ] ,
[ { text : "🔕 Тихие часы" , callback _data : "/qh" } ] ,
[ { text : "🔍 Проверка правила" , callback _data : "/test_rule" } ] ,
[ { text : "📤 Экспорт конфига" , callback _data : "/export_config" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
@@ -527,16 +530,25 @@ function view_menu(token, chat_id, msg_id) {
{ text : "💻 Устройства" , callback _data : "/devices" } ,
{ text : "🐕 Watchdog" , callback _data : "/watchdog" }
] ,
[
{ text : "⚡ Speedtest" , callback _data : "/speed" } ,
{ text : "📍 Ping" , callback _data : "/ping" }
] ,
[
{ text : "🩺 Диагностика" , callback _data : "/test" } ,
{ text : "🔗 Подключения" , callback _data : "/connections" }
] ,
[
{ text : "📋 Логи" , callback _data : "/logs" } ,
{ text : "ℹ ️ Инфо" , callback _data : "/info" }
] ,
[
{ text : "🤖 ИИ-Самолечение" , callback _data : "/heal" } ,
{ text : "🎮 Игровой QoS" , callback _data : "/qos" }
] ,
[
{ text : "🩺 Диагностика " , callback _data : "/doctor " } ,
{ text : "🔄 Перезапуск " , callback _data : "/restart " }
] ,
[
{ text : "⚙️ Все Настройки" , callback _data : "/settings" }
{ text : "⚙️ Все Настройки " , callback _data : "/settings " } ,
{ text : "📖 Справка " , callback _data : "/help " }
]
] ;
@@ -546,33 +558,46 @@ function view_menu(token, chat_id, msg_id) {
function view _status ( token , chat _id , msg _id ) {
let sys = api . get _system _status ( ) ;
let conn = api . check _connection ( ) ;
let text = "📊 <b>Статус Системы</b>\n\n" +
"Версия: <code>" + ( sys . tachyon _version || "?" ) + "</code>\n" +
"Аптайм: <code>" + sys . uptime + "</code>\n" +
"CPU: <code>" + sys . cpu + "</code>\n" +
"RAM: <code>" + sys . ram _avail + "MB free / " + sys . ram _total + "MB total </code>\n\n" +
"RAM: <code>" + sys . ram _avail + "MB / " + sys . ram _total + "MB</code>\n\n" +
"sing-box: <code>" + sys . singbox + "</code>\n" +
"Watchdog: <code>" + ( sys . watchdog _running ? "🟢 running" : "🔴 stopped" ) + "</code>\n\n" +
"WAN IP : <code>" + ( sys . wan _ip || "unknown " ) + "</code>\n " +
"LAN IP: <code>" + ( sys . lan _ip || "unknown" ) + "</code>\n\n" ;
"WAN: <code>" + ( sys . wan _ip || "? " ) + "</code> " +
( conn && conn . direct ? "✅" : "❌" ) + "\n" +
"Proxy: " + ( conn && conn . proxy ? "✅ reachable" : "❌ unreachable" ) + "\n" +
"LAN: <code>" + ( sys . lan _ip || "?" ) + "</code>\n" ;
if ( sys . pause _remaining > 0 ) {
text += "\n⏸ Пауза: " + as _string ( sys . pause _remaining ) + " сек.\n" ;
}
let keys _servers = keys ( sys . active _servers || { } ) ;
if ( length ( keys _servers ) > 0 ) {
text += "Активные серверы:\n" ;
text += "\n Активные серверы:\n" ;
for ( let i = 0 ; i < length ( keys _servers ) ; i ++ ) {
let gname = keys _servers [ i ] ;
let srv = sys . active _servers [ gname ] ;
let lat = srv . latency != "N/A" ? " (" + srv . latency + " ms)" : "" ;
text += "└ " + escape _html ( gname ) + ": <code>" + escape _html ( srv . server ) + lat + "</code>\n" ;
}
} else {
text += "Активный сервер: <code>нет</code>" ;
}
let keyboard = [
[ { text : "🔄 Обновить" , callback _data : "/status" } ] ,
[
{ text : "⚡ Speedtest" , callback _data : "/speed" } ,
{ text : "📍 Ping" , callback _data : "/ping" }
] ,
[
{ text : "🔄 Обновить" , callback _data : "/status" } ,
{ text : "🩺 Тест" , callback _data : "/test" }
] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
@@ -1163,6 +1188,373 @@ function view_instances(token, chat_id, msg_id) {
else send _message ( token , chat _id , text , "HTML" , kb ) ;
}
// ─── Phase 1: Speed, Ping, Improved Status ─────────────────────────────────
function exec _speedtest ( token , chat _id , msg _id ) {
let wait _text = "⚡ <b>Запуск Speedtest...</b>\n\nТестирую скорость через Cloudflare. Это займёт до 30 секунд." ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , wait _text , "HTML" ) ;
else send _message ( token , chat _id , wait _text , "HTML" ) ;
let result = api . run _speedtest ( ) ;
let text = "⚡ <b>Результат Speedtest</b>\n\n" ;
if ( result ) {
text += "📥 Прямое соединение: <code>" + sprintf ( "%.1f" , result . direct _mbps || 0 ) + " Mbps</code>\n" ;
text += "📤 Через прокси: <code>" + sprintf ( "%.1f" , result . proxy _mbps || 0 ) + " Mbps</code>\n" ;
} else {
text += "❌ Не удалось выполнить тест. Проверьте, запущен ли sing-box.\n" ;
}
let keyboard = [
[ { text : "⚡ Ещё раз" , callback _data : "/speed" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/status" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function view _ping ( token , chat _id , msg _id ) {
let text = "📍 <b>Задержка до серверов</b>\n\n" ;
let data = api . get _clash _proxies _data ( ) ;
if ( ! data || ! data . proxies ) {
text += "❌ Не удалось получить данные из Clash API." ;
let keyboard = [ [ { text : "🔄 Обновить" , callback _data : "/ping" } , { text : "⬅️ Назад" , callback _data : "/status" } ] ] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
return ;
}
let shown = 0 ;
for ( let name in data . proxies ) {
let p = data . proxies [ name ] ;
if ( p . type != "Selector" && p . type != "URLTest" ) continue ;
if ( ! p . history || length ( p . history ) == 0 ) continue ;
let last = p . history [ length ( p . history ) - 1 ] ;
if ( ! last || ! last . delay ) continue ;
let delay = int ( last . delay ) ;
let icon = delay < 100 ? "🟢" : ( delay < 300 ? "🟡" : "🔴" ) ;
text += icon + " <code>" + escape _html ( name ) + "</code>: <code>" + delay + " ms</code>\n" ;
shown ++ ;
}
if ( shown == 0 ) text += "Нет данных о задержках. Нажмите «Обновить»." ;
let keyboard = [
[ { text : "🔄 Обновить" , callback _data : "/ping" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/status" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
// ─── Phase 2: Quick Test, Logs, System Info ────────────────────────────────
function view _quick _test ( token , chat _id , msg _id ) {
let text = "🩺 <b>Быстрая диагностика</b>\n\n" ;
let conn = api . check _connection ( ) ;
let sys = api . get _system _status ( ) ;
text += ( conn && conn . direct ? "✅" : "❌" ) + " Прямое соединение\n" ;
text += ( conn && conn . proxy ? "✅" : "❌" ) + " Прокси соединение\n" ;
text += ( sys && sys . singbox _running ? "✅" : "❌" ) + " sing-box процесс\n" ;
text += ( sys && sys . tachyon _running ? "✅" : "❌" ) + " Tachyon сервис\n" ;
text += ( sys && sys . watchdog _running ? "✅" : "❌" ) + " Watchdog\n" ;
let nft = command _capture ( command _from _args ( [ "/usr/sbin/nft" , "list" , "tables" ] ) ) ;
text += ( nft && nft . status == 0 && match ( nft . output || "" , /ip tachyon/ ) ) ? "✅" : "❌" ;
text += " nftables правила\n" ;
let dns _ok = false ;
try {
let dns _res = command _capture ( command _from _args ( [ "nslookup" , "google.com" , "127.0.0.1" ] ) ) ;
dns _ok = dns _res && dns _res . status == 0 ;
} catch ( e ) { }
text += ( dns _ok ? "✅" : "❌" ) + " DNS на роутере\n" ;
if ( sys && sys . pause _remaining > 0 ) {
text += "\n⏸ Пауза активна: " + as _string ( sys . pause _remaining ) + " сек." ;
}
let keyboard = [
[ { text : "🔄 Повторить" , callback _data : "/test" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function view _logs ( token , chat _id , msg _id , level , count ) {
level = level || "all" ;
count = int ( count || "30" ) ;
let text = "📋 <b>Логи Tachyon</b> (уровень: " + level + ", последние " + count + ")\n\n<pre>" ;
let args = [ "/sbin/logread" ] ;
let res = command _capture ( command _from _args ( args ) ) ;
if ( res && res . status == 0 && res . output ) {
let lines = split ( res . output , "\n" ) ;
let filtered = [ ] ;
for ( let line in lines ) {
if ( line == "" ) continue ;
if ( level == "error" && ! match ( line , /\[err\]|\[error\]/i ) ) continue ;
if ( level == "warn" && ! match ( line , /\[warn\]/i ) ) continue ;
if ( level == "info" && ! match ( line , /\[info\]/i ) ) continue ;
if ( match ( line , /tachyon|sing-box|watchdog/i ) ) push ( filtered , line ) ;
}
let start = length ( filtered ) - count ;
if ( start < 0 ) start = 0 ;
for ( let i = start ; i < length ( filtered ) ; i ++ ) {
text += escape _html ( filtered [ i ] ) + "\n" ;
}
if ( length ( filtered ) == 0 ) text += "Нет записей для данного уровня.\n" ;
} else {
text += "Не удалось прочитать логи.\n" ;
}
text += "</pre>" ;
let keyboard = [
[
{ text : "❌ Errors" , callback _data : "/logs error 30" } ,
{ text : "⚠️ Warns" , callback _data : "/logs warn 30" }
] ,
[
{ text : "ℹ ️ Info" , callback _data : "/logs info 30" } ,
{ text : "📋 All" , callback _data : "/logs all 30" }
] ,
[ { text : "🔄 Обновить" , callback _data : "/logs " + level + " " + as _string ( count ) } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function view _system _info ( token , chat _id , msg _id ) {
let text = "ℹ ️ <b>Информация о системе</b>\n\n" ;
let res = command _capture ( command _from _args ( [ "/usr/lib/tachyon/diagnostics/runtime.uc" , "get-system-info" ] ) ) ;
if ( res && res . status == 0 && res . output ) {
try {
let info = json ( res . output ) ;
text += "📱 Устройство: <code>" + as _string ( info . device _model || "N/A" ) + "</code>\n" ;
text += "💻 OpenWrt: <code>" + as _string ( info . openwrt _version || "N/A" ) + "</code>\n\n" ;
text += "🔧 Tachyon: <code>" + as _string ( info . tachyon _version || "N/A" ) + "</code>\n" ;
text += "📱 LuCI App: <code>" + as _string ( info . luci _app _version || "N/A" ) + "</code>\n\n" ;
text += "📦 sing-box: <code>" + as _string ( info . sing _box _version || "N/A" ) + "</code>\n" ;
if ( info . sing _box _extended ) text += " Extended: ✅\n" ;
if ( info . sing _box _tiny ) text += " Tiny: ✅\n" ;
if ( info . sing _box _tailscale ) text += " Tailscale: ✅\n" ;
text += "\n" ;
if ( info . zapret _installed == "1" ) text += "🛡 Zapret: <code>" + as _string ( info . zapret _version || "?" ) + "</code>\n" ;
if ( info . zapret2 _installed == "1" ) text += "🛡 Zapret2: <code>" + as _string ( info . zapret2 _version || "?" ) + "</code>\n" ;
if ( info . byedpi _installed == "1" ) text += "🛡 ByeDPI: <code>" + as _string ( info . byedpi _version || "?" ) + "</code>\n" ;
} catch ( e ) {
text += "Ошибка чтения информации: " + e ;
}
} else {
text += "❌ Не удалось получить информацию о системе." ;
}
let keyboard = [
[ { text : "🔄 Обновить" , callback _data : "/info" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
// ─── Phase 3: Connections, Help ────────────────────────────────────────────
function view _connections ( token , chat _id , msg _id , page ) {
page = int ( page || 0 ) ;
let data = api . get _clash _connections ( ) ;
let text = "🔗 <b>Активные подключения</b>\n\n" ;
if ( ! data || ! data . connections || length ( data . connections ) == 0 ) {
text += "Нет активных подключений." ;
let keyboard = [
[ { text : "🔄 Обновить" , callback _data : "/connections" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
return ;
}
text += "📥 Всего скачано: <code>" + format _bytes ( data . downloadTotal ) + "</code>\n" ;
text += "📤 Всего отдано: <code>" + format _bytes ( data . uploadTotal ) + "</code>\n" ;
text += "🔗 Соединений: <code>" + length ( data . connections ) + "</code>\n\n" ;
let per _page = 8 ;
let total = length ( data . connections ) ;
let start = page * per _page ;
let end = start + per _page ;
if ( end > total ) end = total ;
for ( let i = start ; i < end ; i ++ ) {
let c = data . connections [ i ] ;
let metadata = c . metadata || { } ;
let proto = metadata . type || "?" ;
let dest = metadata . destinationIP || "?" ;
let local = metadata . sourceIP || "?" ;
let chain = "" ;
if ( c . chain && length ( c . chain ) > 0 ) chain = c . chain [ length ( c . chain ) - 1 ] ;
let dl = format _bytes ( c . download ) ;
let ul = format _bytes ( c . upload ) ;
text += "• <code>" + escape _html ( proto ) + "</code> " + escape _html ( local ) + " → " + escape _html ( dest ) + "\n" ;
text += " ↳ " + escape _html ( chain ) + " 📥" + dl + " 📤" + ul + "\n" ;
}
let total _pages = ( total + per _page - 1 ) / per _page ;
let keyboard = [ ] ;
if ( total _pages > 1 ) {
let nav = [ ] ;
if ( page > 0 ) push ( nav , { text : "◀️ Prev" , callback _data : "/connections " + as _string ( page - 1 ) } ) ;
push ( nav , { text : as _string ( page + 1 ) + "/" + as _string ( int ( total _pages ) ) , callback _data : "/noop" } ) ;
if ( end < total ) push ( nav , { text : "▶️ Next" , callback _data : "/connections " + as _string ( page + 1 ) } ) ;
push ( keyboard , nav ) ;
}
push ( keyboard , [ { text : "🔄 Обновить" , callback _data : "/connections" } ] ) ;
push ( keyboard , [ { text : "❌ Закрыть все" , callback _data : "/close_connections" } ] ) ;
push ( keyboard , [ { text : "⬅️ Назад" , callback _data : "/menu" } ] ) ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function view _help ( token , chat _id , msg _id ) {
let text = "📖 <b>Справка по командам</b>\n\n" +
"<b>Основные:</b>\n" +
"/status — Статус системы\n" +
"/runtime — Статистика трафика\n" +
"/outbounds — Прокси серверы\n" +
"/sections — Секции маршрутизации\n" +
"/devices — Устройства в сети\n" +
"/instances — Live серверы\n\n" +
"<b>Диагностика:</b>\n" +
"/speed — Тест скорости\n" +
"/ping — Задержка до серверов\n" +
"/test — Быстрая диагностика\n" +
"/doctor — Полная диагностика\n" +
"/logs — Просмотр логов\n" +
"/info — Информация о системе\n" +
"/connections — Активные подключения\n\n" +
"<b>Управление:</b>\n" +
"/restart — Перезапуск роутера\n" +
"/backup — Бэкап конфига\n" +
"/close_connections — Закрыть все соединения\n" +
"/check_updates — Проверить обновления\n\n" +
"<b>Настройка:</b>\n" +
"/settings — Все настройки\n" +
"/dns_presets — DNS пресеты\n" +
"/help — Эта справка" ;
let keyboard = [ [ { text : "⬅️ Меню" , callback _data : "/menu" } ] ] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
// ─── Phase 4: Quiet Hours, Rule Test, Export ───────────────────────────────
function view _quiet _hours ( token , chat _id , msg _id ) {
let c = uci _core . cursor ( ) ;
c . load ( CONFIG _NAME ) ;
let s = c . get _all ( CONFIG _NAME , "telegram" ) ;
let enabled = option ( s , "quiet_hours_enabled" , "0" ) == "1" ;
let start _hr = option ( s , "quiet_hours_start" , "23" ) ;
let end _hr = option ( s , "quiet_hours_end" , "7" ) ;
let text = "🔕 <b>Тихие часы</b>\n\n" +
"Статус: " + ( enabled ? "🟢 Включены" : "❌ Выключены" ) + "\n" +
"Начало: <code>" + start _hr + ":00</code>\n" +
"Конец: <code>" + end _hr + ":00</code>\n\n" +
"В тихие часы бот отправляет только критические уведомления." ;
let keyboard = [
[ { text : ( enabled ? "❌ Выключить" : "✅ Включить" ) , callback _data : "/qh_toggle" } ] ,
[ { text : "⏰ Начало: " + start _hr , callback _data : "/qh_start" } ] ,
[ { text : "⏰ Конец: " + end _hr , callback _data : "/qh_end" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/settings" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function handle _qh _toggle ( token , chat _id , msg _id ) {
let c = uci _core . cursor ( ) ;
c . load ( CONFIG _NAME ) ;
let s = c . get _all ( CONFIG _NAME , "telegram" ) ;
let current = option ( s , "quiet_hours_enabled" , "0" ) ;
c . set ( CONFIG _NAME , "telegram" , "quiet_hours_enabled" , current == "1" ? "0" : "1" ) ;
c . commit ( CONFIG _NAME ) ;
return view _quiet _hours ( token , chat _id , msg _id ) ;
}
function view _test _rule ( token , chat _id , msg _id , target ) {
if ( ! target ) {
set _tg _state ( chat _id , { action : "test_rule" } ) ;
return send _message ( token , chat _id , "🔍 Введите домен или IP для проверки:\n\n<i>Отправьте /cancel для отмены</i>" , "HTML" ) ;
}
let text = "🔍 <b>Проверка правила:</b> <code>" + escape _html ( target ) + "</code>\n\n" ;
let sections = api . get _sections ( ) ;
let matched = false ;
for ( let s in sections ) {
let sec = sections [ s ] ;
if ( sec [ ".type" ] == "settings" || sec [ ".type" ] == "telegram" ) continue ;
if ( sec . enabled == "0" ) continue ;
let domain _suffix = common . list _option ( sec , "domain_suffix" ) ;
let domain = common . list _option ( sec , "domain" ) ;
let ip _cidr = common . list _option ( sec , "ip_cidr" ) ;
for ( let d in domain _suffix ) {
if ( match ( target , escape _html ( d ) + "$" ) || target == d ) {
text += "✅ Совпадение: <code>" + escape _html ( sec [ ".name" ] ) + "</code> (domain_suffix)\n" ;
text += " Действие: <code>" + as _string ( sec . action || "proxy" ) + "</code>\n\n" ;
matched = true ;
}
}
for ( let d in domain ) {
if ( target == d || target == "full:" + d ) {
text += "✅ Совпадение: <code>" + escape _html ( sec [ ".name" ] ) + "</code> (domain)\n" ;
text += " Действие: <code>" + as _string ( sec . action || "proxy" ) + "</code>\n\n" ;
matched = true ;
}
}
for ( let ip in ip _cidr ) {
if ( match ( target , /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ ) && match ( ip , /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ ) ) {
text += "✅ Совпадение: <code>" + escape _html ( sec [ ".name" ] ) + "</code> (ip_cidr)\n" ;
text += " Действие: <code>" + as _string ( sec . action || "proxy" ) + "</code>\n\n" ;
matched = true ;
}
}
}
if ( ! matched ) text += "❌ Совпадений не найдено. Трафик пойдёт через default route." ;
let keyboard = [
[ { text : "🔄 Ещё раз" , callback _data : "/test_rule" } ] ,
[ { text : "⬅️ Назад" , callback _data : "/menu" } ]
] ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , text , "HTML" , keyboard ) ;
else send _message ( token , chat _id , text , "HTML" , keyboard ) ;
}
function exec _export _config ( token , chat _id , msg _id ) {
let wait _text = "📤 <b>Экспорт конфига...</b>\n" ;
if ( msg _id ) edit _message ( token , chat _id , msg _id , wait _text , "HTML" ) ;
else send _message ( token , chat _id , wait _text , "HTML" ) ;
let export _path = "/tmp/tachyon_export_" + time ( ) + ".json" ;
let res = command _capture ( command _from _args ( [ "/usr/lib/tachyon/diagnostics/runtime.uc" , "show-config" ] ) ) ;
if ( res && res . status == 0 && res . output ) {
fs . writefile ( export _path , res . output ) ;
send _document ( token , chat _id , export _path ) ;
try { fs . unlink ( export _path ) ; } catch ( e ) { }
send _message ( token , chat _id , "✅ Конфиг экспортирован.\n\n⚠️ Файл содержит чувствительные данные. Не публикуйте его." , "HTML" , [ [ { text : "⬅️ Меню" , callback _data : "/menu" } ] ] ) ;
} else {
send _message ( token , chat _id , "❌ Не удалось экспортировать конфиг." , "HTML" , [ [ { text : "⬅️ Меню" , callback _data : "/menu" } ] ] ) ;
}
}
function view _devices ( token , chat _id , msg _id ) {
let lease _file = "/tmp/dhcp.leases" ;
let data = fs . readfile ( lease _file ) ;
@@ -1322,6 +1714,29 @@ function dispatch_command(token, chat_id, text, msg_id) {
if ( cmd == "/heal" || cmd == "/ai_heal" ) return exec _ai _heal ( token , chat _id , msg _id ) ;
if ( cmd == "/qos" ) return view _qos ( token , chat _id , msg _id ) ;
if ( cmd == "/qos_toggle" ) return handle _qos _toggle ( token , chat _id , msg _id ) ;
if ( cmd == "/speed" ) return exec _speedtest ( token , chat _id , msg _id ) ;
if ( cmd == "/ping" ) return view _ping ( token , chat _id , msg _id ) ;
if ( cmd == "/test" ) return view _quick _test ( token , chat _id , msg _id ) ;
if ( cmd == "/info" ) return view _system _info ( token , chat _id , msg _id ) ;
if ( cmd == "/help" ) return view _help ( token , chat _id , msg _id ) ;
if ( match ( cmd , /^\/logs / ) ) {
let parts = split ( trim ( substr ( cmd , 6 ) ) , " " ) ;
return view _logs ( token , chat _id , msg _id , parts [ 0 ] || "all" , parts [ 1 ] || "30" ) ;
}
if ( cmd == "/logs" ) return view _logs ( token , chat _id , msg _id ) ;
if ( match ( cmd , /^\/connections / ) ) {
let page = trim ( substr ( cmd , 13 ) ) ;
return view _connections ( token , chat _id , msg _id , page ) ;
}
if ( cmd == "/connections" ) return view _connections ( token , chat _id , msg _id ) ;
if ( cmd == "/test_rule" ) return view _test _rule ( token , chat _id , msg _id ) ;
if ( cmd == "/export_config" ) return exec _export _config ( token , chat _id , msg _id ) ;
if ( cmd == "/qh" ) return view _quiet _hours ( token , chat _id , msg _id ) ;
if ( cmd == "/qh_toggle" ) return handle _qh _toggle ( token , chat _id , msg _id ) ;
if ( cmd == "/outbounds" ) return view _outbounds ( token , chat _id , msg _id ) ;
if ( match ( cmd , /^\/outbounds / ) ) {
@@ -1795,6 +2210,9 @@ function process_updates(token, admin_ids) {
}
view _sec _list ( token , chat _id , null , state . sec , state . list ) ;
}
else if ( state . action == "test_rule" ) {
view _test _rule ( token , chat _id , null , trim ( msg . text ) ) ;
}
continue ;
}
@@ -1871,16 +2289,24 @@ function worker() {
if ( cfg . enabled != "1" || ! cfg . bot _token ) return 0 ;
let commands = [
{ command : "menu" , description : "Main Menu " } ,
{ command : "status" , description : "System status " } ,
{ command : "runtime" , description : "Runtime stats " } ,
{ command : "outbounds" , description : "Proxy servers " } ,
{ command : "sections" , description : "Routing sections " } ,
{ command : "instances" , description : "Live Server Instances " } ,
{ command : "check_updates " , description : "Check component updates " } ,
{ command : "close_connections " , description : "Close All Connections " } ,
{ command : "doctor " , description : "Diagnostics " } ,
{ command : "restart " , description : "Restart router " }
{ command : "menu" , description : "Главное меню " } ,
{ command : "status" , description : "Статус системы " } ,
{ command : "runtime" , description : "Статистика трафика " } ,
{ command : "outbounds" , description : "Прокси серверы " } ,
{ command : "sections" , description : "Секции маршрутизации " } ,
{ command : "instances" , description : "Live серверы " } ,
{ command : "speed " , description : "Тест скорости " } ,
{ command : "ping " , description : "Задержка до серверов " } ,
{ command : "test " , description : "Быстрая диагностика " } ,
{ command : "logs " , description : "Просмотр логов " } ,
{ command : "info" , description : "Информация о системе" } ,
{ command : "connections" , description : "Активные подключения" } ,
{ command : "test_rule" , description : "Проверка правила" } ,
{ command : "help" , description : "Справка" } ,
{ command : "check_updates" , description : "Проверить обновления" } ,
{ command : "close_connections" , description : "Закрыть все соединения" } ,
{ command : "doctor" , description : "Диагностика" } ,
{ command : "restart" , description : "Перезапуск роутера" }
] ;
tg _request ( cfg . bot _token , "setMyCommands" , { commands : commands } ) ;