sing-box-tray/singbox_tray_plan.md
2026-06-30 20:20:50 +03:00

59 lines
3.7 KiB
Markdown

# Planning: Sing-box Windows Tray Controller in Jai
We will implement a lightweight, headless Windows tray application in the **Jai** language to control the `sing-box` core.
## 1. Core Architecture
The application will run with a hidden/message-only window to remain headless, handling tray interaction, background updates, and process management.
```mermaid
graph TD
A[Main Loop / Hidden Window] --> B[System Tray Icon]
B -->|Right Click| C[Context Menu]
C -->|Set URL| D[Custom Edit Dialog]
C -->|Start/Stop| E[Process Manager: sing-box.exe]
C -->|Update Now| F[Auto-Update Loop: libcurl]
C -->|Exit| G[Shutdown & Cleanup]
F -->|Timer/Thread| F
```
## 2. Component Design
### A. Headless Window & System Tray Icon
- **Win32 Window**: We register a window class and create a hidden utility window using `CreateWindowExW`. This window serves as the message receiver.
- **Tray Icon**: We register a system tray icon via `Shell_NotifyIconW` (using `NOTIFYICONDATAW`).
- **Events**: We define a custom window message `WM_TRAY_CALLBACK` (`WM_USER + 1`). When the tray icon receives input (e.g. mouse clicks), Windows sends `WM_TRAY_CALLBACK` to our hidden window.
- **Context Menu**: On `WM_RBUTTONUP` (right click) or `WM_LBUTTONUP` (left click) over the tray icon, we load a dynamic popup menu using `CreatePopupMenu`, `AppendMenuW`, and `TrackPopupMenu`.
### B. Custom Modal Dialog (Set URL)
To avoid needing an external resource compiler (`.rc`) or complex UI libraries, we will implement a clean, lightweight modal window:
- **Dialog Window**: A popup window using `WS_POPUP | WS_CAPTION | WS_SYSMENU` centered on screen.
- **Controls**:
- A static label: "Enter Sing-box Config URL:"
- An edit control (`EDIT` window class) to input the URL.
- An OK button and a Cancel button (`BUTTON` window class).
- **Behavior**: Block interactions with other menus, read the edit text on OK, write it to a `url.txt` file, and trigger an immediate config update.
### C. Config Downloader (Auto-Update Engine)
- **Curl Library**: Use the standard `Curl` module to perform HTTP requests.
- **Storage**: Save the downloaded JSON content to `config.json` in the same directory as the executable.
- **Auto-Update Thread**: Spawn a background thread (using `Thread` module) that sleeps for a set interval (e.g., 1 hour), then downloads the URL. If the file content changes, it updates `config.json` and restarts the `sing-box` process if it was running.
### D. Process Management (`sing-box.exe`)
- **Process Spawning**: Use the standard `Process` module's `create_process` to run:
`sing-box.exe run -c config.json`
- **Job Object**: Windows processes started via `create_process` will be assigned to a Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`. This ensures `sing-box.exe` automatically shuts down when the controller application is closed.
- **Status Checking**: Use `get_process_result` with 0 timeout to check if sing-box is actively running.
## 3. Implementation Steps
1. **`main.jai`**: Core application entry point, hidden window loop, tray icon management.
2. **`dialog.jai`**: Edit-box dialog for config URL input.
3. **`updater.jai`**: Libcurl wrapper and background auto-update thread.
4. **`build.jai`**: Jai build script (metaprogram) to compile the app without standard console window popup (using `-subsystem windows`).
## 4. Key Questions & Decisions
- **Tray Icon**: Do we need a default/builtin icon? Yes, we will use a standard Windows system icon (like `IDI_APPLICATION` or `IDI_SHIELD`) so that the application works out-of-the-box without requiring an external `.ico` asset.
- **sing-box Location**: We will assume `sing-box.exe` is in the same directory as the controller. If not found there, we will search the system PATH.