feat: remove curllib dependency
This commit is contained in:
parent
1c030cfa09
commit
6ea2cfd4b8
17
build.jai
17
build.jai
@ -15,22 +15,7 @@
|
|||||||
options := get_build_options(w);
|
options := get_build_options(w);
|
||||||
options.output_executable_name = "singbox_tray";
|
options.output_executable_name = "singbox_tray";
|
||||||
|
|
||||||
// Copy libcurl.dll from compiler modules to output directory
|
// No longer need to copy libcurl.dll since we use native Windows WinINet API.
|
||||||
for options.import_path {
|
|
||||||
dll_path := tprint("%Curl/windows/lib/libcurl.dll", it);
|
|
||||||
if file_exists(dll_path) {
|
|
||||||
dest_path := "libcurl.dll";
|
|
||||||
if options.output_path {
|
|
||||||
dest_path = tprint("%/libcurl.dll", options.output_path);
|
|
||||||
}
|
|
||||||
if copy_file(dll_path, dest_path) {
|
|
||||||
print("Build: Successfully copied libcurl.dll to %\n", dest_path);
|
|
||||||
} else {
|
|
||||||
print("Build Warning: Could not copy libcurl.dll to %\n", dest_path);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// options.additional_linker_arguments is a slice, so copy it to a dynamic array, append, and assign back
|
// options.additional_linker_arguments is a slice, so copy it to a dynamic array, append, and assign back
|
||||||
new_args: [..] string;
|
new_args: [..] string;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ graph TD
|
|||||||
B -->|Right Click| C[Context Menu]
|
B -->|Right Click| C[Context Menu]
|
||||||
C -->|Set URL| D[Custom Edit Dialog]
|
C -->|Set URL| D[Custom Edit Dialog]
|
||||||
C -->|Start/Stop| E[Process Manager: sing-box.exe]
|
C -->|Start/Stop| E[Process Manager: sing-box.exe]
|
||||||
C -->|Update Now| F[Auto-Update Loop: libcurl]
|
C -->|Update Now| F[Auto-Update Loop: WinINet]
|
||||||
C -->|Exit| G[Shutdown & Cleanup]
|
C -->|Exit| G[Shutdown & Cleanup]
|
||||||
F -->|Timer/Thread| F
|
F -->|Timer/Thread| F
|
||||||
```
|
```
|
||||||
@ -35,7 +35,7 @@ To avoid needing an external resource compiler (`.rc`) or complex UI libraries,
|
|||||||
- **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.
|
- **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)
|
### C. Config Downloader (Auto-Update Engine)
|
||||||
- **Curl Library**: Use the standard `Curl` module to perform HTTP requests.
|
- **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.
|
- **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.
|
- **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.
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ To avoid needing an external resource compiler (`.rc`) or complex UI libraries,
|
|||||||
|
|
||||||
1. **`main.jai`**: Core application entry point, hidden window loop, tray icon management.
|
1. **`main.jai`**: Core application entry point, hidden window loop, tray icon management.
|
||||||
2. **`dialog.jai`**: Edit-box dialog for config URL input.
|
2. **`dialog.jai`**: Edit-box dialog for config URL input.
|
||||||
3. **`updater.jai`**: Libcurl wrapper and background auto-update thread.
|
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. **`build.jai`**: Jai build script (metaprogram) to compile the app without standard console window popup (using `-subsystem windows`).
|
||||||
|
|
||||||
## 4. Key Questions & Decisions
|
## 4. Key Questions & Decisions
|
||||||
|
|||||||
82
updater.jai
82
updater.jai
@ -1,5 +1,4 @@
|
|||||||
#import "Basic";
|
#import "Basic";
|
||||||
#import "Curl";
|
|
||||||
#import "File";
|
#import "File";
|
||||||
#import "Thread";
|
#import "Thread";
|
||||||
#import "Windows";
|
#import "Windows";
|
||||||
@ -12,44 +11,65 @@ Updater_Thread_Data :: struct {
|
|||||||
stop_event: HANDLE;
|
stop_event: HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_callback :: (ptr: *u8, size: u64, nmemb: u64, userdata: *void) -> u64 #c_call {
|
|
||||||
builder := cast(*String_Builder) userdata;
|
|
||||||
push_context {
|
|
||||||
append(builder, ptr, xx nmemb);
|
|
||||||
}
|
|
||||||
return nmemb;
|
|
||||||
}
|
|
||||||
|
|
||||||
download_url :: (url: string) -> string, bool, string {
|
download_url :: (url: string) -> string, bool, string {
|
||||||
curl := curl_easy_init();
|
hInternet := InternetOpenW(
|
||||||
if !curl return "", false, "Failed to initialize Curl";
|
utf8_to_wide("SingboxTrayUpdater"),
|
||||||
defer curl_easy_cleanup(curl);
|
INTERNET_OPEN_TYPE_PRECONFIG,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if !hInternet {
|
||||||
|
return "", false, "Failed to initialize WinINet session";
|
||||||
|
}
|
||||||
|
defer InternetCloseHandle(hInternet);
|
||||||
|
|
||||||
curl_easy_setopt(curl, .URL, temp_c_string(url));
|
flags: DWORD = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
|
||||||
curl_easy_setopt(curl, .FOLLOWLOCATION, 1);
|
if starts_with(url, "https") {
|
||||||
curl_easy_setopt(curl, .TIMEOUT, 30);
|
flags |= INTERNET_FLAG_SECURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Disable SSL verification to prevent issues with missing CA cert bundles on Windows
|
hUrl := InternetOpenUrlW(
|
||||||
curl_easy_setopt(curl, .SSL_VERIFYPEER, 0);
|
hInternet,
|
||||||
curl_easy_setopt(curl, .SSL_VERIFYHOST, 0);
|
utf8_to_wide(url),
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
flags,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if !hUrl {
|
||||||
|
err := GetLastError();
|
||||||
|
return "", false, tprint("Failed to open URL (Win32 Error: %)", err);
|
||||||
|
}
|
||||||
|
defer InternetCloseHandle(hUrl);
|
||||||
|
|
||||||
|
// Query response code
|
||||||
|
response_code: DWORD;
|
||||||
|
response_code_size: DWORD = size_of(type_of(response_code));
|
||||||
|
if HttpQueryInfoW(hUrl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, *response_code, *response_code_size, null) {
|
||||||
|
if response_code != 200 {
|
||||||
|
return "", false, tprint("HTTP request failed with status code %", response_code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := GetLastError();
|
||||||
|
return "", false, tprint("Failed to query HTTP status code (Win32 Error: %)", err);
|
||||||
|
}
|
||||||
|
|
||||||
builder: String_Builder;
|
builder: String_Builder;
|
||||||
defer free_buffers(*builder);
|
defer free_buffers(*builder);
|
||||||
|
|
||||||
curl_easy_setopt(curl, .WRITEFUNCTION, write_callback);
|
buffer: [4096] u8;
|
||||||
curl_easy_setopt(curl, .WRITEDATA, *builder);
|
bytes_read: DWORD;
|
||||||
|
while true {
|
||||||
curl_code := curl_easy_perform(curl);
|
ok := InternetReadFile(hUrl, buffer.data, xx buffer.count, *bytes_read);
|
||||||
if curl_code != .OK {
|
if !ok {
|
||||||
err_msg := tprint("Curl perform failed: %", to_string(curl_easy_strerror(curl_code)));
|
err := GetLastError();
|
||||||
return "", false, err_msg;
|
return "", false, tprint("Error reading from URL (Win32 Error: %)", err);
|
||||||
}
|
}
|
||||||
|
if bytes_read == 0 {
|
||||||
response_code: int;
|
break;
|
||||||
curl_easy_getinfo(curl, .RESPONSE_CODE, *response_code);
|
}
|
||||||
if response_code != 200 {
|
append(*builder, buffer.data, xx bytes_read);
|
||||||
err_msg := tprint("HTTP request failed with status code %", response_code);
|
|
||||||
return "", false, err_msg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder_to_string(*builder), true, "";
|
return builder_to_string(*builder), true, "";
|
||||||
|
|||||||
46
win32.jai
46
win32.jai
@ -153,6 +153,52 @@ RegCloseKey :: (hKey: HKEY) -> LSTATUS #foreign advapi32;
|
|||||||
|
|
||||||
InternetSetOptionW :: (hInternet: HANDLE, dwOption: DWORD, lpBuffer: *void, dwBufferLength: DWORD) -> BOOL #foreign wininet;
|
InternetSetOptionW :: (hInternet: HANDLE, dwOption: DWORD, lpBuffer: *void, dwBufferLength: DWORD) -> BOOL #foreign wininet;
|
||||||
|
|
||||||
|
HINTERNET :: *void;
|
||||||
|
|
||||||
|
INTERNET_OPEN_TYPE_PRECONFIG :: 0;
|
||||||
|
INTERNET_FLAG_RELOAD :: 0x80000000;
|
||||||
|
INTERNET_FLAG_SECURE :: 0x00800000;
|
||||||
|
INTERNET_FLAG_NO_CACHE_WRITE :: 0x04000000;
|
||||||
|
|
||||||
|
HTTP_QUERY_STATUS_CODE :: 19;
|
||||||
|
HTTP_QUERY_FLAG_NUMBER :: 0x20000000;
|
||||||
|
|
||||||
|
InternetOpenW :: (
|
||||||
|
lpszAgent: LPCWSTR,
|
||||||
|
dwAccessType: DWORD,
|
||||||
|
lpszProxy: LPCWSTR,
|
||||||
|
lpszProxyBypass: LPCWSTR,
|
||||||
|
dwFlags: DWORD
|
||||||
|
) -> HINTERNET #foreign wininet;
|
||||||
|
|
||||||
|
InternetOpenUrlW :: (
|
||||||
|
hInternet: HINTERNET,
|
||||||
|
lpszUrl: LPCWSTR,
|
||||||
|
lpszHeaders: LPCWSTR,
|
||||||
|
dwHeadersLength: DWORD,
|
||||||
|
dwFlags: DWORD,
|
||||||
|
dwContext: u64
|
||||||
|
) -> HINTERNET #foreign wininet;
|
||||||
|
|
||||||
|
InternetReadFile :: (
|
||||||
|
hFile: HINTERNET,
|
||||||
|
lpBuffer: *void,
|
||||||
|
dwNumberOfBytesToRead: DWORD,
|
||||||
|
lpdwNumberOfBytesRead: *DWORD
|
||||||
|
) -> BOOL #foreign wininet;
|
||||||
|
|
||||||
|
InternetCloseHandle :: (
|
||||||
|
hInternet: HINTERNET
|
||||||
|
) -> BOOL #foreign wininet;
|
||||||
|
|
||||||
|
HttpQueryInfoW :: (
|
||||||
|
hRequest: HINTERNET,
|
||||||
|
dwInfoLevel: DWORD,
|
||||||
|
lpBuffer: *void,
|
||||||
|
lpdwBufferLength: *DWORD,
|
||||||
|
lpdwIndex: *DWORD
|
||||||
|
) -> BOOL #foreign wininet;
|
||||||
|
|
||||||
wcslen :: (str: *u16) -> int {
|
wcslen :: (str: *u16) -> int {
|
||||||
len := 0;
|
len := 0;
|
||||||
while str[len] != 0 {
|
while str[len] != 0 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user