feat(singbox): поддержка составных длительностей и автоподнятие urltest idle_timeout, зеркала gh-proxy в README и расширение Knowledge Base

This commit is contained in:
Dushnilin
2026-08-16 10:56:27 +03:00
parent 7b215e5792
commit fc45498a8b
11 changed files with 816 additions and 33 deletions
+15
View File
@@ -196,6 +196,16 @@ Run the following single command in your router's SSH terminal:
sh <(wget -O - https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
```
> [!TIP]
> **Installation Mirrors (if direct access to GitHub is blocked or throttled):**
> ```bash
> # Mirror 1 (gh-proxy.com):
> sh <(wget -O - https://gh-proxy.com/raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
>
> # Mirror 2 (ghfast.top):
> sh <(wget -O - https://ghfast.top/https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
> ```
> [!NOTE]
> **Automatic Migration:** Existing configurations from **Forkop**, **Podkop Plus**, or original **Podkop** are fully compatible. The installer will automatically migrate your settings to `/etc/config/tachyon` without data loss.
@@ -207,6 +217,11 @@ To cleanly remove Tachyon, restore stock DNS, flush nftables rules, and preserve
sh <(wget -O - https://raw.githubusercontent.com/Dushnilin/tachyon/main/uninstall.sh)
```
*Via mirror gh-proxy.com:*
```bash
sh <(wget -O - https://gh-proxy.com/raw.githubusercontent.com/Dushnilin/tachyon/main/uninstall.sh)
```
**Options & Flags:**
* `-y`, `--yes` — non-interactive mode without confirmation prompts.
* `-p`, `--purge` — completely remove all files including configurations and backups.
+15
View File
@@ -196,6 +196,16 @@ curl http://192.168.1.1/cgi-bin/tachyon-agent/openapi.json
sh <(wget -O - https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
```
> [!TIP]
> **Зеркала установки (при блокировке или замедлении GitHub):**
> ```bash
> # Зеркало 1 (gh-proxy.com):
> sh <(wget -O - https://gh-proxy.com/raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
>
> # Зеркало 2 (ghfast.top):
> sh <(wget -O - https://ghfast.top/https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.sh)
> ```
> [!NOTE]
> **Автоматическая миграция:** Конфигурации от **Forkop**, **Podkop Plus** и оригинального **Podkop** полностью совместимы. Инсталлятор автоматически перенесет ваши правила в `/etc/config/tachyon` без потери данных.
@@ -207,6 +217,11 @@ sh <(wget -O - https://raw.githubusercontent.com/Dushnilin/tachyon/main/install.
sh <(wget -O - https://raw.githubusercontent.com/Dushnilin/tachyon/main/uninstall.sh)
```
*Через зеркало gh-proxy.com:*
```bash
sh <(wget -O - https://gh-proxy.com/raw.githubusercontent.com/Dushnilin/tachyon/main/uninstall.sh)
```
**Опции и флаги:**
* `-y`, `--yes` — автоматическое выполнение без интерактивного подтверждения.
* `-p`, `--purge` — полное удаление всех файлов вместе с конфигурациями и бэкапами.
@@ -0,0 +1,152 @@
# 08. Complete UCI Configuration Schema Reference
The primary configuration for Tachyon is stored at `/etc/config/tachyon` (UCI format, mode `0600`).
---
## 1. Section: `config settings 'settings'`
Global settings defining service behaviour, DNS resolution, watchdog parameters, Telegram integration, and AI Doctor.
| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` (`0`/`1`) | `1` | Master toggle for Tachyon service. |
| `log_level` | `string` | `info` | Logging verbosity: `debug`, `info`, `warn`, `error`. |
| `dns_mode` | `string` | `doh` | DNS routing mode: `direct`, `doh`, `dot`, `udp`, `hosts_only`. |
| `remote_dns_server` | `string` | `https://1.1.1.1/dns-query` | Upstream secure DNS resolver for proxied domains. |
| `direct_dns_server` | `string` | `77.88.8.8` | Fallback DNS resolver for direct / local domains. |
| `tproxy_port` | `integer` | `10080` | Local TCP/UDP transparent proxy port for sing-box. |
| `dns_port` | `integer` | `5353` | Local DNS listening port for sing-box DNS engine. |
| `clash_api_port` | `integer` | `9090` | sing-box Clash REST API controller port. |
| `clash_api_secret` | `string` | `""` | Secret token for sing-box Clash API. |
| `watchdog_interval` | `integer` | `10` | Watchdog polling interval in seconds (5–60s). |
| `memory_limit_mb` | `integer` | `0` | Dynamic `GOMEMLIMIT` cap in MB (`0` = auto 50% free RAM). |
| `enable_telegram` | `boolean` | `0` | Enable interactive Telegram management bot. |
| `telegram_token` | `string` | `""` | Telegram Bot API token from `@BotFather`. |
| `telegram_chat_id` | `string` | `""` | Allowed Admin Telegram Chat ID(s) (comma-separated). |
| `enable_ai_doctor` | `boolean` | `0` | Enable LLM AI Doctor diagnostic engine. |
| `ai_doctor_provider`| `string` | `openai` | LLM Provider: `openai`, `anthropic`, `deepseek`, `custom`. |
| `ai_doctor_model` | `string` | `""` | Model override (e.g. `gpt-4o-mini`, `claude-3-5-haiku`). |
| `ai_doctor_api_key`| `string` | `""` | API key for the chosen LLM provider. |
| `ai_doctor_custom_url`| `string` | `""` | Custom OpenAI-compatible endpoint URL (e.g. OpenRouter/Ollama). |
| `agent_api_token` | `string` | `""` | Bearer token for HTTP REST Agent API write access. |
---
## 2. Section: `config server 'name'`
Defines an individual manual proxy outbound node.
| Option | Type | Required | Description |
|---|---|---|---|
| `type` | `string` | Yes | Protocol: `vless`, `vmess`, `shadowsocks`, `trojan`, `hysteria2`, `wireguard`. |
| `server` | `string` | Yes | Remote server hostname or IPv4/IPv6 address. |
| `server_port` | `integer` | Yes | Remote server port (e.g. `443`, `8443`). |
| `uuid` | `string` | Conditional | User UUID for VLESS / VMess. |
| `password` | `string` | Conditional | Password for Shadowsocks / Trojan / Hysteria2. |
| `flow` | `string` | No | Flow control: `xtls-rprx-vision` (VLESS). |
| `security` | `string` | No | Security type: `reality`, `tls`, `none`. |
| `sni` | `string` | Conditional | Server Name Indication for TLS / Reality. |
| `pbk` | `string` | Conditional | Public Key for VLESS Reality. |
| `sid` | `string` | Conditional | Short ID for VLESS Reality (hex string). |
| `fingerprint` | `string` | No | TLS fingerprint: `chrome`, `firefox`, `safari`, `randomized`. |
| `method` | `string` | Conditional | Cipher method for Shadowsocks (e.g. `2022-blake3-aes-128-gcm`). |
---
## 3. Section: `config subscription 'name'`
Defines a remote subscription URL for automated batch node fetching.
| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` | `1` | Enable this subscription source. |
| `url` | `string` | Required | HTTPS / HTTP link to subscription (Base64, Clash, SIP002). |
| `update_interval`| `integer` | `86400` | Auto-update interval in seconds (default 24 hours). |
| `custom_user_agent`| `string` | `""` | Custom User-Agent header for subscription request. |
| `filter_keywords` | `list string` | `[]` | Include nodes matching regex/keywords. |
| `exclude_keywords`| `list string` | `[]` | Exclude nodes matching regex/keywords. |
---
## 4. Section: `config rule 'name'`
Defines a selective routing policy.
| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` | `1` | Enable this routing rule. |
| `name` | `string` | `""` | Human-readable label for UI. |
| `action` | `string` | `proxy` | Route target: `proxy`, `zapret`, `zapret2`, `byedpi`, `direct`, `hosts`. |
| `target_server` | `string` | `""` | Bound server ID or outbound tag when `action = 'proxy'`. |
| `domain_pattern` | `list string` | `[]` | List of target domains or wildcards (e.g. `*.youtube.com`). |
| `ip_cidr` | `list string` | `[]` | List of IP subnets (e.g. `104.16.0.0/12`). |
| `client_group` | `string` | `""` | Restrict this rule to a specific client device group. |
---
## 5. Section: `config hosts 'name'`
Configures static DNS overrides and remote blocklists ingestion.
| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` | `1` | Enable hosts mapping. |
| `dns_hosts` | `list string` | `[]` | Static mappings in format `domain:ip` (e.g. `example.com:1.2.3.4`). |
| `hosts_list_urls` | `list string` | `[]` | External URLs for blocklists (AdAway, StevenBlack). |
| `update_interval` | `integer` | `86400` | Auto-refresh interval in seconds. |
---
## 6. Ready-to-Use Configuration Recipes
### Recipe A: Zero-VPS Local DPI Bypass (YouTube + Discord)
```ini
config settings 'settings'
option enabled '1'
option dns_mode 'doh'
config provider 'zapret2'
option enabled '1'
option daemon_bin '/usr/bin/nfqws2'
option qnum '201'
option args_tcp '--dpi-desync=multisplit --dpi-desync-split-pos=1,midsld --dpi-desync-seqovl=1 --dpi-desync-fooling=badseq'
config rule 'youtube_discord'
option enabled '1'
option name 'YouTube & Discord Local Desync'
option action 'zapret2'
list domain_pattern 'googlevideo.com'
list domain_pattern 'youtube.com'
list domain_pattern 'ytimg.com'
list domain_pattern 'discord.com'
list domain_pattern 'discord.gg'
```
### Recipe B: Hybrid Mode (Local Desync for Media + VLESS Reality for Blocked Sites)
```ini
config server 'my_vps'
option type 'vless'
option server 'vps.example.com'
option server_port '443'
option uuid '12345678-1234-1234-1234-123456789abc'
option flow 'xtls-rprx-vision'
option security 'reality'
option sni 'yahoo.com'
option pbk 'XYZ...PUBLIC_KEY...'
option sid '1a2b3c4d'
config rule 'media_rule'
option enabled '1'
option action 'zapret2'
list domain_pattern 'youtube.com'
list domain_pattern 'googlevideo.com'
config rule 'blocked_rule'
option enabled '1'
option action 'proxy'
option target_server 'my_vps'
list domain_pattern 'instagram.com'
list domain_pattern 'twitter.com'
list domain_pattern 'x.com'
```
@@ -0,0 +1,101 @@
# 09. Telegram Bot Architecture & Management Protocol
Tachyon includes an embedded, high-performance Telegram management bot written entirely in **ucode** (`service/telegram.uc`).
---
## 1. Architectural Highlights
```mermaid
graph LR
User[Telegram Client] -->|Encrypted HTTPS| TGAPI[Telegram Bot API Servers]
TGAPI -->|Long Polling: getUpdates| Daemon[Tachyon telegram.uc Daemon]
Daemon --> Auth{Admin Chat ID Match?}
Auth -->|No| Reject[Silent Ignore / Warning]
Auth -->|Yes| Router[Command & Callback Dispatcher]
Router -->|/doctor, /ai_doctor| AIDoc[AI Doctor Engine]
Router -->|/server, /switch| SrvMgr[Server Manager]
Router -->|/restart| SvcLife[Service Lifecycle]
Router -->|/status| StateRep[State Assembler]
```
* **No Public IP or Port Forwarding Required**: Uses outbound long-polling (`getUpdates` with 30s timeout) to securely communicate through NAT/firewalls.
* **Zero Overhead Memory Footprint**: Runs as a lightweight ucode process consuming under 2 MB RAM.
* **Role-Based Access Control**: Rejects any commands from chat IDs not explicitly listed in UCI option `telegram_chat_id`.
---
## 2. Command Set Reference
| Command | Arguments | Action |
|---|---|---|
| `/start` | — | Displays main welcome card and interactive control keyboard. |
| `/status` | — | Returns real-time health card: uptime, active server, RAM usage, ping RTT. |
| `/doctor` | — | Executes Local Rule Doctor and returns offline diagnostic report. |
| `/ai_doctor`| — | Invokes AI Doctor with LLM reasoning and returns diagnosis + fix buttons. |
| `/fix` | `<fix_code>` | Applies specific automated repair code (e.g. `/fix clear_dns_cache`). |
| `/server` | — | Opens interactive server selector with inline pagination and RTT pings. |
| `/rules` | — | Shows active routing rules with 1-click toggle switches. |
| `/restart` | `[service]` | Restarts sing-box, dnsmasq, watchdog, or entire network stack. |
| `/backup` | — | Sends latest atomic configuration backup directly to Telegram chat. |
---
## 3. Inline Keyboard & Callback Query Protocol
The bot uses dynamic inline keyboards (`InlineKeyboardMarkup`) for single-tap actions without typing commands.
### 3.1. Callback Data Scheme
Callbacks follow a structured token format: `action:target:param`
```
srv:select:node_1 # Switch active proxy server to node_1
rule:toggle:youtube # Toggle routing rule 'youtube' on/off
fix:apply:clear_dns_cache# Execute repair code 'clear_dns_cache'
page:srv:2 # Navigate to page 2 of server list
```
### 3.2. Example: Server Switcher Response
```json
{
"chat_id": 123456789,
"text": "⚡ <b>Выберите активный сервер:</b>\nТекущий: <i>🇩🇪 Frankfurt VLESS (18 ms)</i>",
"parse_mode": "HTML",
"reply_markup": {
"inline_keyboard": [
[
{"text": "🇩🇪 Frankfurt (18 ms) ✅", "callback_data": "srv:select:de_1"},
{"text": "🇳🇱 Amsterdam (24 ms)", "callback_data": "srv:select:nl_1"}
],
[
{"text": "🇫🇮 Helsinki (31 ms)", "callback_data": "srv:select:fi_1"},
{"text": "🇺🇸 New York (95 ms)", "callback_data": "srv:select:us_1"}
],
[
{"text": "🔄 Замерить пинг", "callback_data": "srv:ping:all"},
{"text": "🩺 Запустить Доктора", "callback_data": "cmd:doctor"}
]
]
}
}
```
---
## 4. Configuration via CLI
```sh
# Set Bot Token
uci set tachyon.settings.enable_telegram='1'
uci set tachyon.settings.telegram_token='123456789:ABCdefGHIjklMNOpqrsTUVwxyz'
# Set Authorized Chat ID(s)
uci set tachyon.settings.telegram_chat_id='123456789'
# Commit and restart service
uci commit tachyon
/etc/init.d/tachyon restart
```
@@ -0,0 +1,76 @@
# 10. Hosts Engine, Blocklists & Smart Caching
The Hosts Engine (`components/hosts.uc`) provides automated background ingestion, normalization, deduplication, and caching of external host lists and static DNS overrides.
---
## 1. Architecture of Hosts Engine
```mermaid
graph TD
Sources[External Remote URLs: AdAway, StevenBlack, Custom] --> Downloader[HTTP Fetcher with Mirror Retry]
Static[Static dns_hosts in UCI] --> Downloader
Downloader --> Parser[Multi-Format Parser: Hosts, AdBlock, Domains]
Parser --> Deduper[Deduplication & Sorting Engine]
Deduper --> Cache[Unified Cache: /tmp/tachyon/hosts/combined.txt]
Cache --> DNSMasq[dnsmasq /etc/dnsmasq.d/tachyon-hosts.conf]
Cache --> SingboxDNS[sing-box DNS hosts rule]
```
---
## 2. Multi-Format Ingestion
The parser automatically detects and normalizes multiple common blocklist formats:
1. **Standard `/etc/hosts` format**:
```
0.0.0.0 ads.example.com
127.0.0.1 tracker.adserver.net
```
2. **Domain-only list format**:
```
malware-domain.org
telemetry.app.com
```
3. **AdBlock / DNSmasq syntax**:
```
||badsite.com^
server=/blocked.com/
address=/ads.org/0.0.0.0
```
---
## 3. GitHub Mirror Retry Resiliency
When fetching blocklists hosted on GitHub (e.g. `raw.githubusercontent.com`), access may be blocked or throttled by regional DPI.
Tachyon implements an automated fallback retry chain:
1. **Primary**: Direct HTTPS request to target URL.
2. **Mirror 1**: `https://gh-proxy.com/<original_url>`
3. **Mirror 2**: `https://ghfast.top/<original_url>`
4. **Mirror 3**: `https://ghproxy.net/<original_url>`
If direct connection fails with timeout or SSL handshake error, Tachyon transparently cycles through available mirrors before reporting an error.
---
## 4. Dedicated Hosts Routing (`action = 'hosts'`)
Tachyon supports routing sections that operate purely as DNS-overriding engines without requiring an outbound proxy association.
### Example UCI Configuration:
```ini
config rule 'adblock_section'
option enabled '1'
option name 'AdBlock & Anti-Tracker'
option action 'hosts'
list hosts_list_urls 'https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts'
list hosts_list_urls 'https://adaway.org/hosts.txt'
```
* Domains in this section are redirected directly to `0.0.0.0` or custom IPs in dnsmasq / sing-box DNS.
* Zero traffic is routed to external proxies, preserving VPS bandwidth and minimizing latency.
@@ -0,0 +1,73 @@
# 11. Troubleshooting & Field Diagnostic Manual
A comprehensive guide for diagnosing and resolving common network, proxy, and routing issues on OpenWrt routers running Tachyon.
---
## 1. Quick Emergency Recovery
If router traffic drops completely or DNS resolution is broken, use the **Emergency Native Internet Restoration** command:
```sh
tachyon restore_native_internet
```
This performs the following actions in under 200 ms:
1. Atomically drops all nftables interception tables (`nft delete table inet TachyonTable`).
2. Clears policy routing `table 100` and `ip rule` entries.
3. Restores dnsmasq to stock upstream forwarders.
4. Stops sing-box and DPI bypass daemons without rebooting the router.
---
## 2. Symptom Resolution Matrix
| Symptom | Likely Cause | Recommended Fix / Command |
|---|---|---|
| **Websites fail to open, ping to 8.8.8.8 works** | DNS loop or dnsmasq forwarder crash. | `tachyon apply_quick_fix clear_dns_cache,fix_dnsmasq` |
| **YouTube 4K buffers indefinitely** | Zapret strategy out-of-date for current ISP. | Switch Zapret v2 strategy to `multisplit` with `seqovl=1`. |
| **sing-box fails to start after config change** | Syntax error in custom outbound or invalid UUID. | Check `/var/log/tachyon_service.log` and run `tachyon doctor`. |
| **System clock desynchronized, TLS fails** | Router rebooted without RTC battery, NTP desync. | `tachyon apply_quick_fix fix_system_time` |
| **High latency or packet drop under heavy load** | Kernel `nf_conntrack` table overflow. | `tachyon apply_quick_fix flush_conntrack` |
| **VLESS Reality connection timeout** | Reality SNI domain blocked or expired short ID. | Update server SNI to accessible target (e.g. `yahoo.com`). |
| **Router runs out of RAM (OOM Crash)** | sing-box buffer explosion on low-RAM device (128 MB). | Lower `memory_limit_mb` in UCI settings (`GOMEMLIMIT=40MiB`). |
---
## 3. Diagnostic Commands Reference
```sh
# 1. Run local offline rule checks
tachyon doctor
# 2. Run AI Doctor with LLM analysis
tachyon ai_doctor
# 3. View real-time Watchdog telemetry
tachyon ai_status_full
# 4. Inspect active nftables firewall tables
nft list table inet TachyonTable
# 5. Inspect policy routing table 100
ip route show table 100
ip rule show
# 6. Stream live Tachyon system logs
logread -f -e tachyon
# 7. Check listening ports (TProxy 10080, DNS 5353, Clash 9090)
netstat -tulpn | grep -E 'sing-box|tachyon|5353|10080'
```
---
## 4. Log Inspection Paths
| Log Location | Content Description |
|---|---|
| `/var/log/tachyon_service.log` | Core service lifecycle events (start, stop, reload). |
| `/var/log/tachyon_watchdog.log` | Background supervisor health checks and loop warnings. |
| `/tmp/ai_doctor_last.json` | JSON report of the most recent AI Doctor diagnosis. |
| `/tmp/tachyon/sing-box.json` | Generated live configuration compiled for sing-box. |
| `/tmp/tachyon/hosts/combined.txt` | Consolidated deduplicated hosts list. |
@@ -0,0 +1,81 @@
# 12. ucode Programming Patterns & Conventions
A developer's guide to writing safe, high-performance, and idiomatic **ucode** modules for Tachyon on OpenWrt.
---
## 1. ucode vs JavaScript: Critical Distinctions
While ucode syntax resembles JavaScript, its runtime semantics differ significantly:
1. **Variables & Scope**:
* Always declare variables with `let` or `const`.
* Unassigned variables are `null` (not `undefined`).
2. **Arrays vs Dictionaries**:
* Arrays: `[1, 2, 3]`. Iterated with `for (let item in array)`.
* Dictionaries (Objects): `{"key": "value"}`. Iterated with `for (let key, val in dict)`.
3. **Regular Expressions**:
* Use `match(str, /regex/)` or `replace(str, /regex/g, "replacement")`.
* Global flag `/g` works with `replace()`, while `match()` returns capture groups array `[full_match, group1, ...]`.
4. **Boolean Coercion**:
* Empty strings `""`, `0`, and `null` are falsy. Everything else is truthy.
---
## 2. Mandatory Core Design Patterns
### 2.1. Atomic Configuration Writes
Never overwrite active configuration files in-place. Always write to a temporary file in `/tmp/` and atomically rename:
```ucode
let fs = require("fs");
function write_atomic(path, content) {
let tmp_path = path + ".tmp." + int(time());
let f = fs.open(tmp_path, "w");
if (!f) return false;
f.write(content);
f.close();
return fs.rename(tmp_path, path);
}
```
### 2.2. Shell Argument Quoting
When executing external shell commands, all user inputs must be quoted safely:
```ucode
function shell_quote(value) {
return "'" + replace("" + value, /'/g, "'\\''") + "'";
}
function safe_exec(cmd_args) {
let parts = [];
for (let arg in cmd_args)
push(parts, shell_quote(arg));
return system(join(" ", parts));
}
```
### 2.3. Safe Error Handling (`try-catch`)
All external library loading or file parsing must be wrapped in `try-catch` blocks to avoid unhandled script panics:
```ucode
let uci_data = null;
try {
let uci = require("uci").cursor();
uci_data = uci.get_all("tachyon", "settings");
}
catch (e) {
warn("Failed to load UCI settings: " + e + "\n");
}
```
---
## 3. Performance & Memory Optimization Guidelines
1. **Stream Large Files**: Avoid loading multi-megabyte blocklists entirely into RAM with `fs.readfile()`. Use line-by-line streaming via `fs.open()` and `f.read("line")`.
2. **Avoid Spawning Subprocesses in Loops**: Invoking `system()` or `fs.popen()` spawns a fork-exec sequence in Linux. Use native ucode functions for string manipulation and path operations whenever possible.
3. **Keep Modules Stateless**: Module files under `usr/lib/tachyon/` should export reusable pure functions or class definitions rather than maintaining mutable global state.
@@ -0,0 +1,117 @@
# 13. HTTP REST Agent API & Model Context Protocol (MCP) Specification
Tachyon provides a standardized RESTful Agent API and Model Context Protocol (MCP) integration, enabling seamless orchestration by autonomous LLM agents (ChatGPT Actions, Claude Code, Cursor, Windsurf, N8N, Dify).
---
## 1. REST API Overview
* **Base URL**: `http://<router-ip>/cgi-bin/tachyon-agent/`
* **OpenAPI Schema**: `http://<router-ip>/cgi-bin/tachyon-agent/openapi.json`
* **Content-Type**: `application/json`
---
## 2. Authentication Model
1. **Read-Only Endpoints**: Unrestricted when accessed from local LAN.
2. **Write Endpoints**: Require HTTP Authorization header:
```http
Authorization: Bearer <agent_api_token>
```
---
## 3. Endpoint Reference & Payloads
### 3.1. `GET /health`
Returns lightweight status of all core daemons.
```json
{
"status": "healthy",
"version": "1.2.85",
"uptime_seconds": 18450,
"singbox_running": true,
"watchdog_running": true,
"active_server": "Frankfurt_VLESS_Reality"
}
```
### 3.2. `GET /diagnose`
Returns Local Rule Doctor checks and suggested repair codes.
```json
{
"status": "warning",
"checks": {
"dns_loop": false,
"conntrack_full": false,
"time_desync": true,
"singbox_ok": true
},
"suggested_fixes": ["fix_system_time"]
}
```
### 3.3. `POST /ai-doctor/fix`
Applies one or more quick-fix codes.
* **Request**:
```json
{
"fix": "clear_dns_cache,start_singbox"
}
```
* **Response**:
```json
{
"success": true,
"applied_fixes": ["clear_dns_cache", "start_singbox"],
"details": "DNS cache cleared. sing-box process restarted."
}
```
---
## 4. Model Context Protocol (MCP) Tool Definitions
For MCP-compatible agents (Cursor, Claude Desktop), Tachyon exports tools via `GET /cgi-bin/tachyon-agent/tools`:
```json
[
{
"name": "tachyon_diagnose",
"description": "Run diagnostic checks on OpenWrt router network and proxy health",
"input_schema": {
"type": "object",
"properties": {}
}
},
{
"name": "tachyon_apply_fix",
"description": "Apply automated repair codes to fix router network or proxy issues",
"input_schema": {
"type": "object",
"properties": {
"fix_codes": {
"type": "string",
"description": "Comma-separated list of fix codes (e.g. clear_dns_cache,restart_singbox)"
}
},
"required": ["fix_codes"]
}
},
{
"name": "tachyon_switch_server",
"description": "Switch active proxy server node",
"input_schema": {
"type": "object",
"properties": {
"server_id": {
"type": "string",
"description": "Identifier of target proxy server"
}
},
"required": ["server_id"]
}
}
]
```
+6
View File
@@ -15,6 +15,12 @@ Welcome to the comprehensive technical knowledge base for **Tachyon**. This dire
| [**05. AI Stack & AI Doctor**](05_AI_STACK_AND_AUTONOMOUS_DOCTOR.md) | AI Doctor v2.5, Watchdog & REST Agent API | 13 Quick Fixes, Local Rule Doctor, NTP/MTU tuning, OpenAPI 3.0.3, REST API |
| [**06. Frontend LuCI Architecture**](06_FRONTEND_LUCI_TYPESCRIPT.md) | TypeScript SPA & LuCI view integration | `baseclass.extend` patch, reactive stores, live log streaming modal |
| [**07. Build & Testing Pipeline**](07_BUILD_TESTS_AND_DEPLOYMENT.md) | Compilation, testing & release workflows | `build.sh` (ipk/apk), `install.sh`, Docker CI container, vitest tests |
| [**08. UCI Configuration Schema**](08_UCI_CONFIGURATION_SCHEMA.md) | Complete `/etc/config/tachyon` reference | All UCI sections, options, validators, default values, ready recipes |
| [**09. Telegram Bot Architecture**](09_TELEGRAM_BOT_ARCHITECTURE.md) | Remote Telegram control daemon protocol | Long-polling model, inline keyboards, callback query routing, security |
| [**10. Hosts Engine & Blocklists**](10_HOSTS_ENGINE_AND_BLOCKLISTS.md) | Hosts ingestion, parsing & smart caching | `combined.txt`, multi-format parsing, GitHub mirror retry resiliency |
| [**11. Troubleshooting Manual**](11_TROUBLESHOOTING_AND_FIELD_MANUAL.md) | Field diagnostics & emergency recovery | Symptom resolution matrix, diagnostic commands, log inspection paths |
| [**12. ucode Programming Patterns**](12_UCODE_PROGRAMMING_PATTERNS.md) | Developer guidelines for OpenWrt ucode | Atomic file writes, shell quoting, libuci bindings, RAM efficiency |
| [**13. REST API & MCP Specification**](13_REST_API_AND_MCP_SPECIFICATION.md) | REST Agent API & MCP tool definitions | OpenAPI 3.0.3, Bearer Auth, OpenAI Function Calling, MCP JSON schema |
---
@@ -72,28 +72,34 @@ function ruleset_registered(config, tag_name) {
}
function duration_to_seconds(value) {
value = as_string(value);
if (value == "")
let rest = as_string(value);
if (rest == "")
return null;
if (match(value, /^[0-9]+$/) != null)
return int(value, 10);
if (match(rest, /^[0-9]+$/) != null)
return int(rest, 10);
let suffix = substr(value, length(value) - 1);
let number = substr(value, 0, length(value) - 1);
if (match(number, /^[0-9]+$/) == null)
let total = 0.0;
let multipliers = {
ns: 0.000000001,
us: 0.000001,
ms: 0.001,
s: 1,
m: 60,
h: 3600,
d: 86400
};
while (rest != "") {
let matched = match(rest, /^([0-9]+(\.[0-9]+)?)(ns|us|ms|s|m|h|d)/);
if (!matched)
return null;
let multiplier = null;
if (suffix == "s")
multiplier = 1;
else if (suffix == "m")
multiplier = 60;
else if (suffix == "h")
multiplier = 3600;
else if (suffix == "d")
multiplier = 86400;
let token = as_string(matched[0]);
total += (matched[1] * 1) * multipliers[matched[3]];
rest = substr(rest, length(token));
}
return multiplier == null ? null : int(number, 10) * multiplier;
return total <= 0 ? null : int(total + 0.5);
}
function urltest_check_interval(section, urltest_id) {
@@ -101,23 +107,22 @@ function urltest_check_interval(section, urltest_id) {
return interval != "" ? interval : "3m";
}
function legacy_urltest_idle_timeout(section, urltest_id) {
if (urltest_id != "urltest")
return "";
let settings = connections.urltest_settings(section, urltest_id);
if (type(settings) == "object" && as_string(settings[".type"] || "") == "urltest")
return "";
let interval = urltest_check_interval(section, urltest_id);
let interval_seconds = duration_to_seconds(interval);
let default_idle_seconds = duration_to_seconds(runtime_constants.URLTEST_DEFAULT_IDLE_TIMEOUT);
return interval_seconds != null && interval_seconds > default_idle_seconds ? interval : "";
}
function urltest_idle_timeout(section, urltest_id) {
let configured = connections.urltest_idle_timeout(section, urltest_id);
return configured != "" ? configured : legacy_urltest_idle_timeout(section, urltest_id);
let interval = urltest_check_interval(section, urltest_id);
let interval_seconds = duration_to_seconds(interval);
let idle_seconds = duration_to_seconds(configured != ""
? configured
: runtime_constants.URLTEST_DEFAULT_IDLE_TIMEOUT);
// sing-box refuses to start a URLTest group whose interval exceeds its
// idle_timeout, and substitutes URLTEST_DEFAULT_IDLE_TIMEOUT when the
// option is omitted. Raise the timeout to the interval instead of emitting
// a config that fails with "interval must be less or equal than idle_timeout".
if (interval_seconds != null && idle_seconds != null && interval_seconds > idle_seconds)
return interval;
return configured;
}
function supported_urltest_filter_mode(mode) {
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
WORK_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
generate_config() {
local fixture="$1"
local output="$2"
mkdir -p "${output}.section-cache"
ucode -L "$TACHYON_LIB" "$TACHYON_LIB/singbox/generator.uc" generate-config-fixture \
"$fixture" "$output" "127.0.0.1"
}
# sing-box rejects a URLTest group whose interval exceeds its idle_timeout and
# substitutes its own 30m default when the option is omitted, so the generator
# has to raise idle_timeout to the check interval whenever it would be smaller.
cat >"$WORK_DIR/children.json" <<'JSON'
{
"settings": {
".name": "settings",
".type": "settings",
"log_level": "warn"
},
"section": [
{
".name": "proxy",
".type": "section",
"enabled": "1",
"action": "proxy",
"selector_proxy_links": [
"vless://00000000-0000-4000-8000-000000000001@example.com:443?encryption=none&security=tls&sni=example.com#first",
"vless://00000000-0000-4000-8000-000000000002@example.org:443?encryption=none&security=tls&sni=example.org#second"
]
}
],
"urltest": [
{
".name": "cfg010001",
".type": "urltest",
"section": "proxy",
"name": "Hourly",
"check_interval": "1h",
"tolerance": "50",
"testing_url": "https://www.gstatic.com/generate_204",
"idle_timeout": "30m",
"interrupt_exist_connections": "1"
},
{
".name": "cfg010002",
".type": "urltest",
"section": "proxy",
"name": "Compound",
"check_interval": "1h30m",
"tolerance": "50",
"testing_url": "https://www.gstatic.com/generate_204",
"interrupt_exist_connections": "1"
},
{
".name": "cfg010003",
".type": "urltest",
"section": "proxy",
"name": "Short idle",
"check_interval": "3m",
"tolerance": "50",
"testing_url": "https://www.gstatic.com/generate_204",
"idle_timeout": "1m",
"interrupt_exist_connections": "1"
},
{
".name": "cfg010004",
".type": "urltest",
"section": "proxy",
"name": "Explicit idle",
"check_interval": "3m",
"tolerance": "50",
"testing_url": "https://www.gstatic.com/generate_204",
"idle_timeout": "45m",
"interrupt_exist_connections": "1"
},
{
".name": "cfg010005",
".type": "urltest",
"section": "proxy",
"name": "Default idle",
"check_interval": "3m",
"tolerance": "50",
"testing_url": "https://www.gstatic.com/generate_204",
"interrupt_exist_connections": "1"
}
]
}
JSON
children_output="$WORK_DIR/children-config.json"
generate_config "$WORK_DIR/children.json" "$children_output"
ucode -e '
let fs = require("fs");
let cfg = json(fs.readfile(ARGV[0]));
let groups = {};
for (let outbound in cfg.outbounds || [])
if (outbound && outbound.type == "urltest")
groups[outbound.tag] = outbound;
let expected = {
"proxy-urltest-cfg010001-out": [ "1h", "1h" ],
"proxy-urltest-cfg010002-out": [ "1h30m", "1h30m" ],
"proxy-urltest-cfg010003-out": [ "3m", "3m" ],
"proxy-urltest-cfg010004-out": [ "3m", "45m" ]
};
for (let tag, values in expected) {
let group = groups[tag];
if (!group)
die(sprintf("missing URLTest outbound %s\n", tag));
if (group.interval != values[0])
die(sprintf("%s: expected interval %s, got %s\n", tag, values[0], group.interval));
if (group.idle_timeout != values[1])
die(sprintf("%s: expected idle_timeout %s, got %s\n", tag, values[1], group.idle_timeout));
}
let relaxed = groups["proxy-urltest-cfg010005-out"];
if (!relaxed)
die("missing URLTest outbound proxy-urltest-cfg010005-out\n");
if (relaxed.idle_timeout != null)
die(sprintf("expected no idle_timeout below the sing-box default, got %s\n", relaxed.idle_timeout));
' "$children_output" || fail "URLTest child idle_timeout regression"
echo "PASS: urltest_idle_timeout test passed"