| 20 | }; |
| 21 | |
| 22 | export function fetch(url: string, options?: RequestInit): Promise<Response> { |
| 23 | if (window.__TAURI__) { |
| 24 | const { |
| 25 | signal, |
| 26 | method = "GET", |
| 27 | headers: _headers = {}, |
| 28 | body = [], |
| 29 | } = options || {}; |
| 30 | let unlisten: Function | undefined; |
| 31 | let setRequestId: Function | undefined; |
| 32 | const requestIdPromise = new Promise((resolve) => (setRequestId = resolve)); |
| 33 | const ts = new TransformStream(); |
| 34 | const writer = ts.writable.getWriter(); |
| 35 | |
| 36 | let closed = false; |
| 37 | const close = () => { |
| 38 | if (closed) return; |
| 39 | closed = true; |
| 40 | unlisten && unlisten(); |
| 41 | writer.ready.then(() => { |
| 42 | writer.close().catch((e) => console.error(e)); |
| 43 | }); |
| 44 | }; |
| 45 | |
| 46 | if (signal) { |
| 47 | signal.addEventListener("abort", () => close()); |
| 48 | } |
| 49 | // @ts-ignore 2. listen response multi times, and write to Response.body |
| 50 | window.__TAURI__.event |
| 51 | .listen("stream-response", (e: ResponseEvent) => |
| 52 | requestIdPromise.then((request_id) => { |
| 53 | const { request_id: rid, chunk, status } = e?.payload || {}; |
| 54 | if (request_id != rid) { |
| 55 | return; |
| 56 | } |
| 57 | if (chunk) { |
| 58 | writer.ready.then(() => { |
| 59 | writer.write(new Uint8Array(chunk)); |
| 60 | }); |
| 61 | } else if (status === 0) { |
| 62 | // end of body |
| 63 | close(); |
| 64 | } |
| 65 | }), |
| 66 | ) |
| 67 | .then((u: Function) => (unlisten = u)); |
| 68 | |
| 69 | const headers: Record<string, string> = { |
| 70 | Accept: "application/json, text/plain, */*", |
| 71 | "Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7", |
| 72 | "User-Agent": navigator.userAgent, |
| 73 | }; |
| 74 | for (const item of new Headers(_headers || {})) { |
| 75 | headers[item[0]] = item[1]; |
| 76 | } |
| 77 | return window.__TAURI__ |
| 78 | .invoke("stream_fetch", { |
| 79 | method: method.toUpperCase(), |