HTTP add stream support (#2479)

* feat: add stream support

* feat: add stream support

* Revert "feat: add stream support"

This reverts commit 5edea81680.

* feat: add stream support

* Discard changes to pnpm-lock.yaml

* Discard changes to plugins/http/package.json

* fix(stream): change IPC packet

* fix: update stream message guest-js

* fix: return early when aborted

* fix: use InvokeResponseBody as packet

* fix: remove serde_bytes

* fix: remove reqwest response

* fix: content conversion bug

* fix: remove ReqwestResponses along with its implementations

* formatting and update changelog

* build api-iife.js

---------

Co-authored-by: Fabian-Lars <github@fabianlars.de>
This commit is contained in:
Adriel Jansen Siahaya
2025-03-09 02:45:05 +08:00
committed by GitHub
parent d37bbdef8d
commit cb38f54f4a
6 changed files with 67 additions and 51 deletions
+17 -21
View File
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
use tauri::{
async_runtime::Mutex,
command,
ipc::{CommandScope, GlobalScope},
ipc::{Channel, CommandScope, GlobalScope},
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
};
use tokio::sync::oneshot::{channel, Receiver, Sender};
@@ -22,9 +22,6 @@ use crate::{
const HTTP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
struct ReqwestResponse(reqwest::Response);
impl tauri::Resource for ReqwestResponse {}
type CancelableResponseResult = Result<reqwest::Response>;
type CancelableResponseFuture =
Pin<Box<dyn Future<Output = CancelableResponseResult> + Send + Sync>>;
@@ -181,6 +178,7 @@ pub async fn fetch<R: Runtime>(
client_config: ClientConfig,
command_scope: CommandScope<Entry>,
global_scope: GlobalScope<Entry>,
stream_channel: Channel<tauri::ipc::InvokeResponseBody>,
) -> crate::Result<ResourceId> {
let ClientConfig {
method,
@@ -314,7 +312,21 @@ pub async fn fetch<R: Runtime>(
#[cfg(feature = "tracing")]
tracing::trace!("{:?}", request);
let fut = async move { request.send().await.map_err(Into::into) };
let fut = async move {
let mut res = request.send().await?;
// send response through IPC channel
while let Some(chunk) = res.chunk().await? {
stream_channel.send(tauri::ipc::InvokeResponseBody::Raw(chunk.to_vec()))?;
}
// send empty vector when done
stream_channel.send(tauri::ipc::InvokeResponseBody::Raw(Vec::new()))?;
// return that response
Ok(res)
};
let mut resources_table = webview.resources_table();
let rid = resources_table.add_request(Box::pin(fut));
@@ -398,9 +410,6 @@ pub async fn fetch_send<R: Runtime>(
));
}
let mut resources_table = webview.resources_table();
let rid = resources_table.add(ReqwestResponse(res));
Ok(FetchResponse {
status: status.as_u16(),
status_text: status.canonical_reason().unwrap_or_default().to_string(),
@@ -410,19 +419,6 @@ pub async fn fetch_send<R: Runtime>(
})
}
#[tauri::command]
pub(crate) async fn fetch_read_body<R: Runtime>(
webview: Webview<R>,
rid: ResourceId,
) -> crate::Result<tauri::ipc::Response> {
let res = {
let mut resources_table = webview.resources_table();
resources_table.take::<ReqwestResponse>(rid)?
};
let res = Arc::into_inner(res).unwrap().0;
Ok(tauri::ipc::Response::new(res.bytes().await?.to_vec()))
}
// forbidden headers per fetch spec https://fetch.spec.whatwg.org/#terminology-headers
#[cfg(not(feature = "unsafe-headers"))]
fn is_unsafe_header(header: &HeaderName) -> bool {
+1 -2
View File
@@ -36,8 +36,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.invoke_handler(tauri::generate_handler![
commands::fetch,
commands::fetch_cancel,
commands::fetch_send,
commands::fetch_read_body,
commands::fetch_send
])
.build()
}