From 3f9f3363596b5817308bfb9f3261fee07a71ee8f Mon Sep 17 00:00:00 2001 From: Robert Long Date: Thu, 5 Dec 2024 09:51:15 -0800 Subject: [PATCH] Clean up channel.onmessage when stream terminates --- plugins/http/api-iife.js | 2 +- plugins/http/guest-js/index.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/http/api-iife.js b/plugins/http/api-iife.js index 8d6dbfbbc8..bc80ea21b4 100644 --- a/plugins/http/api-iife.js +++ b/plugins/http/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_PLUGIN_HTTP__=function(e){"use strict";function t(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}function r(e,t,r,n,s){if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,r),r}var n,s,o;"function"==typeof SuppressedError&&SuppressedError;const a="__TAURI_TO_IPC_KEY__";class i{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),s.set(this,0),o.set(this,{}),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:a})=>{if(a===t(this,s,"f")){r(this,s,a+1),t(this,n,"f").call(this,e);const i=Object.keys(t(this,o,"f"));if(i.length>0){let e=a+1;for(const r of i.sort()){if(parseInt(r)!==e)break;{const s=t(this,o,"f")[r];delete t(this,o,"f")[r],t(this,n,"f").call(this,s),e+=1}}r(this,s,e)}}else t(this,o,"f")[a.toString()]=e}))}set onmessage(e){r(this,n,e)}get onmessage(){return t(this,n,"f")}[(n=new WeakMap,s=new WeakMap,o=new WeakMap,a)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[a]()}}async function c(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}const d="Request canceled";return e.fetch=async function(e,t){const r=t?.signal;if(r?.aborted)throw new Error(d);const n=t?.maxRedirections,s=t?.connectTimeout,o=t?.proxy;t&&(delete t.maxRedirections,delete t.connectTimeout,delete t.proxy);const a=t?.headers?t.headers instanceof Headers?t.headers:new Headers(t.headers):new Headers,h=new Request(e,t),f=await h.arrayBuffer(),_=0!==f.byteLength?Array.from(new Uint8Array(f)):null;for(const[e,t]of h.headers)a.get(e)||a.set(e,t);const u=(a instanceof Headers?Array.from(a.entries()):Array.isArray(a)?a:Object.entries(a)).map((([e,t])=>[e,"string"==typeof t?t:t.toString()]));if(r?.aborted)throw new Error(d);const l=await c("plugin:http|fetch",{clientConfig:{method:h.method,url:h.url,headers:u,data:_,maxRedirections:n,connectTimeout:s,proxy:o}}),w=()=>c("plugin:http|fetch_cancel",{rid:l});if(r?.aborted)throw w(),new Error(d);r?.addEventListener("abort",(()=>{w()}));const{status:p,statusText:y,url:m,headers:T,rid:g}=await c("plugin:http|fetch_send",{rid:l}),b=new ReadableStream({start(e){const t=new i;t.onmessage=t=>{const r=new Uint8Array(t);0===r.length?e.close():e.enqueue(r)};c("plugin:http|fetch_read_body",{rid:g,channel:t}).catch((t=>{console.error("error reading body",t),e.error(t)}))}}),A=new Response(b,{status:p,statusText:y});return Object.defineProperty(A,"url",{value:m}),Object.defineProperty(A,"headers",{value:new Headers(T)}),A},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_PLUGIN_HTTP__})} +if("__TAURI__"in window){var __TAURI_PLUGIN_HTTP__=function(e){"use strict";function t(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}function r(e,t,r,n,s){if("function"==typeof t?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,r),r}var n,s,o;"function"==typeof SuppressedError&&SuppressedError;const a="__TAURI_TO_IPC_KEY__";class i{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),s.set(this,0),o.set(this,{}),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:a})=>{if(a===t(this,s,"f")){r(this,s,a+1),t(this,n,"f").call(this,e);const i=Object.keys(t(this,o,"f"));if(i.length>0){let e=a+1;for(const r of i.sort()){if(parseInt(r)!==e)break;{const s=t(this,o,"f")[r];delete t(this,o,"f")[r],t(this,n,"f").call(this,s),e+=1}}r(this,s,e)}}else t(this,o,"f")[a.toString()]=e}))}set onmessage(e){r(this,n,e)}get onmessage(){return t(this,n,"f")}[(n=new WeakMap,s=new WeakMap,o=new WeakMap,a)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[a]()}}async function c(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}const d="Request canceled";return e.fetch=async function(e,t){const r=t?.signal;if(r?.aborted)throw new Error(d);const n=t?.maxRedirections,s=t?.connectTimeout,o=t?.proxy;t&&(delete t.maxRedirections,delete t.connectTimeout,delete t.proxy);const a=t?.headers?t.headers instanceof Headers?t.headers:new Headers(t.headers):new Headers,h=new Request(e,t),f=await h.arrayBuffer(),_=0!==f.byteLength?Array.from(new Uint8Array(f)):null;for(const[e,t]of h.headers)a.get(e)||a.set(e,t);const u=(a instanceof Headers?Array.from(a.entries()):Array.isArray(a)?a:Object.entries(a)).map((([e,t])=>[e,"string"==typeof t?t:t.toString()]));if(r?.aborted)throw new Error(d);const l=await c("plugin:http|fetch",{clientConfig:{method:h.method,url:h.url,headers:u,data:_,maxRedirections:n,connectTimeout:s,proxy:o}}),w=()=>c("plugin:http|fetch_cancel",{rid:l});if(r?.aborted)throw w(),new Error(d);r?.addEventListener("abort",(()=>{w()}));const{status:p,statusText:y,url:m,headers:g,rid:T}=await c("plugin:http|fetch_send",{rid:l}),b=new i,A=new ReadableStream({start(e){b.onmessage=t=>{const r=new Uint8Array(t);0===r.length?e.close():e.enqueue(r)};c("plugin:http|fetch_read_body",{rid:T,channel:b}).catch((t=>{console.error("error reading body",t),b.onmessage=()=>{},e.error(t)}))},cancel(){b.onmessage=()=>{}}}),R=new Response(A,{status:p,statusText:y});return Object.defineProperty(R,"url",{value:m}),Object.defineProperty(R,"headers",{value:new Headers(g)}),R},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_PLUGIN_HTTP__})} diff --git a/plugins/http/guest-js/index.ts b/plugins/http/guest-js/index.ts index 7d918883cb..b0be6435db 100644 --- a/plugins/http/guest-js/index.ts +++ b/plugins/http/guest-js/index.ts @@ -206,10 +206,11 @@ export async function fetch( rid }) + const channel = new Channel() + // Create ReadableStream from channel messages const stream = new ReadableStream({ start(controller) { - const channel = new Channel() channel.onmessage = (arr) => { const chunk = new Uint8Array(arr) @@ -230,8 +231,12 @@ export async function fetch( // If the promise fails, make sure the stream is closed readPromise.catch((e) => { console.error('error reading body', e) + channel.onmessage = () => {} controller.error(e) }) + }, + cancel() { + channel.onmessage = () => {} } })