59 lines
3.7 KiB
Markdown
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.
|