mirror of
				https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
				synced 2025-11-04 16:23:41 +08:00 
			
		
		
		
	using sse: schema to fetch in App
This commit is contained in:
		
							
								
								
									
										51
									
								
								app/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								app/utils.ts
									
									
									
									
									
								
							@@ -2,8 +2,7 @@ import { useEffect, useState } from "react";
 | 
			
		||||
import { showToast } from "./components/ui-lib";
 | 
			
		||||
import Locale from "./locales";
 | 
			
		||||
import { RequestMessage } from "./client/api";
 | 
			
		||||
import { ServiceProvider, REQUEST_TIMEOUT_MS } from "./constant";
 | 
			
		||||
import { fetch as tauriFetch, ResponseType } from "@tauri-apps/api/http";
 | 
			
		||||
import { ServiceProvider } from "./constant";
 | 
			
		||||
 | 
			
		||||
export function trimTopic(topic: string) {
 | 
			
		||||
  // Fix an issue where double quotes still show in the Indonesian language
 | 
			
		||||
@@ -292,30 +291,50 @@ export function fetch(
 | 
			
		||||
  options?: Record<string, unknown>,
 | 
			
		||||
): Promise<any> {
 | 
			
		||||
  if (window.__TAURI__) {
 | 
			
		||||
    const payload = options?.body || options?.data;
 | 
			
		||||
    return tauriFetch(url, {
 | 
			
		||||
      ...options,
 | 
			
		||||
      body:
 | 
			
		||||
        payload &&
 | 
			
		||||
        ({
 | 
			
		||||
          type: "Text",
 | 
			
		||||
          payload,
 | 
			
		||||
        } as any),
 | 
			
		||||
      timeout: ((options?.timeout as number) || REQUEST_TIMEOUT_MS) / 1000,
 | 
			
		||||
      responseType:
 | 
			
		||||
        options?.responseType == "text" ? ResponseType.Text : ResponseType.JSON,
 | 
			
		||||
    } as any);
 | 
			
		||||
    const tauriUri = window.__TAURI__.convertFileSrc(url, "sse");
 | 
			
		||||
    return window.fetch(tauriUri, options).then((r) => {
 | 
			
		||||
      // 1. create response,
 | 
			
		||||
      // TODO using event to get status and statusText and headers
 | 
			
		||||
      const { status, statusText } = r;
 | 
			
		||||
      const { readable, writable } = new TransformStream();
 | 
			
		||||
      const res = new Response(readable, { status, statusText });
 | 
			
		||||
      // 2. call fetch_read_body multi times, and write to Response.body
 | 
			
		||||
      const writer = writable.getWriter();
 | 
			
		||||
      let unlisten;
 | 
			
		||||
      window.__TAURI__.event
 | 
			
		||||
        .listen("sse-response", (e) => {
 | 
			
		||||
          const { id, payload } = e;
 | 
			
		||||
          console.log("event", id, payload);
 | 
			
		||||
          writer.ready.then(() => {
 | 
			
		||||
            if (payload !== 0) {
 | 
			
		||||
              writer.write(new Uint8Array(payload));
 | 
			
		||||
            } else {
 | 
			
		||||
              writer.releaseLock();
 | 
			
		||||
              writable.close();
 | 
			
		||||
              unlisten && unlisten();
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        })
 | 
			
		||||
        .then((u) => (unlisten = u));
 | 
			
		||||
      return res;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return window.fetch(url, options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (undefined !== window) {
 | 
			
		||||
  window.tauriFetch = fetch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function adapter(config: Record<string, unknown>) {
 | 
			
		||||
  const { baseURL, url, params, ...rest } = config;
 | 
			
		||||
  const path = baseURL ? `${baseURL}${url}` : url;
 | 
			
		||||
  const fetchUrl = params
 | 
			
		||||
    ? `${path}?${new URLSearchParams(params as any).toString()}`
 | 
			
		||||
    : path;
 | 
			
		||||
  return fetch(fetchUrl as string, { ...rest, responseType: "text" });
 | 
			
		||||
  return fetch(fetchUrl as string, rest)
 | 
			
		||||
    .then((res) => res.text())
 | 
			
		||||
    .then((data) => ({ data }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function safeLocalStorage(): {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										86
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										86
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -348,9 +348,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bytes"
 | 
			
		||||
version = "1.4.0"
 | 
			
		||||
version = "1.7.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
 | 
			
		||||
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
@@ -942,9 +942,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "form_urlencoded"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
version = "1.2.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
 | 
			
		||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
]
 | 
			
		||||
@@ -970,9 +970,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-core"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
 | 
			
		||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-executor"
 | 
			
		||||
@@ -987,9 +987,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-io"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
 | 
			
		||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-lite"
 | 
			
		||||
@@ -1008,9 +1008,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-macro"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
 | 
			
		||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@@ -1019,21 +1019,21 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-sink"
 | 
			
		||||
version = "0.3.29"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
 | 
			
		||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-task"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
 | 
			
		||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-util"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
 | 
			
		||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "futures-io",
 | 
			
		||||
@@ -1555,9 +1555,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "idna"
 | 
			
		||||
version = "0.3.0"
 | 
			
		||||
version = "0.5.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
 | 
			
		||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-bidi",
 | 
			
		||||
 "unicode-normalization",
 | 
			
		||||
@@ -1986,6 +1986,9 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
 | 
			
		||||
name = "nextchat"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "reqwest",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "tauri",
 | 
			
		||||
@@ -2213,6 +2216,17 @@ dependencies = [
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "os_info"
 | 
			
		||||
version = "3.8.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "log",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "overload"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
@@ -2281,9 +2295,9 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "percent-encoding"
 | 
			
		||||
version = "2.2.0"
 | 
			
		||||
version = "2.3.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
 | 
			
		||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "phf"
 | 
			
		||||
@@ -2545,9 +2559,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "proc-macro2"
 | 
			
		||||
version = "1.0.58"
 | 
			
		||||
version = "1.0.86"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
 | 
			
		||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-ident",
 | 
			
		||||
]
 | 
			
		||||
@@ -3237,6 +3251,19 @@ dependencies = [
 | 
			
		||||
 "unicode-ident",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sys-locale"
 | 
			
		||||
version = "0.2.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "web-sys",
 | 
			
		||||
 "windows-sys 0.45.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "system-configuration"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
@@ -3385,6 +3412,7 @@ dependencies = [
 | 
			
		||||
 "objc",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "open",
 | 
			
		||||
 "os_info",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "rand 0.8.5",
 | 
			
		||||
 "raw-window-handle",
 | 
			
		||||
@@ -3397,6 +3425,7 @@ dependencies = [
 | 
			
		||||
 "serde_repr",
 | 
			
		||||
 "serialize-to-javascript",
 | 
			
		||||
 "state",
 | 
			
		||||
 "sys-locale",
 | 
			
		||||
 "tar",
 | 
			
		||||
 "tauri-macros",
 | 
			
		||||
 "tauri-runtime",
 | 
			
		||||
@@ -3889,9 +3918,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "url"
 | 
			
		||||
version = "2.3.1"
 | 
			
		||||
version = "2.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
 | 
			
		||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "form_urlencoded",
 | 
			
		||||
 "idna",
 | 
			
		||||
@@ -4316,6 +4345,15 @@ dependencies = [
 | 
			
		||||
 "windows-targets 0.48.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-sys"
 | 
			
		||||
version = "0.52.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-targets 0.52.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-targets"
 | 
			
		||||
version = "0.42.2"
 | 
			
		||||
 
 | 
			
		||||
@@ -35,8 +35,12 @@ tauri = { version = "1.5.4", features = [ "http-all",
 | 
			
		||||
    "window-start-dragging",
 | 
			
		||||
    "window-unmaximize",
 | 
			
		||||
    "window-unminimize",
 | 
			
		||||
    "linux-protocol-headers",
 | 
			
		||||
] }
 | 
			
		||||
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
 | 
			
		||||
percent-encoding = "2.3.1"
 | 
			
		||||
reqwest = "0.11.18"
 | 
			
		||||
futures-util = "0.3.30"
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,57 @@
 | 
			
		||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
 | 
			
		||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
 | 
			
		||||
 | 
			
		||||
use futures_util::{StreamExt};
 | 
			
		||||
use reqwest::Client;
 | 
			
		||||
use tauri::{ Manager};
 | 
			
		||||
use tauri::http::{ResponseBuilder};
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
  tauri::Builder::default()
 | 
			
		||||
    .plugin(tauri_plugin_window_state::Builder::default().build())
 | 
			
		||||
    .register_uri_scheme_protocol("sse", |app_handle, request| {
 | 
			
		||||
      let path = request.uri().strip_prefix("sse://localhost/").unwrap();
 | 
			
		||||
      let path = percent_encoding::percent_decode(path.as_bytes())
 | 
			
		||||
        .decode_utf8_lossy()
 | 
			
		||||
        .to_string();
 | 
			
		||||
      // println!("path : {}", path);
 | 
			
		||||
      let client = Client::new();
 | 
			
		||||
      let window = app_handle.get_window("main").unwrap();
 | 
			
		||||
      // send http request
 | 
			
		||||
      let body = reqwest::Body::from(request.body().clone());
 | 
			
		||||
      let response_future = client.request(request.method().clone(), path)
 | 
			
		||||
        .headers(request.headers().clone())
 | 
			
		||||
        .body(body).send();
 | 
			
		||||
 | 
			
		||||
      // get response and emit to client
 | 
			
		||||
      tauri::async_runtime::spawn(async move {
 | 
			
		||||
        let res = response_future.await;
 | 
			
		||||
 | 
			
		||||
        match res {
 | 
			
		||||
          Ok(res) => {
 | 
			
		||||
            let mut stream = res.bytes_stream();
 | 
			
		||||
 | 
			
		||||
            while let Some(chunk) = stream.next().await {
 | 
			
		||||
              match chunk {
 | 
			
		||||
                Ok(bytes) => {
 | 
			
		||||
                  window.emit("sse-response", bytes).unwrap();
 | 
			
		||||
                }
 | 
			
		||||
                Err(err) => {
 | 
			
		||||
                  println!("Error: {:?}", err);
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            window.emit("sse-response", 0).unwrap();
 | 
			
		||||
          }
 | 
			
		||||
          Err(err) => {
 | 
			
		||||
            println!("Error: {:?}", err);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      ResponseBuilder::new()
 | 
			
		||||
        .header("Access-Control-Allow-Origin", "*")
 | 
			
		||||
        .status(200).body("OK".into())
 | 
			
		||||
      })
 | 
			
		||||
    .run(tauri::generate_context!())
 | 
			
		||||
    .expect("error while running tauri application");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user