@zappdev/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/dist/zapp-cli.js +9471 -0
- package/native/src/app/app.zc +490 -0
- package/native/src/event/event.zc +24 -0
- package/native/src/event/events.zc +70 -0
- package/native/src/platform/darwin/backend.zc +923 -0
- package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
- package/native/src/platform/darwin/bootstrap.zc +9 -0
- package/native/src/platform/darwin/engine_jsc.zc +86 -0
- package/native/src/platform/darwin/engine_qjs.zc +92 -0
- package/native/src/platform/darwin/platform.zc +156 -0
- package/native/src/platform/darwin/webview.zc +550 -0
- package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
- package/native/src/platform/darwin/window.zc +1223 -0
- package/native/src/platform/darwin/worker/common.zc +223 -0
- package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
- package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
- package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
- package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
- package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
- package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
- package/native/src/platform/darwin/worker/dispatch.zc +55 -0
- package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
- package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
- package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
- package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
- package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
- package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
- package/native/src/platform/darwin/worker/jsc.zc +670 -0
- package/native/src/platform/darwin/worker/mod.zc +30 -0
- package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
- package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
- package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
- package/native/src/platform/darwin/worker/qjs.zc +1053 -0
- package/native/src/platform/darwin/worker/timers.zc +149 -0
- package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
- package/native/src/platform/platform.zc +64 -0
- package/native/src/platform/shared/log.zc +156 -0
- package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
- package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
- package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
- package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
- package/native/src/platform/shared/worker_registry.zc +206 -0
- package/native/src/platform/window.zc +446 -0
- package/native/src/platform/windows/backend.zc +452 -0
- package/native/src/platform/windows/backend_bootstrap.zc +9 -0
- package/native/src/platform/windows/bootstrap.zc +9 -0
- package/native/src/platform/windows/engine_qjs.zc +60 -0
- package/native/src/platform/windows/platform.zc +387 -0
- package/native/src/platform/windows/webview.zc +1175 -0
- package/native/src/platform/windows/webview_bootstrap.zc +9 -0
- package/native/src/platform/windows/window.zc +1271 -0
- package/native/src/platform/windows/worker/common.zc +409 -0
- package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
- package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
- package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
- package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
- package/native/src/platform/windows/worker/core/url_core.zc +216 -0
- package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
- package/native/src/platform/windows/worker/dispatch.zc +34 -0
- package/native/src/platform/windows/worker/mod.zc +46 -0
- package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
- package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
- package/native/src/platform/windows/worker/qjs.zc +1049 -0
- package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
- package/native/src/platform/worker.zc +8 -0
- package/native/src/service/service.zc +228 -0
- package/native/vendor/quickjs-ng/.gitattributes +4 -0
- package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
- package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
- package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
- package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
- package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
- package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
- package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
- package/native/vendor/quickjs-ng/.gitmodules +5 -0
- package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
- package/native/vendor/quickjs-ng/LICENSE +24 -0
- package/native/vendor/quickjs-ng/Makefile +149 -0
- package/native/vendor/quickjs-ng/amalgam.js +53 -0
- package/native/vendor/quickjs-ng/api-test.c +927 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
- package/native/vendor/quickjs-ng/ctest.c +17 -0
- package/native/vendor/quickjs-ng/cutils.h +2013 -0
- package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
- package/native/vendor/quickjs-ng/dtoa.c +1619 -0
- package/native/vendor/quickjs-ng/dtoa.h +87 -0
- package/native/vendor/quickjs-ng/examples/fib.c +67 -0
- package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
- package/native/vendor/quickjs-ng/examples/hello.js +1 -0
- package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
- package/native/vendor/quickjs-ng/examples/meson.build +17 -0
- package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
- package/native/vendor/quickjs-ng/examples/point.c +154 -0
- package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
- package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
- package/native/vendor/quickjs-ng/fuzz.c +51 -0
- package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/native/vendor/quickjs-ng/gen/hello.c +53 -0
- package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
- package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
- package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
- package/native/vendor/quickjs-ng/libregexp.c +2687 -0
- package/native/vendor/quickjs-ng/libregexp.h +98 -0
- package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
- package/native/vendor/quickjs-ng/libunicode.c +1746 -0
- package/native/vendor/quickjs-ng/libunicode.h +126 -0
- package/native/vendor/quickjs-ng/list.h +107 -0
- package/native/vendor/quickjs-ng/lre-test.c +73 -0
- package/native/vendor/quickjs-ng/meson.build +684 -0
- package/native/vendor/quickjs-ng/meson_options.txt +6 -0
- package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
- package/native/vendor/quickjs-ng/qjs.c +748 -0
- package/native/vendor/quickjs-ng/qjsc.c +673 -0
- package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
- package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
- package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
- package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
- package/native/vendor/quickjs-ng/quickjs.c +60259 -0
- package/native/vendor/quickjs-ng/quickjs.h +1419 -0
- package/native/vendor/quickjs-ng/repl.js +1927 -0
- package/native/vendor/quickjs-ng/run-test262.c +2417 -0
- package/native/vendor/quickjs-ng/standalone.js +129 -0
- package/native/vendor/quickjs-ng/tests/assert.js +49 -0
- package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
- package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
- package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
- package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
- package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
- package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
- package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
- package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
- package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
- package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
- package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
- package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
- package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
- package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
- package/native/vendor/quickjs-ng/tests/empty.js +0 -0
- package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
- package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
- package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
- package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
- package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
- package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
- package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
- package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
- package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
- package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
- package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
- package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
- package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
- package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
- package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
- package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
- package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
- package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
- package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
- package/native/vendor/quickjs-ng/tests.conf +14 -0
- package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
- package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
- package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/native/vendor/quickjs-ng/update-version.sh +32 -0
- package/native/vendor/webview2/include/WebView2.h +60636 -0
- package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
- package/package.json +33 -0
- package/src/backend.ts +139 -0
- package/src/build-config.ts +87 -0
- package/src/build.ts +276 -0
- package/src/common.ts +195 -0
- package/src/config.ts +89 -0
- package/src/dev.ts +164 -0
- package/src/generate.ts +200 -0
- package/src/icons.ts +116 -0
- package/src/init.ts +190 -0
- package/src/package.ts +150 -0
- package/src/zapp-cli.ts +263 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// Win32-native WebSocket using WinHTTP WebSocket APIs.
|
|
2
|
+
// Mirrors the interface of darwin/worker/core/websocket_core.zc.
|
|
3
|
+
|
|
4
|
+
//> windows: link: -lwinhttp
|
|
5
|
+
|
|
6
|
+
raw {
|
|
7
|
+
#ifdef _WIN32
|
|
8
|
+
#include <windows.h>
|
|
9
|
+
#include <winhttp.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
|
|
14
|
+
typedef void (*zapp_ws_event_fn)(
|
|
15
|
+
const char* ws_id,
|
|
16
|
+
const char* event_type,
|
|
17
|
+
const char* json_payload,
|
|
18
|
+
void* user_data
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Per-connection state
|
|
22
|
+
typedef struct {
|
|
23
|
+
char ws_id[64];
|
|
24
|
+
HINTERNET session;
|
|
25
|
+
HINTERNET connection;
|
|
26
|
+
HINTERNET websocket;
|
|
27
|
+
zapp_ws_event_fn callback;
|
|
28
|
+
void* user_data;
|
|
29
|
+
HANDLE thread;
|
|
30
|
+
volatile int closed;
|
|
31
|
+
} ZappWsConn;
|
|
32
|
+
|
|
33
|
+
#define ZAPP_WS_MAX 64
|
|
34
|
+
static ZappWsConn zapp_ws_conns[ZAPP_WS_MAX] = {0};
|
|
35
|
+
static int zapp_ws_id_counter = 1;
|
|
36
|
+
static CRITICAL_SECTION zapp_ws_lock;
|
|
37
|
+
static int zapp_ws_lock_init = 0;
|
|
38
|
+
|
|
39
|
+
static void zapp_ws_ensure_init(void) {
|
|
40
|
+
if (!zapp_ws_lock_init) {
|
|
41
|
+
InitializeCriticalSection(&zapp_ws_lock);
|
|
42
|
+
zapp_ws_lock_init = 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static ZappWsConn* zapp_ws_find(const char* ws_id) {
|
|
47
|
+
if (!ws_id) return NULL;
|
|
48
|
+
for (int i = 0; i < ZAPP_WS_MAX; i++) {
|
|
49
|
+
if (zapp_ws_conns[i].ws_id[0] && strcmp(zapp_ws_conns[i].ws_id, ws_id) == 0)
|
|
50
|
+
return &zapp_ws_conns[i];
|
|
51
|
+
}
|
|
52
|
+
return NULL;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static ZappWsConn* zapp_ws_alloc(void) {
|
|
56
|
+
for (int i = 0; i < ZAPP_WS_MAX; i++) {
|
|
57
|
+
if (!zapp_ws_conns[i].ws_id[0]) return &zapp_ws_conns[i];
|
|
58
|
+
}
|
|
59
|
+
return NULL;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static void zapp_ws_fire(ZappWsConn* c, const char* event_type, const char* json_payload) {
|
|
63
|
+
if (!c || !c->callback) return;
|
|
64
|
+
c->callback(c->ws_id, event_type, json_payload ? json_payload : "{}", c->user_data);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static char* zapp_ws_escape_json_string(const char* s) {
|
|
68
|
+
if (!s) return _strdup("");
|
|
69
|
+
size_t slen = strlen(s);
|
|
70
|
+
size_t cap = slen * 2 + 1;
|
|
71
|
+
char* out = (char*)malloc(cap);
|
|
72
|
+
size_t j = 0;
|
|
73
|
+
for (size_t i = 0; i < slen; i++) {
|
|
74
|
+
if (j + 6 >= cap) { cap *= 2; out = (char*)realloc(out, cap); }
|
|
75
|
+
char ch = s[i];
|
|
76
|
+
if (ch == '"') { out[j++] = '\\'; out[j++] = '"'; }
|
|
77
|
+
else if (ch == '\\') { out[j++] = '\\'; out[j++] = '\\'; }
|
|
78
|
+
else if (ch == '\n') { out[j++] = '\\'; out[j++] = 'n'; }
|
|
79
|
+
else if (ch == '\r') { out[j++] = '\\'; out[j++] = 'r'; }
|
|
80
|
+
else if (ch == '\t') { out[j++] = '\\'; out[j++] = 't'; }
|
|
81
|
+
else out[j++] = ch;
|
|
82
|
+
}
|
|
83
|
+
out[j] = '\0';
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Receive loop running on a dedicated thread
|
|
88
|
+
static DWORD WINAPI zapp_ws_receive_thread(LPVOID param) {
|
|
89
|
+
ZappWsConn* c = (ZappWsConn*)param;
|
|
90
|
+
BYTE buf[65536];
|
|
91
|
+
DWORD bytesRead = 0;
|
|
92
|
+
WINHTTP_WEB_SOCKET_BUFFER_TYPE bufType;
|
|
93
|
+
|
|
94
|
+
while (!c->closed && c->websocket) {
|
|
95
|
+
DWORD err = WinHttpWebSocketReceive(c->websocket, buf, sizeof(buf) - 1, &bytesRead, &bufType);
|
|
96
|
+
if (err != NO_ERROR) {
|
|
97
|
+
if (!c->closed) {
|
|
98
|
+
char errJson[256];
|
|
99
|
+
snprintf(errJson, sizeof(errJson),
|
|
100
|
+
"{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Receive error: %lu\"}",
|
|
101
|
+
c->ws_id, err);
|
|
102
|
+
zapp_ws_fire(c, "error", errJson);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (bufType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE) {
|
|
108
|
+
USHORT statusCode = 0;
|
|
109
|
+
BYTE reasonBuf[256] = {0};
|
|
110
|
+
DWORD reasonLen = 0;
|
|
111
|
+
WinHttpWebSocketQueryCloseStatus(c->websocket, &statusCode, reasonBuf, sizeof(reasonBuf) - 1, &reasonLen);
|
|
112
|
+
reasonBuf[reasonLen] = '\0';
|
|
113
|
+
|
|
114
|
+
char* escapedReason = zapp_ws_escape_json_string((const char*)reasonBuf);
|
|
115
|
+
char closeJson[512];
|
|
116
|
+
snprintf(closeJson, sizeof(closeJson),
|
|
117
|
+
"{\"type\":\"close\",\"wsId\":\"%s\",\"code\":%d,\"reason\":\"%s\",\"wasClean\":true}",
|
|
118
|
+
c->ws_id, (int)statusCode, escapedReason);
|
|
119
|
+
free(escapedReason);
|
|
120
|
+
zapp_ws_fire(c, "close", closeJson);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (bufType == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE ||
|
|
125
|
+
bufType == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE) {
|
|
126
|
+
buf[bytesRead] = '\0';
|
|
127
|
+
char* escaped = zapp_ws_escape_json_string((const char*)buf);
|
|
128
|
+
size_t jsonLen = strlen(escaped) + 128 + strlen(c->ws_id);
|
|
129
|
+
char* msgJson = (char*)malloc(jsonLen);
|
|
130
|
+
snprintf(msgJson, jsonLen,
|
|
131
|
+
"{\"type\":\"message\",\"wsId\":\"%s\",\"data\":\"%s\",\"binary\":false}",
|
|
132
|
+
c->ws_id, escaped);
|
|
133
|
+
free(escaped);
|
|
134
|
+
zapp_ws_fire(c, "message", msgJson);
|
|
135
|
+
free(msgJson);
|
|
136
|
+
} else if (bufType == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE ||
|
|
137
|
+
bufType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE) {
|
|
138
|
+
// Build a JSON array of bytes
|
|
139
|
+
size_t arrCap = bytesRead * 4 + 64 + strlen(c->ws_id) + 64;
|
|
140
|
+
char* msgJson = (char*)malloc(arrCap);
|
|
141
|
+
int off = snprintf(msgJson, arrCap,
|
|
142
|
+
"{\"type\":\"message\",\"wsId\":\"%s\",\"data\":[", c->ws_id);
|
|
143
|
+
for (DWORD i = 0; i < bytesRead; i++) {
|
|
144
|
+
if (i > 0) off += snprintf(msgJson + off, arrCap - off, ",");
|
|
145
|
+
off += snprintf(msgJson + off, arrCap - off, "%u", (unsigned)buf[i]);
|
|
146
|
+
}
|
|
147
|
+
off += snprintf(msgJson + off, arrCap - off, "],\"binary\":true}");
|
|
148
|
+
zapp_ws_fire(c, "message", msgJson);
|
|
149
|
+
free(msgJson);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Connect. Returns wsId C string (caller must free), or NULL on failure.
|
|
156
|
+
static char* zapp_core_ws_connect(const char* url_str, const char** protocols, int protocol_count,
|
|
157
|
+
zapp_ws_event_fn callback, void* user_data) {
|
|
158
|
+
zapp_ws_ensure_init();
|
|
159
|
+
if (!url_str || !callback) return NULL;
|
|
160
|
+
|
|
161
|
+
// Parse URL: ws://host:port/path or wss://host:port/path
|
|
162
|
+
int secure = 0;
|
|
163
|
+
const char* hostStart = url_str;
|
|
164
|
+
if (strncmp(url_str, "wss://", 6) == 0) { hostStart = url_str + 6; secure = 1; }
|
|
165
|
+
else if (strncmp(url_str, "ws://", 5) == 0) { hostStart = url_str + 5; }
|
|
166
|
+
else return NULL;
|
|
167
|
+
|
|
168
|
+
char host[256] = {0};
|
|
169
|
+
INTERNET_PORT port = secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
|
|
170
|
+
const char* slash = strchr(hostStart, '/');
|
|
171
|
+
const char* colon = strchr(hostStart, ':');
|
|
172
|
+
if (colon && (!slash || colon < slash)) {
|
|
173
|
+
size_t hlen = (size_t)(colon - hostStart);
|
|
174
|
+
if (hlen >= sizeof(host)) return NULL;
|
|
175
|
+
memcpy(host, hostStart, hlen);
|
|
176
|
+
port = (INTERNET_PORT)atoi(colon + 1);
|
|
177
|
+
} else if (slash) {
|
|
178
|
+
size_t hlen = (size_t)(slash - hostStart);
|
|
179
|
+
if (hlen >= sizeof(host)) return NULL;
|
|
180
|
+
memcpy(host, hostStart, hlen);
|
|
181
|
+
} else {
|
|
182
|
+
strncpy(host, hostStart, sizeof(host) - 1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const char* pathStr = slash ? slash : "/";
|
|
186
|
+
wchar_t wHost[256], wPath[1024];
|
|
187
|
+
MultiByteToWideChar(CP_UTF8, 0, host, -1, wHost, 256);
|
|
188
|
+
MultiByteToWideChar(CP_UTF8, 0, pathStr, -1, wPath, 1024);
|
|
189
|
+
|
|
190
|
+
HINTERNET session = WinHttpOpen(L"Zapp/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
|
|
191
|
+
if (!session) return NULL;
|
|
192
|
+
|
|
193
|
+
HINTERNET connection = WinHttpConnect(session, wHost, port, 0);
|
|
194
|
+
if (!connection) { WinHttpCloseHandle(session); return NULL; }
|
|
195
|
+
|
|
196
|
+
DWORD flags = secure ? WINHTTP_FLAG_SECURE : 0;
|
|
197
|
+
HINTERNET request = WinHttpOpenRequest(connection, L"GET", wPath, NULL, NULL, NULL, flags);
|
|
198
|
+
if (!request) { WinHttpCloseHandle(connection); WinHttpCloseHandle(session); return NULL; }
|
|
199
|
+
|
|
200
|
+
// Add subprotocol header if requested
|
|
201
|
+
if (protocols && protocol_count > 0) {
|
|
202
|
+
size_t headerLen = 64;
|
|
203
|
+
for (int i = 0; i < protocol_count; i++) {
|
|
204
|
+
if (protocols[i]) headerLen += strlen(protocols[i]) + 2;
|
|
205
|
+
}
|
|
206
|
+
char* header = (char*)malloc(headerLen);
|
|
207
|
+
int off = snprintf(header, headerLen, "Sec-WebSocket-Protocol: ");
|
|
208
|
+
for (int i = 0; i < protocol_count; i++) {
|
|
209
|
+
if (protocols[i]) {
|
|
210
|
+
if (i > 0) off += snprintf(header + off, headerLen - off, ", ");
|
|
211
|
+
off += snprintf(header + off, headerLen - off, "%s", protocols[i]);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
wchar_t wHeader[1024];
|
|
215
|
+
MultiByteToWideChar(CP_UTF8, 0, header, -1, wHeader, 1024);
|
|
216
|
+
WinHttpAddRequestHeaders(request, wHeader, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD);
|
|
217
|
+
free(header);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Upgrade to WebSocket
|
|
221
|
+
if (!WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0)) {
|
|
222
|
+
WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
|
|
223
|
+
return NULL;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0) ||
|
|
227
|
+
!WinHttpReceiveResponse(request, NULL)) {
|
|
228
|
+
WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
|
|
229
|
+
return NULL;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
HINTERNET websocket = WinHttpWebSocketCompleteUpgrade(request, 0);
|
|
233
|
+
WinHttpCloseHandle(request);
|
|
234
|
+
if (!websocket) {
|
|
235
|
+
WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
|
|
236
|
+
return NULL;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
EnterCriticalSection(&zapp_ws_lock);
|
|
240
|
+
ZappWsConn* c = zapp_ws_alloc();
|
|
241
|
+
if (!c) {
|
|
242
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
243
|
+
WinHttpWebSocketClose(websocket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, NULL, 0);
|
|
244
|
+
WinHttpCloseHandle(websocket); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
|
|
245
|
+
return NULL;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
snprintf(c->ws_id, sizeof(c->ws_id), "ws-%d", zapp_ws_id_counter++);
|
|
249
|
+
c->session = session;
|
|
250
|
+
c->connection = connection;
|
|
251
|
+
c->websocket = websocket;
|
|
252
|
+
c->callback = callback;
|
|
253
|
+
c->user_data = user_data;
|
|
254
|
+
c->closed = 0;
|
|
255
|
+
c->thread = CreateThread(NULL, 0, zapp_ws_receive_thread, c, 0, NULL);
|
|
256
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
257
|
+
|
|
258
|
+
// Fire open event
|
|
259
|
+
char openJson[128];
|
|
260
|
+
snprintf(openJson, sizeof(openJson), "{\"type\":\"open\",\"wsId\":\"%s\"}", c->ws_id);
|
|
261
|
+
zapp_ws_fire(c, "open", openJson);
|
|
262
|
+
|
|
263
|
+
return _strdup(c->ws_id);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static void zapp_core_ws_send_text(const char* ws_id, const char* text) {
|
|
267
|
+
if (!ws_id || !text) return;
|
|
268
|
+
EnterCriticalSection(&zapp_ws_lock);
|
|
269
|
+
ZappWsConn* c = zapp_ws_find(ws_id);
|
|
270
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
271
|
+
if (!c || c->closed || !c->websocket) return;
|
|
272
|
+
|
|
273
|
+
DWORD len = (DWORD)strlen(text);
|
|
274
|
+
DWORD err = WinHttpWebSocketSend(c->websocket,
|
|
275
|
+
WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, (PVOID)text, len);
|
|
276
|
+
if (err != NO_ERROR) {
|
|
277
|
+
char errJson[256];
|
|
278
|
+
snprintf(errJson, sizeof(errJson),
|
|
279
|
+
"{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Send failed: %lu\"}",
|
|
280
|
+
ws_id, err);
|
|
281
|
+
zapp_ws_fire(c, "error", errJson);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static void zapp_core_ws_send_binary(const char* ws_id, const uint8_t* bytes, size_t len) {
|
|
286
|
+
if (!ws_id || !bytes || len == 0) return;
|
|
287
|
+
EnterCriticalSection(&zapp_ws_lock);
|
|
288
|
+
ZappWsConn* c = zapp_ws_find(ws_id);
|
|
289
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
290
|
+
if (!c || c->closed || !c->websocket) return;
|
|
291
|
+
|
|
292
|
+
DWORD err = WinHttpWebSocketSend(c->websocket,
|
|
293
|
+
WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, (PVOID)bytes, (DWORD)len);
|
|
294
|
+
if (err != NO_ERROR) {
|
|
295
|
+
char errJson[256];
|
|
296
|
+
snprintf(errJson, sizeof(errJson),
|
|
297
|
+
"{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Binary send failed: %lu\"}",
|
|
298
|
+
ws_id, err);
|
|
299
|
+
zapp_ws_fire(c, "error", errJson);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
static void zapp_core_ws_close(const char* ws_id, int code, const char* reason) {
|
|
304
|
+
if (!ws_id) return;
|
|
305
|
+
|
|
306
|
+
EnterCriticalSection(&zapp_ws_lock);
|
|
307
|
+
ZappWsConn* c = zapp_ws_find(ws_id);
|
|
308
|
+
if (!c || c->closed) {
|
|
309
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
c->closed = 1;
|
|
313
|
+
LeaveCriticalSection(&zapp_ws_lock);
|
|
314
|
+
|
|
315
|
+
if (c->websocket) {
|
|
316
|
+
DWORD reasonLen = reason ? (DWORD)strlen(reason) : 0;
|
|
317
|
+
WinHttpWebSocketClose(c->websocket, (USHORT)code, reason ? (PVOID)reason : NULL, reasonLen);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Fire close event
|
|
321
|
+
char* escapedReason = zapp_ws_escape_json_string(reason ? reason : "");
|
|
322
|
+
char closeJson[512];
|
|
323
|
+
snprintf(closeJson, sizeof(closeJson),
|
|
324
|
+
"{\"type\":\"close\",\"wsId\":\"%s\",\"code\":%d,\"reason\":\"%s\",\"wasClean\":true}",
|
|
325
|
+
ws_id, code, escapedReason);
|
|
326
|
+
free(escapedReason);
|
|
327
|
+
zapp_ws_fire(c, "close", closeJson);
|
|
328
|
+
|
|
329
|
+
// Wait for receive thread to exit
|
|
330
|
+
if (c->thread) {
|
|
331
|
+
WaitForSingleObject(c->thread, 2000);
|
|
332
|
+
CloseHandle(c->thread);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Cleanup handles
|
|
336
|
+
if (c->websocket) WinHttpCloseHandle(c->websocket);
|
|
337
|
+
if (c->connection) WinHttpCloseHandle(c->connection);
|
|
338
|
+
if (c->session) WinHttpCloseHandle(c->session);
|
|
339
|
+
|
|
340
|
+
memset(c, 0, sizeof(ZappWsConn));
|
|
341
|
+
}
|
|
342
|
+
#endif
|
|
343
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
raw {
|
|
2
|
+
#if defined(_WIN32) && defined(ZAPP_WORKER_ENGINE_QJS)
|
|
3
|
+
#include <windows.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
extern void zapp_windows_webview_eval_all(const char* js_utf8);
|
|
9
|
+
extern char* zapp_escape_js_string(const char* raw);
|
|
10
|
+
|
|
11
|
+
void zapp_dispatch_worker_to_webviews(const char* kind, const char* worker_id, const char* payload_json) {
|
|
12
|
+
if (kind == NULL || worker_id == NULL) return;
|
|
13
|
+
if (payload_json == NULL) payload_json = "null";
|
|
14
|
+
|
|
15
|
+
char* escaped_kind = zapp_escape_js_string(kind);
|
|
16
|
+
char* escaped_wid = zapp_escape_js_string(worker_id);
|
|
17
|
+
|
|
18
|
+
size_t jsLen = strlen(escaped_kind) + strlen(escaped_wid) + strlen(payload_json) + 256;
|
|
19
|
+
char* js = (char*)malloc(jsLen);
|
|
20
|
+
snprintf(js, jsLen,
|
|
21
|
+
"(function(){var b=globalThis[Symbol.for('zapp.bridge')];"
|
|
22
|
+
"if(b&&typeof b.dispatchWorkerBridge==='function'){"
|
|
23
|
+
"b.dispatchWorkerBridge('%s','%s',%s);}})();",
|
|
24
|
+
escaped_kind, escaped_wid, payload_json
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
zapp_windows_webview_eval_all(js);
|
|
28
|
+
|
|
29
|
+
free(js);
|
|
30
|
+
free(escaped_kind);
|
|
31
|
+
free(escaped_wid);
|
|
32
|
+
}
|
|
33
|
+
#endif
|
|
34
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Windows worker: QuickJS engine, opt-in via ZAPP_WORKER_ENGINE_QJS define.
|
|
2
|
+
|
|
3
|
+
import "../../worker.zc";
|
|
4
|
+
|
|
5
|
+
@cfg(ZAPP_WORKER_ENGINE_QJS)
|
|
6
|
+
import "./qjs.zc";
|
|
7
|
+
|
|
8
|
+
@cfg(ZAPP_WORKER_ENGINE_QJS)
|
|
9
|
+
fn windows_platform_bind_runtime(app: App*) -> void {
|
|
10
|
+
raw {
|
|
11
|
+
#ifdef _WIN32
|
|
12
|
+
zapp_ui_thread_id = GetCurrentThreadId();
|
|
13
|
+
#endif
|
|
14
|
+
}
|
|
15
|
+
(WindowsWorkerQjs{}).bind_runtime(app);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@cfg(ZAPP_WORKER_ENGINE_QJS)
|
|
19
|
+
fn windows_platform_handle_worker_bridge(app: App*, action: string, payload: string) -> void {
|
|
20
|
+
(WindowsWorkerQjs{}).handle_bridge(app, action, payload);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// No-op stubs when QJS workers are disabled
|
|
24
|
+
@cfg(not(ZAPP_WORKER_ENGINE_QJS))
|
|
25
|
+
fn windows_platform_bind_runtime(app: App*) -> void {
|
|
26
|
+
let _a = app;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@cfg(not(ZAPP_WORKER_ENGINE_QJS))
|
|
30
|
+
fn windows_platform_handle_worker_bridge(app: App*, action: string, payload: string) -> void {
|
|
31
|
+
let _a = app; let _b = action; let _c = payload;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
raw {
|
|
35
|
+
#if defined(_WIN32) && !defined(ZAPP_WORKER_ENGINE_QJS)
|
|
36
|
+
// Stubs for worker functions referenced outside the worker module
|
|
37
|
+
void zapp_windows_reset_owner_workers(const char* owner_id) { (void)owner_id; }
|
|
38
|
+
void zapp_windows_reset_all_workers(void) {}
|
|
39
|
+
void zapp_windows_send_event_to_js(void* app_ptr, char* name, char* payload) {
|
|
40
|
+
(void)app_ptr; (void)name; (void)payload;
|
|
41
|
+
}
|
|
42
|
+
void zapp_windows_worker_dispatch_sync_result(const char* worker_id, const char* payload_json) {
|
|
43
|
+
(void)worker_id; (void)payload_json;
|
|
44
|
+
}
|
|
45
|
+
#endif
|
|
46
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// QJS wrapper for fetch on Windows. Delegates to core/fetch_core.zc.
|
|
2
|
+
|
|
3
|
+
raw {
|
|
4
|
+
#if defined(_WIN32) && defined(ZAPP_WORKER_ENGINE_QJS)
|
|
5
|
+
#include "quickjs.h"
|
|
6
|
+
#include "quickjs-libc.h"
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
extern void* zapp_windows_qjs_get_context(const char* workerId);
|
|
11
|
+
extern void zapp_windows_qjs_dispatch(void (*func)(void*), void* data);
|
|
12
|
+
extern void zapp_windows_qjs_drain_jobs(void* ctx, const char* label);
|
|
13
|
+
extern void zapp_log_worker(int level, int window_id, int worker_id, const char* message);
|
|
14
|
+
#ifndef ZAPP_LOG_ERROR
|
|
15
|
+
#define ZAPP_LOG_ERROR 0
|
|
16
|
+
#define ZAPP_LOG_WARN 1
|
|
17
|
+
#define ZAPP_LOG_INFO 2
|
|
18
|
+
#define ZAPP_LOG_DEBUG 3
|
|
19
|
+
#define ZAPP_LOG_TRACE 4
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
typedef struct {
|
|
24
|
+
char workerId[128];
|
|
25
|
+
JSContext* creatingCtx;
|
|
26
|
+
JSValue savedResolve;
|
|
27
|
+
JSValue savedReject;
|
|
28
|
+
zapp_fetch_response_t* response;
|
|
29
|
+
char* error;
|
|
30
|
+
} ZappFetchResultData;
|
|
31
|
+
|
|
32
|
+
static void zapp_fetch_deliver_on_qjs(void* data) {
|
|
33
|
+
ZappFetchResultData* d = (ZappFetchResultData*)data;
|
|
34
|
+
|
|
35
|
+
void* ctx_ptr = zapp_windows_qjs_get_context(d->workerId);
|
|
36
|
+
if (!ctx_ptr || (JSContext*)ctx_ptr != d->creatingCtx) {
|
|
37
|
+
JS_FreeValue(d->creatingCtx, d->savedResolve);
|
|
38
|
+
JS_FreeValue(d->creatingCtx, d->savedReject);
|
|
39
|
+
if (d->error) free(d->error);
|
|
40
|
+
if (d->response) {
|
|
41
|
+
free(d->response->status_text);
|
|
42
|
+
for (int i = 0; i < d->response->header_count; i++) {
|
|
43
|
+
free(d->response->header_keys[i]);
|
|
44
|
+
free(d->response->header_values[i]);
|
|
45
|
+
}
|
|
46
|
+
free(d->response->header_keys);
|
|
47
|
+
free(d->response->header_values);
|
|
48
|
+
free(d->response->body);
|
|
49
|
+
free(d->response->body_base64);
|
|
50
|
+
free(d->response);
|
|
51
|
+
}
|
|
52
|
+
free(d);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
JSContext* ctx = (JSContext*)ctx_ptr;
|
|
57
|
+
|
|
58
|
+
if (d->error) {
|
|
59
|
+
JSValue args[1] = { JS_NewString(ctx, d->error) };
|
|
60
|
+
JSValue ret = JS_Call(ctx, d->savedReject, JS_UNDEFINED, 1, args);
|
|
61
|
+
if (JS_IsException(ret)) {
|
|
62
|
+
JSValue exc = JS_GetException(ctx);
|
|
63
|
+
const char* s = JS_ToCString(ctx, exc);
|
|
64
|
+
if (s) { zapp_log_worker(ZAPP_LOG_ERROR, -1, -1, s); JS_FreeCString(ctx, s); }
|
|
65
|
+
JS_FreeValue(ctx, exc);
|
|
66
|
+
}
|
|
67
|
+
JS_FreeValue(ctx, ret);
|
|
68
|
+
JS_FreeValue(ctx, args[0]);
|
|
69
|
+
} else if (d->response) {
|
|
70
|
+
zapp_fetch_response_t* r = d->response;
|
|
71
|
+
JSValue resObj = JS_NewObject(ctx);
|
|
72
|
+
JS_SetPropertyStr(ctx, resObj, "status", JS_NewInt32(ctx, r->status));
|
|
73
|
+
JS_SetPropertyStr(ctx, resObj, "statusText",
|
|
74
|
+
JS_NewString(ctx, r->status_text ? r->status_text : ""));
|
|
75
|
+
|
|
76
|
+
JSValue headersObj = JS_NewObject(ctx);
|
|
77
|
+
for (int i = 0; i < r->header_count; i++) {
|
|
78
|
+
if (r->header_keys[i] && r->header_values[i]) {
|
|
79
|
+
JS_SetPropertyStr(ctx, headersObj, r->header_keys[i],
|
|
80
|
+
JS_NewString(ctx, r->header_values[i]));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
JS_SetPropertyStr(ctx, resObj, "headers", headersObj);
|
|
84
|
+
|
|
85
|
+
if (r->body)
|
|
86
|
+
JS_SetPropertyStr(ctx, resObj, "body", JS_NewString(ctx, r->body));
|
|
87
|
+
else if (r->body_base64)
|
|
88
|
+
JS_SetPropertyStr(ctx, resObj, "body_base64", JS_NewString(ctx, r->body_base64));
|
|
89
|
+
else
|
|
90
|
+
JS_SetPropertyStr(ctx, resObj, "body", JS_NewString(ctx, ""));
|
|
91
|
+
|
|
92
|
+
JSValue args[1] = { resObj };
|
|
93
|
+
JSValue ret = JS_Call(ctx, d->savedResolve, JS_UNDEFINED, 1, args);
|
|
94
|
+
if (JS_IsException(ret)) {
|
|
95
|
+
JSValue exc = JS_GetException(ctx);
|
|
96
|
+
const char* s = JS_ToCString(ctx, exc);
|
|
97
|
+
if (s) { zapp_log_worker(ZAPP_LOG_ERROR, -1, -1, s); JS_FreeCString(ctx, s); }
|
|
98
|
+
JS_FreeValue(ctx, exc);
|
|
99
|
+
}
|
|
100
|
+
JS_FreeValue(ctx, ret);
|
|
101
|
+
JS_FreeValue(ctx, resObj);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
JS_FreeValue(ctx, d->savedResolve);
|
|
105
|
+
JS_FreeValue(ctx, d->savedReject);
|
|
106
|
+
zapp_windows_qjs_drain_jobs(ctx, "fetch");
|
|
107
|
+
|
|
108
|
+
if (d->error) free(d->error);
|
|
109
|
+
if (d->response) {
|
|
110
|
+
free(d->response->status_text);
|
|
111
|
+
for (int i = 0; i < d->response->header_count; i++) {
|
|
112
|
+
free(d->response->header_keys[i]);
|
|
113
|
+
free(d->response->header_values[i]);
|
|
114
|
+
}
|
|
115
|
+
free(d->response->header_keys);
|
|
116
|
+
free(d->response->header_values);
|
|
117
|
+
free(d->response->body);
|
|
118
|
+
free(d->response->body_base64);
|
|
119
|
+
free(d->response);
|
|
120
|
+
}
|
|
121
|
+
free(d);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static void zapp_fetch_completion_handler(zapp_fetch_response_t* response, const char* error, void* userdata) {
|
|
125
|
+
ZappFetchResultData* d = (ZappFetchResultData*)userdata;
|
|
126
|
+
|
|
127
|
+
if (error) {
|
|
128
|
+
d->error = _strdup(error);
|
|
129
|
+
d->response = NULL;
|
|
130
|
+
} else if (response) {
|
|
131
|
+
// Deep copy the response since it's freed after callback returns
|
|
132
|
+
zapp_fetch_response_t* copy = (zapp_fetch_response_t*)calloc(1, sizeof(zapp_fetch_response_t));
|
|
133
|
+
copy->status = response->status;
|
|
134
|
+
copy->status_text = response->status_text ? _strdup(response->status_text) : NULL;
|
|
135
|
+
copy->header_count = response->header_count;
|
|
136
|
+
if (copy->header_count > 0) {
|
|
137
|
+
copy->header_keys = (char**)calloc(copy->header_count, sizeof(char*));
|
|
138
|
+
copy->header_values = (char**)calloc(copy->header_count, sizeof(char*));
|
|
139
|
+
for (int i = 0; i < copy->header_count; i++) {
|
|
140
|
+
copy->header_keys[i] = response->header_keys[i] ? _strdup(response->header_keys[i]) : NULL;
|
|
141
|
+
copy->header_values[i] = response->header_values[i] ? _strdup(response->header_values[i]) : NULL;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
copy->body = response->body ? _strdup(response->body) : NULL;
|
|
145
|
+
copy->body_base64 = response->body_base64 ? _strdup(response->body_base64) : NULL;
|
|
146
|
+
d->response = copy;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
zapp_windows_qjs_dispatch(zapp_fetch_deliver_on_qjs, d);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static JSValue qjs_bridge_fetch(JSContext* ctx, JSValue this_val, int argc, JSValue* argv, int magic, JSValue* func_data) {
|
|
153
|
+
(void)this_val; (void)magic;
|
|
154
|
+
if (argc < 4) return JS_UNDEFINED;
|
|
155
|
+
|
|
156
|
+
const char* worker_id = JS_ToCString(ctx, func_data[0]);
|
|
157
|
+
if (!worker_id) return JS_UNDEFINED;
|
|
158
|
+
|
|
159
|
+
const char* urlStr = JS_ToCString(ctx, argv[0]);
|
|
160
|
+
if (!urlStr) { JS_FreeCString(ctx, worker_id); return JS_UNDEFINED; }
|
|
161
|
+
|
|
162
|
+
JSValue optionsVal = argv[1];
|
|
163
|
+
JSValue resolveVal = argv[2];
|
|
164
|
+
JSValue rejectVal = argv[3];
|
|
165
|
+
|
|
166
|
+
// Extract method
|
|
167
|
+
char* method_copy = NULL;
|
|
168
|
+
if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
|
|
169
|
+
JSValue m = JS_GetPropertyStr(ctx, optionsVal, "method");
|
|
170
|
+
if (!JS_IsUndefined(m)) {
|
|
171
|
+
const char* ms = JS_ToCString(ctx, m);
|
|
172
|
+
if (ms) { method_copy = _strdup(ms); JS_FreeCString(ctx, ms); }
|
|
173
|
+
}
|
|
174
|
+
JS_FreeValue(ctx, m);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Extract headers
|
|
178
|
+
char** hKeys = NULL;
|
|
179
|
+
char** hVals = NULL;
|
|
180
|
+
int hCount = 0;
|
|
181
|
+
if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
|
|
182
|
+
JSValue headersVal = JS_GetPropertyStr(ctx, optionsVal, "headers");
|
|
183
|
+
if (JS_IsObject(headersVal)) {
|
|
184
|
+
JSPropertyEnum* tab = NULL;
|
|
185
|
+
uint32_t len = 0;
|
|
186
|
+
if (JS_GetOwnPropertyNames(ctx, &tab, &len, headersVal, JS_GPN_STRING_MASK) == 0 && len > 0) {
|
|
187
|
+
hCount = (int)len;
|
|
188
|
+
hKeys = (char**)calloc(hCount, sizeof(char*));
|
|
189
|
+
hVals = (char**)calloc(hCount, sizeof(char*));
|
|
190
|
+
for (uint32_t i = 0; i < len; i++) {
|
|
191
|
+
const char* key = JS_AtomToCString(ctx, tab[i].atom);
|
|
192
|
+
JSValue val = JS_GetProperty(ctx, headersVal, tab[i].atom);
|
|
193
|
+
const char* valStr = JS_ToCString(ctx, val);
|
|
194
|
+
hKeys[i] = key ? _strdup(key) : NULL;
|
|
195
|
+
hVals[i] = valStr ? _strdup(valStr) : NULL;
|
|
196
|
+
if (key) JS_FreeCString(ctx, key);
|
|
197
|
+
if (valStr) JS_FreeCString(ctx, valStr);
|
|
198
|
+
JS_FreeValue(ctx, val);
|
|
199
|
+
JS_FreeAtom(ctx, tab[i].atom);
|
|
200
|
+
}
|
|
201
|
+
js_free(ctx, tab);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
JS_FreeValue(ctx, headersVal);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Extract body
|
|
208
|
+
char* body_copy = NULL;
|
|
209
|
+
size_t body_len = 0;
|
|
210
|
+
if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
|
|
211
|
+
JSValue bodyVal = JS_GetPropertyStr(ctx, optionsVal, "body");
|
|
212
|
+
if (!JS_IsUndefined(bodyVal) && !JS_IsNull(bodyVal) && JS_IsString(bodyVal)) {
|
|
213
|
+
const char* bs = JS_ToCString(ctx, bodyVal);
|
|
214
|
+
if (bs) { body_copy = _strdup(bs); body_len = strlen(body_copy); JS_FreeCString(ctx, bs); }
|
|
215
|
+
}
|
|
216
|
+
JS_FreeValue(ctx, bodyVal);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Create result data with saved JS callbacks
|
|
220
|
+
ZappFetchResultData* resultData = (ZappFetchResultData*)calloc(1, sizeof(ZappFetchResultData));
|
|
221
|
+
strncpy(resultData->workerId, worker_id, sizeof(resultData->workerId) - 1);
|
|
222
|
+
resultData->creatingCtx = ctx;
|
|
223
|
+
resultData->savedResolve = JS_DupValue(ctx, resolveVal);
|
|
224
|
+
resultData->savedReject = JS_DupValue(ctx, rejectVal);
|
|
225
|
+
|
|
226
|
+
char* urlCopy = _strdup(urlStr);
|
|
227
|
+
JS_FreeCString(ctx, urlStr);
|
|
228
|
+
JS_FreeCString(ctx, worker_id);
|
|
229
|
+
|
|
230
|
+
zapp_core_fetch_execute(
|
|
231
|
+
urlCopy, method_copy,
|
|
232
|
+
(const char**)hKeys, (const char**)hVals, hCount,
|
|
233
|
+
body_copy, body_len,
|
|
234
|
+
resultData->workerId,
|
|
235
|
+
zapp_fetch_completion_handler, resultData
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
free(urlCopy);
|
|
239
|
+
free(method_copy);
|
|
240
|
+
for (int i = 0; i < hCount; i++) { free(hKeys[i]); free(hVals[i]); }
|
|
241
|
+
free(hKeys); free(hVals);
|
|
242
|
+
free(body_copy);
|
|
243
|
+
|
|
244
|
+
return JS_UNDEFINED;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
void zapp_windows_qjs_fetch_install(JSContext* ctx, JSValue bridge, const char* worker_id) {
|
|
248
|
+
JSValue wIdVal = JS_NewString(ctx, worker_id);
|
|
249
|
+
JSValue funcData[1] = { wIdVal };
|
|
250
|
+
JS_SetPropertyStr(ctx, bridge, "fetch",
|
|
251
|
+
JS_NewCFunctionData(ctx, qjs_bridge_fetch, 4, 0, 1, funcData));
|
|
252
|
+
JS_FreeValue(ctx, wIdVal);
|
|
253
|
+
}
|
|
254
|
+
#endif
|
|
255
|
+
}
|