sing-box-tray/singbox_tray_plan.md

3.7 KiB

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.

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: WinINet]
    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)

  • Downloader: Use the Windows WinINet API to perform HTTP/HTTPS 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: WinINet HTTP/HTTPS client 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.