Просмотр исходного кода

refactor(core): improve HTTP API, closes #1098 (#1237)

Lucas Fernandes Nogueira 4 лет назад
Родитель
Сommit
a7bc472e99

+ 7 - 0
.changes/http-api-refactor.md

@@ -0,0 +1,7 @@
+---
+"api": minor
+"tauri-api": minor
+"tauri": minor
+---
+
+The HTTP API was improved with client caching and better payload and response types.

+ 188 - 117
api/src/http.ts

@@ -1,4 +1,9 @@
-import { promisified } from './tauri'
+import { invoke, promisified } from './tauri'
+
+export interface ClientOptions {
+  maxRedirections: boolean
+  connectTimeout: number
+}
 
 export enum ResponseType {
   JSON = 1,
@@ -6,13 +11,33 @@ export enum ResponseType {
   Binary = 3
 }
 
-export enum BodyType {
-  Form = 1,
-  File = 2,
-  Auto = 3
-}
+export type Part = 'string' | number[]
+
+export class Body {
+  type: string
+  payload: unknown
 
-export type Body = object | string | BinaryType
+  constructor(type: string, payload: unknown) {
+    this.type = type
+    this.payload = payload
+  }
+
+  static form(data: Record<string, Part>): Body {
+    return new Body('Form', data)
+  }
+
+  static json(data: Record<any, any>): Body {
+    return new Body('Json', data)
+  }
+
+  static text(value: string): Body {
+    return new Body('Text', value)
+  }
+
+  static bytes(bytes: number[]): Body {
+    return new Body('Bytes', bytes)
+  }
+}
 
 export type HttpVerb =
   | 'GET'
@@ -29,130 +54,176 @@ export interface HttpOptions {
   method: HttpVerb
   url: string
   headers?: Record<string, any>
-  params?: Record<string, any>
+  query?: Record<string, any>
   body?: Body
-  followRedirects: boolean
-  maxRedirections: boolean
-  connectTimeout: number
-  readTimeout: number
-  timeout: number
-  allowCompression: boolean
+  timeout?: number
   responseType?: ResponseType
-  bodyType: BodyType
 }
 
-export type PartialOptions = Omit<HttpOptions, 'method' | 'url'>
-
-/**
- * makes a HTTP request
- *
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function request<T>(options: HttpOptions): Promise<T> {
-  return await promisified({
-    module: 'Http',
-    message: {
-      cmd: 'httpRequest',
-      options: options
-    }
-  })
-}
+export type RequestOptions = Omit<HttpOptions, 'method' | 'url'>
+export type FetchOptions = Omit<HttpOptions, 'url'>
 
-/**
- * makes a GET request
- *
- * @param url request URL
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function get<T>(url: string, options: PartialOptions): Promise<T> {
-  return await request({
-    method: 'GET',
-    url,
-    ...options
-  })
+export interface Response<T> {
+  url: string
+  status: number
+  headers: Record<string, string>
+  data: T
 }
 
-/**
- * makes a POST request
- *
- * @param url request URL
- * @param body request body
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function post<T>(
-  url: string,
-  body: Body,
-  options: PartialOptions
-): Promise<T> {
-  return await request({
-    method: 'POST',
-    url,
-    body,
-    ...options
-  })
-}
+export class Client {
+  id: number
+  constructor(id: number) {
+    this.id = id
+  }
 
-/**
- * makes a PUT request
- *
- * @param url request URL
- * @param body request body
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function put<T>(
-  url: string,
-  body: Body,
-  options: PartialOptions
-): Promise<T> {
-  return await request({
-    method: 'PUT',
-    url,
-    body,
-    ...options
-  })
+  /**
+   * drops the client instance
+   */
+  drop(): void {
+    invoke({
+      module: 'Http',
+      message: {
+        cmd: 'dropClient',
+        client: this.id
+      }
+    })
+  }
+
+  /**
+   * makes a HTTP request
+   *
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async request<T>(options: HttpOptions): Promise<Response<T>> {
+    return await promisified({
+      module: 'Http',
+      message: {
+        cmd: 'httpRequest',
+        client: this.id,
+        options
+      }
+    })
+  }
+
+  /**
+   * makes a GET request
+   *
+   * @param url request URL
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async get<T>(url: string, options: RequestOptions): Promise<Response<T>> {
+    return await this.request({
+      method: 'GET',
+      url,
+      ...options
+    })
+  }
+
+  /**
+   * makes a POST request
+   *
+   * @param url request URL
+   * @param body request body
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async post<T>(
+    url: string,
+    body: Body,
+    options: RequestOptions
+  ): Promise<Response<T>> {
+    return await this.request({
+      method: 'POST',
+      url,
+      body,
+      ...options
+    })
+  }
+
+  /**
+   * makes a PUT request
+   *
+   * @param url request URL
+   * @param body request body
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async put<T>(
+    url: string,
+    body: Body,
+    options: RequestOptions
+  ): Promise<Response<T>> {
+    return await this.request({
+      method: 'PUT',
+      url,
+      body,
+      ...options
+    })
+  }
+
+  /**
+   * makes a PATCH request
+   *
+   * @param url request URL
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async patch<T>(url: string, options: RequestOptions): Promise<Response<T>> {
+    return await this.request({
+      method: 'PATCH',
+      url,
+      ...options
+    })
+  }
+
+  /**
+   * makes a DELETE request
+   *
+   * @param url request URL
+   * @param options request options
+   *
+   * @return promise resolving to the response
+   */
+  async delete<T>(
+    url: string,
+    options: RequestOptions
+  ): Promise<Response<T>> {
+    return await this.request({
+      method: 'DELETE',
+      url,
+      ...options
+    })
+  }
 }
 
-/**
- * makes a PATCH request
- *
- * @param url request URL
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function patch<T>(url: string, options: PartialOptions): Promise<T> {
-  return await request({
-    method: 'PATCH',
-    url,
-    ...options
-  })
+async function getClient(options?: ClientOptions): Promise<Client> {
+  return await promisified<number>({
+    module: 'Http',
+    message: {
+      cmd: 'createClient',
+      options
+    }
+  }).then(id => new Client(id))
 }
 
-/**
- * makes a DELETE request
- *
- * @param url request URL
- * @param options request options
- *
- * @return promise resolving to the response
- */
-async function deleteRequest<T>(
-  url: string,
-  options: PartialOptions
-): Promise<T> {
-  return await request({
-    method: 'DELETE',
+let defaultClient: Client | null = null
+
+async function fetch<T>(url: string, options?: FetchOptions): Promise<Response<T>> {
+  if (defaultClient === null) {
+    defaultClient = await getClient()
+  }
+  return await defaultClient.request({
     url,
+    method: options?.method ?? 'GET',
     ...options
   })
 }
 
-export { request, get, post, put, patch, deleteRequest as httpDelete }
+export { getClient, fetch }

+ 2 - 1
tauri-api/Cargo.toml

@@ -29,7 +29,8 @@ thiserror = "1.0.23"
 rand = "0.8"
 nfd = "0.0.4"
 tauri-dialog = "0.1.0"
-attohttpc = { version = "0.16.1", features = [ "json", "form" ] }
+reqwest = { version = "0.11", features = [ "json", "multipart" ] }
+bytes = { version = "1", features = ["serde"] }
 http = "0.2"
 tauri-utils = { version = "0.5", path = "../tauri-utils" }
 clap = { version = "=3.0.0-beta.2", optional = true }

+ 9 - 11
tauri-api/src/error.rs

@@ -19,18 +19,21 @@ pub enum Error {
   /// CLI config not set.
   #[error("CLI configuration not set on tauri.conf.json")]
   CliNotConfigured,
-  /// The HTTP response error.
-  #[error("HTTP Response Error: {0}")]
-  Response(attohttpc::StatusCode),
   /// The network error.
   #[error("Network Error: {0}")]
-  Network(#[from] attohttpc::Error),
+  Network(#[from] reqwest::Error),
   /// HTTP method error.
   #[error("{0}")]
   HttpMethod(#[from] http::method::InvalidMethod),
   /// Invalid HTTO header.
   #[error("{0}")]
-  HttpHeader(#[from] attohttpc::header::InvalidHeaderName),
+  HttpHeader(#[from] reqwest::header::InvalidHeaderName),
+  /// Failed to serialize header value as string.
+  #[error("failed to convert response header value to string")]
+  HttpHeaderToString(#[from] reqwest::header::ToStrError),
+  /// HTTP form to must be an object.
+  #[error("http form must be an object")]
+  InvalidHttpForm,
   /// Semver error.
   #[error("{0}")]
   Semver(#[from] semver::SemVerError),
@@ -44,6 +47,7 @@ pub enum Error {
   #[error("{0}")]
   Zip(#[from] zip::result::ZipError),
   /// Notification error.
+  #[cfg(feature = "notification")]
   #[error("{0}")]
   Notification(#[from] notify_rust::error::Error),
   /// failed to detect the current platform.
@@ -58,9 +62,3 @@ pub enum Error {
   #[error("shortcut error: {0}")]
   Shortcut(#[from] tauri_hotkey::Error),
 }
-
-impl From<attohttpc::StatusCode> for Error {
-  fn from(error: attohttpc::StatusCode) -> Self {
-    Self::Response(error)
-  }
-}

+ 194 - 216
tauri-api/src/http.rs

@@ -1,23 +1,111 @@
-use attohttpc::{Method, RequestBuilder};
-use http::header::HeaderName;
-use serde::Deserialize;
+use bytes::Bytes;
+use reqwest::{header::HeaderName, redirect::Policy, Method};
+use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use serde_repr::{Deserialize_repr, Serialize_repr};
-use std::{collections::HashMap, fs::File, time::Duration};
 
-#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
-#[repr(u16)]
-/// The request's body type
-pub enum BodyType {
-  /// Send request body as application/x-www-form-urlencoded
-  Form = 1,
-  /// Send request body (which is a path to a file) as application/octet-stream
-  File,
-  /// Detects the body type automatically
-  /// - if the body is a byte array, send is as bytes (application/octet-stream)
-  /// - if the body is an object or array, send it as JSON (application/json with UTF-8 charset)
-  /// - if the body is a string, send it as text (text/plain with UTF-8 charset)
-  Auto,
+use std::{collections::HashMap, path::PathBuf, time::Duration};
+
+/// Client builder.
+#[derive(Default, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ClientBuilder {
+  /// Max number of redirections to follow
+  pub max_redirections: Option<usize>,
+  /// Connect timeout in seconds for the request
+  pub connect_timeout: Option<u64>,
+}
+
+impl ClientBuilder {
+  /// Creates a new client builder with the default options.
+  pub fn new() -> Self {
+    Default::default()
+  }
+
+  /// Sets the maximum number of redirections.
+  pub fn max_redirections(mut self, max_redirections: usize) -> Self {
+    self.max_redirections = Some(max_redirections);
+    self
+  }
+
+  /// Sets the connection timeout.
+  pub fn connect_timeout(mut self, connect_timeout: u64) -> Self {
+    self.connect_timeout = Some(connect_timeout);
+    self
+  }
+
+  /// Builds the ClientOptions.
+  pub fn build(self) -> crate::Result<Client> {
+    let mut client_builder = reqwest::Client::builder();
+
+    if let Some(max_redirections) = self.max_redirections {
+      client_builder = client_builder.redirect(Policy::limited(max_redirections))
+    }
+
+    if let Some(connect_timeout) = self.connect_timeout {
+      client_builder = client_builder.connect_timeout(Duration::from_secs(connect_timeout));
+    }
+
+    let client = client_builder.build()?;
+    Ok(Client(client))
+  }
+}
+
+/// The HTTP client.
+#[derive(Clone)]
+pub struct Client(reqwest::Client);
+
+impl Client {
+  /// Executes an HTTP request
+  ///
+  /// The response will be transformed to String,
+  /// If reading the response as binary, the byte array will be serialized using serde_json
+  pub async fn send(&self, request: HttpRequestBuilder) -> crate::Result<Response> {
+    let method = Method::from_bytes(request.method.to_uppercase().as_bytes())?;
+    let mut request_builder = self.0.request(method, &request.url);
+
+    if let Some(query) = request.query {
+      request_builder = request_builder.query(&query);
+    }
+
+    if let Some(headers) = request.headers {
+      for (header, header_value) in headers.iter() {
+        request_builder =
+          request_builder.header(HeaderName::from_bytes(header.as_bytes())?, header_value);
+      }
+    }
+
+    if let Some(timeout) = request.timeout {
+      request_builder = request_builder.timeout(Duration::from_secs(timeout));
+    }
+
+    let response = if let Some(body) = request.body {
+      match body {
+        Body::Bytes(data) => request_builder.body(Bytes::from(data)).send().await?,
+        Body::Text(text) => request_builder.body(Bytes::from(text)).send().await?,
+        Body::Json(json) => request_builder.json(&json).send().await?,
+        Body::Form(form_body) => {
+          let mut form = Vec::new();
+          for (name, part) in form_body.0 {
+            match part {
+              FormPart::Bytes(bytes) => form.push((name, serde_json::to_string(&bytes)?)),
+              FormPart::File(file_path) => form.push((name, serde_json::to_string(&file_path)?)),
+              FormPart::Text(text) => form.push((name, text)),
+            }
+          }
+          request_builder.form(&form).send().await?
+        }
+      }
+    } else {
+      request_builder.send().await?
+    };
+
+    let response = response.error_for_status()?;
+    Ok(Response(
+      request.response_type.unwrap_or(ResponseType::Json),
+      response,
+    ))
+  }
 }
 
 #[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
@@ -32,106 +120,99 @@ pub enum ResponseType {
   Binary,
 }
 
+/// FormBody data types.
 #[derive(Deserialize)]
-#[serde(rename_all = "camelCase")]
-/// The configuration object of an HTTP request
-pub struct HttpRequestOptions {
-  /// The request method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE)
-  pub method: String,
-  /// The request URL
-  pub url: String,
-  /// The request query params
-  pub params: Option<HashMap<String, String>>,
-  /// The request headers
-  pub headers: Option<HashMap<String, String>>,
-  /// The request body
-  pub body: Option<Value>,
-  /// Whether to follow redirects or not
-  pub follow_redirects: Option<bool>,
-  /// Max number of redirections to follow
-  pub max_redirections: Option<u32>,
-  /// Connect timeout for the request
-  pub connect_timeout: Option<u64>,
-  /// Read timeout for the request
-  pub read_timeout: Option<u64>,
-  /// Timeout for the whole request
-  pub timeout: Option<u64>,
-  /// Whether the request will announce that it accepts compression
-  pub allow_compression: Option<bool>,
-  /// The body type (defaults to Auto)
-  pub body_type: Option<BodyType>,
-  /// The response type (defaults to Json)
-  pub response_type: Option<ResponseType>,
+#[serde(untagged)]
+pub enum FormPart {
+  /// A file path value.
+  File(PathBuf),
+  /// A string value.
+  Text(String),
+  /// A byte array value.
+  Bytes(Vec<u8>),
 }
 
-/// The builder for HttpRequestOptions.
+/// Form body definition.
+#[derive(Deserialize)]
+pub struct FormBody(HashMap<String, FormPart>);
+
+impl FormBody {
+  /// Creates a new form body.
+  pub fn new(data: HashMap<String, FormPart>) -> Self {
+    Self(data)
+  }
+}
+
+/// A body for the request.
+#[derive(Deserialize)]
+#[serde(tag = "type", content = "payload")]
+pub enum Body {
+  /// A multipart formdata body.
+  Form(FormBody),
+  /// A JSON body.
+  Json(Value),
+  /// A text string body.
+  Text(String),
+  /// A byte array body.
+  Bytes(Vec<u8>),
+}
+
+/// The builder for a HTTP request.
 ///
 /// # Examples
-/// ```
-/// # use tauri_api::http::{ HttpRequestBuilder, HttpRequestOptions, make_request, ResponseType };
-/// let mut builder = HttpRequestBuilder::new("GET", "http://example.com");
-/// let option = builder.response_type(ResponseType::Text)
-///                     .follow_redirects(false)
-///                     .build();
+/// ```no_run
+/// use tauri_api::http::{ HttpRequestBuilder, ResponseType, ClientBuilder };
+/// async fn run() {
+///   let client = ClientBuilder::new()
+///     .max_redirections(3)
+///     .build()
+///     .unwrap();
+///   let mut request_builder = HttpRequestBuilder::new("GET", "http://example.com");
+///   let request = request_builder.response_type(ResponseType::Text);
 ///
-/// if let Ok(response) = make_request(option) {
-///   println!("Response: {}", response);
-/// } else {
-///   println!("Something Happened!");
+///   if let Ok(response) = client.send(request).await {
+///     println!("got response");
+///   } else {
+///     println!("Something Happened!");
+///   }
 /// }
 /// ```
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
 pub struct HttpRequestBuilder {
   /// The request method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE)
   pub method: String,
   /// The request URL
   pub url: String,
   /// The request query params
-  pub params: Option<HashMap<String, String>>,
+  pub query: Option<HashMap<String, String>>,
   /// The request headers
   pub headers: Option<HashMap<String, String>>,
   /// The request body
-  pub body: Option<Value>,
-  /// Whether to follow redirects or not
-  pub follow_redirects: Option<bool>,
-  /// Max number of redirections to follow
-  pub max_redirections: Option<u32>,
-  /// Connect timeout for the request
-  pub connect_timeout: Option<u64>,
-  /// Read timeout for the request
-  pub read_timeout: Option<u64>,
+  pub body: Option<Body>,
   /// Timeout for the whole request
   pub timeout: Option<u64>,
-  /// Whether the request will announce that it accepts compression
-  pub allow_compression: Option<bool>,
-  /// The body type (defaults to Auto)
-  pub body_type: Option<BodyType>,
   /// The response type (defaults to Json)
   pub response_type: Option<ResponseType>,
 }
 
 impl HttpRequestBuilder {
-  /// Initializes a new instance of the HttpRequestBuilder.
+  /// Initializes a new instance of the HttpRequestrequest_builder.
   pub fn new(method: impl Into<String>, url: impl Into<String>) -> Self {
     Self {
       method: method.into(),
       url: url.into(),
-      params: None,
+      query: None,
       headers: None,
       body: None,
-      follow_redirects: None,
-      max_redirections: None,
-      connect_timeout: None,
-      read_timeout: None,
       timeout: None,
-      allow_compression: None,
-      body_type: None,
       response_type: None,
     }
   }
 
   /// Sets the request params.
-  pub fn params(mut self, params: HashMap<String, String>) -> Self {
-    self.params = Some(params);
+  pub fn query(mut self, query: HashMap<String, String>) -> Self {
+    self.query = Some(query);
     self
   }
 
@@ -142,161 +223,58 @@ impl HttpRequestBuilder {
   }
 
   /// Sets the request body.
-  pub fn body(mut self, body: Value) -> Self {
+  pub fn body(mut self, body: Body) -> Self {
     self.body = Some(body);
     self
   }
 
-  /// Sets whether the request should follow redirects or not.
-  pub fn follow_redirects(mut self, follow_redirects: bool) -> Self {
-    self.follow_redirects = Some(follow_redirects);
-    self
-  }
-
-  /// Sets the maximum number of redirections.
-  pub fn max_redirections(mut self, max_redirections: u32) -> Self {
-    self.max_redirections = Some(max_redirections);
-    self
-  }
-
-  /// Sets the connection timeout.
-  pub fn connect_timeout(mut self, connect_timeout: u64) -> Self {
-    self.connect_timeout = Some(connect_timeout);
-    self
-  }
-
-  /// Sets the read timeout.
-  pub fn read_timeout(mut self, read_timeout: u64) -> Self {
-    self.read_timeout = Some(read_timeout);
-    self
-  }
-
   /// Sets the general request timeout.
   pub fn timeout(mut self, timeout: u64) -> Self {
     self.timeout = Some(timeout);
     self
   }
 
-  /// Sets whether the request allows compressed responses or not.
-  pub fn allow_compression(mut self, allow_compression: bool) -> Self {
-    self.allow_compression = Some(allow_compression);
-    self
-  }
-
-  /// Sets the type of the request body.
-  pub fn body_type(mut self, body_type: BodyType) -> Self {
-    self.body_type = Some(body_type);
-    self
-  }
-
   /// Sets the type of the response. Interferes with the way we read the response.
   pub fn response_type(mut self, response_type: ResponseType) -> Self {
     self.response_type = Some(response_type);
     self
   }
-
-  /// Builds the HttpRequestOptions.
-  pub fn build(self) -> HttpRequestOptions {
-    HttpRequestOptions {
-      method: self.method,
-      url: self.url,
-      params: self.params,
-      headers: self.headers,
-      body: self.body,
-      follow_redirects: self.follow_redirects,
-      max_redirections: self.max_redirections,
-      connect_timeout: self.connect_timeout,
-      read_timeout: self.read_timeout,
-      timeout: self.timeout,
-      allow_compression: self.allow_compression,
-      body_type: self.body_type,
-      response_type: self.response_type,
-    }
-  }
 }
 
-/// Executes an HTTP request
-///
-/// The response will be transformed to String,
-/// If reading the response as binary, the byte array will be serialized using serde_json
-pub fn make_request(options: HttpRequestOptions) -> crate::Result<Value> {
-  let method = Method::from_bytes(options.method.to_uppercase().as_bytes())?;
-  let mut builder = RequestBuilder::new(method, options.url);
-  if let Some(params) = options.params {
-    for (param, param_value) in params.iter() {
-      builder = builder.param(param, param_value);
-    }
-  }
+/// The HTTP response.
+pub struct Response(ResponseType, reqwest::Response);
 
-  if let Some(headers) = options.headers {
-    for (header, header_value) in headers.iter() {
-      builder = builder.header(HeaderName::from_bytes(header.as_bytes())?, header_value);
+impl Response {
+  /// Reads the response and returns its info.
+  pub async fn read(self) -> crate::Result<ResponseData> {
+    let url = self.1.url().to_string();
+    let mut headers = HashMap::new();
+    for (name, value) in self.1.headers() {
+      headers.insert(name.as_str().to_string(), value.to_str()?.to_string());
     }
-  }
+    let status = self.1.status().as_u16();
 
-  if let Some(follow_redirects) = options.follow_redirects {
-    builder = builder.follow_redirects(follow_redirects);
-  }
-  if let Some(max_redirections) = options.max_redirections {
-    builder = builder.max_redirections(max_redirections);
-  }
-  if let Some(connect_timeout) = options.connect_timeout {
-    builder = builder.connect_timeout(Duration::from_secs(connect_timeout));
-  }
-  if let Some(read_timeout) = options.read_timeout {
-    builder = builder.read_timeout(Duration::from_secs(read_timeout));
-  }
-  if let Some(timeout) = options.timeout {
-    builder = builder.timeout(Duration::from_secs(timeout));
-  }
-  if let Some(allow_compression) = options.allow_compression {
-    builder = builder.allow_compression(allow_compression);
-  }
-  builder = builder
-    .danger_accept_invalid_certs(true)
-    .danger_accept_invalid_hostnames(true);
-
-  let response = if let Some(body) = options.body {
-    match options.body_type.unwrap_or(BodyType::Auto) {
-      BodyType::Form => builder.form(&body)?.send(),
-      BodyType::File => {
-        if let Some(path) = body.as_str() {
-          builder.file(File::open(path)?).send()
-        } else {
-          return Err(crate::Error::Path(
-            "Body must be the path to the file".into(),
-          ));
-        }
-      }
-      BodyType::Auto => {
-        if body.is_object() {
-          builder.json(&body)?.send()
-        } else if let Some(text) = body.as_str() {
-          builder.text(&text).send()
-        } else if body.is_array() {
-          let u: Result<Vec<u8>, _> = serde_json::from_value(body.clone());
-          match u {
-            Ok(vec) => builder.bytes(&vec).send(),
-            Err(_) => builder.json(&body)?.send(),
-          }
-        } else {
-          builder.send()
-        }
-      }
-    }
-  } else {
-    builder.send()
-  };
-
-  let response = response?;
-  if response.is_success() {
-    let response_data = match options.response_type.unwrap_or(ResponseType::Json) {
-      ResponseType::Json => response.json::<Value>()?,
-      ResponseType::Text => Value::String(response.text()?),
-      ResponseType::Binary => Value::String(serde_json::to_string(&response.bytes()?)?),
+    let data = match self.0 {
+      ResponseType::Json => self.1.json().await?,
+      ResponseType::Text => Value::String(self.1.text().await?),
+      ResponseType::Binary => Value::String(serde_json::to_string(&self.1.bytes().await?)?),
     };
-    Ok(response_data)
-  } else {
-    Err(response.status().into())
+
+    Ok(ResponseData {
+      url,
+      status,
+      headers,
+      data,
+    })
   }
 }
+
+/// The response type.
+#[derive(Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ResponseData {
+  url: String,
+  status: u16,
+  headers: HashMap<String, String>,
+  data: Value,
+}

+ 1 - 0
tauri/Cargo.toml

@@ -33,6 +33,7 @@ once_cell = "1.5.2"
 tauri-api = { version = "0.7.5", path = "../tauri-api" }
 tauri-macros = { version = "0.1", path = "../tauri-macros" }
 wry = { git = "https://github.com/tauri-apps/wry", rev = "b36b3e2d07edddf2ef49dcc901ae2c5888873ad2" }
+rand = "0.8"
 
 [target."cfg(target_os = \"windows\")".dependencies]
 runas = "0.2"

+ 345 - 38
tauri/examples/api/src-tauri/Cargo.lock

@@ -120,24 +120,6 @@ dependencies = [
  "system-deps",
 ]
 
-[[package]]
-name = "attohttpc"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba5b30bf3a0aead269fd5dd69b385a3e90c2b55f4f215d1bdf52c3883f5fa7fa"
-dependencies = [
- "flate2",
- "http",
- "log",
- "native-tls",
- "openssl",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "url",
- "wildmatch",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -227,6 +209,9 @@ name = "bytes"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "bzip2"
@@ -677,18 +662,21 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
-[[package]]
-name = "dtoa"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
-
 [[package]]
 name = "either"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "encoding_rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
 [[package]]
 name = "failure"
 version = "0.1.8"
@@ -1109,6 +1097,26 @@ dependencies = [
  "system-deps",
 ]
 
+[[package]]
+name = "h2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "tracing-futures",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.9.1"
@@ -1144,6 +1152,65 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "httparse"
+version = "1.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691"
+
+[[package]]
+name = "httpdate"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
+
+[[package]]
+name = "hyper"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project 1.0.5",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -1208,6 +1275,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "ipnet"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
+
 [[package]]
 name = "itertools"
 version = "0.9.0"
@@ -1388,6 +1461,22 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.3.7"
@@ -1420,12 +1509,25 @@ dependencies = [
  "kernel32-sys",
  "libc",
  "log",
- "miow",
+ "miow 0.2.2",
  "net2",
  "slab",
  "winapi 0.2.8",
 ]
 
+[[package]]
+name = "mio"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
+dependencies = [
+ "libc",
+ "log",
+ "miow 0.3.6",
+ "ntapi",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "mio-extras"
 version = "2.0.6"
@@ -1434,7 +1536,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
 dependencies = [
  "lazycell",
  "log",
- "mio",
+ "mio 0.6.23",
  "slab",
 ]
 
@@ -1450,6 +1552,16 @@ dependencies = [
  "ws2_32-sys",
 ]
 
+[[package]]
+name = "miow"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "native-tls"
 version = "0.2.7"
@@ -1848,6 +1960,46 @@ dependencies = [
  "siphasher",
 ]
 
+[[package]]
+name = "pin-project"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"
+dependencies = [
+ "pin-project-internal 0.4.27",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63"
+dependencies = [
+ "pin-project-internal 1.0.5",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.8",
+ "syn 1.0.60",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.8",
+ "syn 1.0.60",
+]
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.4"
@@ -2141,6 +2293,42 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "reqwest"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "mime",
+ "mime_guess",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "runas"
 version = "0.2.1"
@@ -2307,14 +2495,14 @@ dependencies = [
 
 [[package]]
 name = "serde_urlencoded"
-version = "0.6.1"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
+checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
 dependencies = [
- "dtoa",
+ "form_urlencoded",
  "itoa",
+ "ryu",
  "serde",
- "url",
 ]
 
 [[package]]
@@ -2360,6 +2548,17 @@ dependencies = [
  "wayland-protocols",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "soup-sys"
 version = "0.10.0"
@@ -2527,6 +2726,7 @@ dependencies = [
  "futures",
  "lazy_static",
  "once_cell",
+ "rand 0.8.3",
  "runas",
  "serde",
  "serde_json",
@@ -2544,7 +2744,7 @@ dependencies = [
 name = "tauri-api"
 version = "0.7.5"
 dependencies = [
- "attohttpc",
+ "bytes",
  "clap",
  "dirs-next",
  "either",
@@ -2554,6 +2754,7 @@ dependencies = [
  "notify-rust",
  "once_cell",
  "rand 0.8.3",
+ "reqwest",
  "semver",
  "serde",
  "serde_json",
@@ -2755,10 +2956,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a"
 dependencies = [
  "autocfg",
+ "bytes",
+ "libc",
+ "memchr",
+ "mio 0.7.7",
  "num_cpus",
  "pin-project-lite",
 ]
 
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
 [[package]]
 name = "toml"
 version = "0.5.8"
@@ -2768,6 +2997,48 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3"
+dependencies = [
+ "cfg-if 1.0.0",
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
+dependencies = [
+ "pin-project 0.4.27",
+ "tracing",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
 [[package]]
 name = "ttf-parser"
 version = "0.6.2"
@@ -2780,6 +3051,15 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.4"
@@ -2878,6 +3158,16 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
@@ -2897,6 +3187,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
 dependencies = [
  "cfg-if 1.0.0",
+ "serde",
+ "serde_json",
  "wasm-bindgen-macro",
 ]
 
@@ -2915,6 +3207,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94"
+dependencies = [
+ "cfg-if 1.0.0",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.70"
@@ -3104,12 +3408,6 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
 
-[[package]]
-name = "wildmatch"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2399814fda0d6999a6bfe9b5c7660d836334deb162a09db8b73d5b38fd8c40a"
-
 [[package]]
 name = "winapi"
 version = "0.2.8"
@@ -3245,7 +3543,7 @@ dependencies = [
  "lazy_static",
  "libc",
  "log",
- "mio",
+ "mio 0.6.23",
  "mio-extras",
  "ndk",
  "ndk-glue",
@@ -3260,6 +3558,15 @@ dependencies = [
  "x11-dl",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
+dependencies = [
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "winres"
 version = "0.1.11"

+ 9 - 10
tauri/examples/api/src/components/Http.svelte

@@ -1,15 +1,15 @@
 <script>
-  import { request } from "@tauri-apps/api/http";
+  import { getClient, Body } from "@tauri-apps/api/http";
   let httpMethod = "GET";
   let httpUrl = "";
   let httpBody = "";
 
   export let onMessage;
 
-  function makeHttpRequest() {
+  async function makeHttpRequest() {
+    const client = await getClient()
     let method = httpMethod || "GET";
     let url = httpUrl || "";
-    let body = httpBody || "";
 
     const options = {
       url: url || "",
@@ -17,16 +17,15 @@
     };
 
     if (
-      (body.startsWith("{") && body.endsWith("}")) ||
-      (body.startsWith("[") && body.endsWith("]"))
+      (httpBody.startsWith("{") && httpBody.endsWith("}")) ||
+      (httpBody.startsWith("[") && httpBody.endsWith("]"))
     ) {
-      body = JSON.parse(body);
-    } else if (body.startsWith("/") || body.match(/\S:\//g)) {
-      options.bodyAsFile = true;
+      options.body = Body.json(JSON.parse(httpBody));
+    } else if (httpBody !== '') {
+      options.body = Body.text(httpBody)
     }
-    options.body = body;
 
-    request(options)
+    client.request(options)
       .then(onMessage)
       .catch(onMessage);
   }

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tauri/examples/communication/dist/__tauri.js


+ 12 - 8
tauri/examples/communication/dist/http.js

@@ -2,6 +2,11 @@ const methodSelect = document.getElementById("request-method");
 const requestUrlInput = document.getElementById("request-url");
 const requestBodyInput = document.getElementById("request-body");
 
+let client
+window.__TAURI__.http.getClient().then(function (c) {
+  client = c
+})
+
 document.getElementById("make-request").addEventListener("click", function () {
   const method = methodSelect.value || "GET";
   const url = requestUrlInput.value || "";
@@ -11,18 +16,17 @@ document.getElementById("make-request").addEventListener("click", function () {
     method: method,
   };
 
-  let body = requestBodyInput.value || "";
+  let httpBody = requestBodyInput.value || "";
   if (
-    (body.startsWith("{") && body.endsWith("}")) ||
-    (body.startsWith("[") && body.endsWith("]"))
+    (httpBody.startsWith("{") && httpBody.endsWith("}")) ||
+    (httpBody.startsWith("[") && httpBody.endsWith("]"))
   ) {
-    body = JSON.parse(body);
-  } else if (body.startsWith("/") || body.match(/\S:\//g)) {
-    options.bodyAsFile = true;
+    options.body = window.__TAURI__.http.Body.json(JSON.parse(httpBody));
+  } else if (httpBody !== '') {
+    options.body = window.__TAURI__.http.Body.text(httpBody)
   }
-  options.body = body;
 
-  window.__TAURI__.http
+  client
     .request(options)
     .then(registerResponse)
     .catch(registerResponse);

+ 345 - 38
tauri/examples/communication/src-tauri/Cargo.lock

@@ -120,24 +120,6 @@ dependencies = [
  "system-deps",
 ]
 
-[[package]]
-name = "attohttpc"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba5b30bf3a0aead269fd5dd69b385a3e90c2b55f4f215d1bdf52c3883f5fa7fa"
-dependencies = [
- "flate2",
- "http",
- "log",
- "native-tls",
- "openssl",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "url",
- "wildmatch",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -227,6 +209,9 @@ name = "bytes"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "bzip2"
@@ -677,18 +662,21 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
-[[package]]
-name = "dtoa"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
-
 [[package]]
 name = "either"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "encoding_rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
 [[package]]
 name = "failure"
 version = "0.1.8"
@@ -1109,6 +1097,26 @@ dependencies = [
  "system-deps",
 ]
 
+[[package]]
+name = "h2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "tracing-futures",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.9.1"
@@ -1144,6 +1152,65 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "httparse"
+version = "1.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691"
+
+[[package]]
+name = "httpdate"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
+
+[[package]]
+name = "hyper"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project 1.0.5",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -1208,6 +1275,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "ipnet"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
+
 [[package]]
 name = "itertools"
 version = "0.9.0"
@@ -1388,6 +1461,22 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.3.7"
@@ -1420,12 +1509,25 @@ dependencies = [
  "kernel32-sys",
  "libc",
  "log",
- "miow",
+ "miow 0.2.2",
  "net2",
  "slab",
  "winapi 0.2.8",
 ]
 
+[[package]]
+name = "mio"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
+dependencies = [
+ "libc",
+ "log",
+ "miow 0.3.6",
+ "ntapi",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "mio-extras"
 version = "2.0.6"
@@ -1434,7 +1536,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
 dependencies = [
  "lazycell",
  "log",
- "mio",
+ "mio 0.6.23",
  "slab",
 ]
 
@@ -1450,6 +1552,16 @@ dependencies = [
  "ws2_32-sys",
 ]
 
+[[package]]
+name = "miow"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "native-tls"
 version = "0.2.7"
@@ -1848,6 +1960,46 @@ dependencies = [
  "siphasher",
 ]
 
+[[package]]
+name = "pin-project"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"
+dependencies = [
+ "pin-project-internal 0.4.27",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63"
+dependencies = [
+ "pin-project-internal 1.0.5",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.8",
+ "syn 1.0.60",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.8",
+ "syn 1.0.60",
+]
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.4"
@@ -2141,6 +2293,42 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "reqwest"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "mime",
+ "mime_guess",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "runas"
 version = "0.2.1"
@@ -2307,14 +2495,14 @@ dependencies = [
 
 [[package]]
 name = "serde_urlencoded"
-version = "0.6.1"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
+checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
 dependencies = [
- "dtoa",
+ "form_urlencoded",
  "itoa",
+ "ryu",
  "serde",
- "url",
 ]
 
 [[package]]
@@ -2360,6 +2548,17 @@ dependencies = [
  "wayland-protocols",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "soup-sys"
 version = "0.10.0"
@@ -2527,6 +2726,7 @@ dependencies = [
  "futures",
  "lazy_static",
  "once_cell",
+ "rand 0.8.3",
  "runas",
  "serde",
  "serde_json",
@@ -2544,7 +2744,7 @@ dependencies = [
 name = "tauri-api"
 version = "0.7.5"
 dependencies = [
- "attohttpc",
+ "bytes",
  "clap",
  "dirs-next",
  "either",
@@ -2554,6 +2754,7 @@ dependencies = [
  "notify-rust",
  "once_cell",
  "rand 0.8.3",
+ "reqwest",
  "semver",
  "serde",
  "serde_json",
@@ -2755,10 +2956,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a"
 dependencies = [
  "autocfg",
+ "bytes",
+ "libc",
+ "memchr",
+ "mio 0.7.7",
  "num_cpus",
  "pin-project-lite",
 ]
 
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
 [[package]]
 name = "toml"
 version = "0.5.8"
@@ -2768,6 +2997,48 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3"
+dependencies = [
+ "cfg-if 1.0.0",
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
+dependencies = [
+ "pin-project 0.4.27",
+ "tracing",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
 [[package]]
 name = "ttf-parser"
 version = "0.6.2"
@@ -2780,6 +3051,15 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.4"
@@ -2878,6 +3158,16 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
@@ -2897,6 +3187,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
 dependencies = [
  "cfg-if 1.0.0",
+ "serde",
+ "serde_json",
  "wasm-bindgen-macro",
 ]
 
@@ -2915,6 +3207,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94"
+dependencies = [
+ "cfg-if 1.0.0",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.70"
@@ -3104,12 +3408,6 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
 
-[[package]]
-name = "wildmatch"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2399814fda0d6999a6bfe9b5c7660d836334deb162a09db8b73d5b38fd8c40a"
-
 [[package]]
 name = "winapi"
 version = "0.2.8"
@@ -3245,7 +3543,7 @@ dependencies = [
  "lazy_static",
  "libc",
  "log",
- "mio",
+ "mio 0.6.23",
  "mio-extras",
  "ndk",
  "ndk-glue",
@@ -3260,6 +3558,15 @@ dependencies = [
  "x11-dl",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
+dependencies = [
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "winres"
 version = "0.1.11"

+ 1 - 1
tauri/examples/communication/src-tauri/tauri.conf.json

@@ -58,7 +58,7 @@
     },
     "windows": [{
       "title": "Tauri API Validation",
-      "resizable": false
+      "resizable": true
     }],
     "security": {
       "csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tauri/examples/multiwindow/dist/__tauri.js


+ 362 - 39
tauri/examples/multiwindow/src-tauri/Cargo.lock

@@ -118,24 +118,6 @@ dependencies = [
  "system-deps",
 ]
 
-[[package]]
-name = "attohttpc"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba5b30bf3a0aead269fd5dd69b385a3e90c2b55f4f215d1bdf52c3883f5fa7fa"
-dependencies = [
- "flate2",
- "http",
- "log",
- "native-tls",
- "openssl",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "url",
- "wildmatch",
-]
-
 [[package]]
 name = "autocfg"
 version = "1.0.1"
@@ -214,6 +196,9 @@ name = "bytes"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "bzip2"
@@ -632,18 +617,21 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
-[[package]]
-name = "dtoa"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
-
 [[package]]
 name = "either"
 version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "encoding_rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
 [[package]]
 name = "failure"
 version = "0.1.8"
@@ -1064,6 +1052,32 @@ dependencies = [
  "system-deps",
 ]
 
+[[package]]
+name = "h2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "tracing-futures",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+
 [[package]]
 name = "heck"
 version = "0.3.2"
@@ -1093,6 +1107,65 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "httparse"
+version = "1.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691"
+
+[[package]]
+name = "httpdate"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47"
+
+[[package]]
+name = "hyper"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project 1.0.5",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -1129,6 +1202,16 @@ dependencies = [
  "tiff",
 ]
 
+[[package]]
+name = "indexmap"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.9"
@@ -1147,6 +1230,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "ipnet"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
+
 [[package]]
 name = "itertools"
 version = "0.9.0"
@@ -1327,6 +1416,22 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.3.7"
@@ -1359,12 +1464,25 @@ dependencies = [
  "kernel32-sys",
  "libc",
  "log",
- "miow",
+ "miow 0.2.2",
  "net2",
  "slab",
  "winapi 0.2.8",
 ]
 
+[[package]]
+name = "mio"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7"
+dependencies = [
+ "libc",
+ "log",
+ "miow 0.3.6",
+ "ntapi",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "mio-extras"
 version = "2.0.6"
@@ -1373,7 +1491,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
 dependencies = [
  "lazycell",
  "log",
- "mio",
+ "mio 0.6.23",
  "slab",
 ]
 
@@ -1389,6 +1507,16 @@ dependencies = [
  "ws2_32-sys",
 ]
 
+[[package]]
+name = "miow"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "native-tls"
 version = "0.2.7"
@@ -1781,6 +1909,46 @@ dependencies = [
  "siphasher",
 ]
 
+[[package]]
+name = "pin-project"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"
+dependencies = [
+ "pin-project-internal 0.4.27",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63"
+dependencies = [
+ "pin-project-internal 1.0.5",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.9",
+ "syn 1.0.60",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.9",
+ "syn 1.0.60",
+]
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.4"
@@ -2074,6 +2242,42 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "reqwest"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd281b1030aa675fb90aa994d07187645bb3c8fc756ca766e7c3070b439de9de"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "mime",
+ "mime_guess",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "runas"
 version = "0.2.1"
@@ -2240,14 +2444,14 @@ dependencies = [
 
 [[package]]
 name = "serde_urlencoded"
-version = "0.6.1"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
+checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
 dependencies = [
- "dtoa",
+ "form_urlencoded",
  "itoa",
+ "ryu",
  "serde",
- "url",
 ]
 
 [[package]]
@@ -2293,6 +2497,17 @@ dependencies = [
  "wayland-protocols",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "soup-sys"
 version = "0.10.0"
@@ -2368,7 +2583,7 @@ checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149"
 dependencies = [
  "heck",
  "proc-macro2",
- "quote 1.0.8",
+ "quote 1.0.9",
  "syn 1.0.60",
 ]
 
@@ -2454,6 +2669,7 @@ dependencies = [
  "futures",
  "lazy_static",
  "once_cell",
+ "rand 0.8.3",
  "runas",
  "serde",
  "serde_json",
@@ -2471,7 +2687,7 @@ dependencies = [
 name = "tauri-api"
 version = "0.7.5"
 dependencies = [
- "attohttpc",
+ "bytes",
  "dirs-next",
  "either",
  "flate2",
@@ -2480,6 +2696,7 @@ dependencies = [
  "notify-rust",
  "once_cell",
  "rand 0.8.3",
+ "reqwest",
  "semver",
  "serde",
  "serde_json",
@@ -2663,10 +2880,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a"
 dependencies = [
  "autocfg",
+ "bytes",
+ "libc",
+ "memchr",
+ "mio 0.7.7",
  "num_cpus",
  "pin-project-lite",
 ]
 
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
 [[package]]
 name = "toml"
 version = "0.5.8"
@@ -2676,6 +2921,48 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d40a22fd029e33300d8d89a5cc8ffce18bb7c587662f54629e94c9de5487f3"
+dependencies = [
+ "cfg-if 1.0.0",
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "tracing-futures"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
+dependencies = [
+ "pin-project 0.4.27",
+ "tracing",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
 [[package]]
 name = "ttf-parser"
 version = "0.6.2"
@@ -2688,6 +2975,15 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.4"
@@ -2774,6 +3070,16 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
@@ -2793,6 +3099,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
 dependencies = [
  "cfg-if 1.0.0",
+ "serde",
+ "serde_json",
  "wasm-bindgen-macro",
 ]
 
@@ -2811,6 +3119,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94"
+dependencies = [
+ "cfg-if 1.0.0",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.70"
@@ -3000,12 +3320,6 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
 
-[[package]]
-name = "wildmatch"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2399814fda0d6999a6bfe9b5c7660d836334deb162a09db8b73d5b38fd8c40a"
-
 [[package]]
 name = "winapi"
 version = "0.2.8"
@@ -3141,7 +3455,7 @@ dependencies = [
  "lazy_static",
  "libc",
  "log",
- "mio",
+ "mio 0.6.23",
  "mio-extras",
  "ndk",
  "ndk-glue",
@@ -3156,6 +3470,15 @@ dependencies = [
  "x11-dl",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
+dependencies = [
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "winres"
 version = "0.1.11"

+ 60 - 6
tauri/src/endpoints/http.rs

@@ -1,15 +1,35 @@
-use crate::ApplicationDispatcherExt;
+use crate::{async_runtime::Mutex, ApplicationDispatcherExt};
 
+use once_cell::sync::Lazy;
 use serde::Deserialize;
-use tauri_api::http::{make_request as request, HttpRequestOptions};
+use tauri_api::http::{Client, ClientBuilder, HttpRequestBuilder};
+
+use std::{collections::HashMap, sync::Arc};
+
+type ClientId = u32;
+type ClientStore = Arc<Mutex<HashMap<ClientId, Client>>>;
+
+fn clients() -> &'static ClientStore {
+  static STORE: Lazy<ClientStore> = Lazy::new(Default::default);
+  &STORE
+}
 
 /// The API descriptor.
 #[derive(Deserialize)]
 #[serde(tag = "cmd", rename_all = "camelCase")]
 pub enum Cmd {
+  /// Create a new HTTP client.
+  CreateClient {
+    options: Option<ClientBuilder>,
+    callback: String,
+    error: String,
+  },
+  /// Drop a HTTP client.
+  DropClient { client: ClientId },
   /// The HTTP request API.
   HttpRequest {
-    options: Box<HttpRequestOptions>,
+    client: ClientId,
+    options: Box<HttpRequestBuilder>,
     callback: String,
     error: String,
   },
@@ -21,13 +41,37 @@ impl Cmd {
     webview_manager: &crate::WebviewManager<D>,
   ) {
     match self {
+      Self::CreateClient {
+        options,
+        callback,
+        error,
+      } => {
+        crate::execute_promise(
+          webview_manager,
+          async move {
+            let client = options.unwrap_or_default().build()?;
+            let mut store = clients().lock().await;
+            let id = rand::random::<ClientId>();
+            store.insert(id, client);
+            Ok(id)
+          },
+          callback,
+          error,
+        )
+        .await;
+      }
+      Self::DropClient { client } => {
+        let mut store = clients().lock().await;
+        store.remove(&client);
+      }
       Self::HttpRequest {
+        client,
         options,
         callback,
         error,
       } => {
         #[cfg(http_request)]
-        make_request(webview_manager, *options, callback, error).await;
+        make_request(webview_manager, client, *options, callback, error).await;
         #[cfg(not(http_request))]
         allowlist_error(webview_manager, error, "httpRequest");
       }
@@ -38,13 +82,23 @@ impl Cmd {
 /// Makes an HTTP request and resolves the response to the webview
 pub async fn make_request<D: ApplicationDispatcherExt>(
   webview_manager: &crate::WebviewManager<D>,
-  options: HttpRequestOptions,
+  client_id: ClientId,
+  options: HttpRequestBuilder,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview_manager,
-    async move { request(options).map_err(|e| e.into()) },
+    async move {
+      let client = clients()
+        .lock()
+        .await
+        .get(&client_id)
+        .ok_or(crate::Error::HttpClientNotInitialized)?
+        .clone();
+      let response = client.send(options).await?;
+      Ok(response.read().await?)
+    },
     callback,
     error,
   )

+ 3 - 0
tauri/src/error.rs

@@ -34,6 +34,9 @@ pub enum Error {
   /// Failed to load window icon.
   #[error("invalid icon: {0}")]
   InvalidIcon(String),
+  /// Client with specified ID not found.
+  #[error("http client dropped or not initialized")]
+  HttpClientNotInitialized,
 }
 
 impl From<serde_json::Error> for Error {

Некоторые файлы не были показаны из-за большого количества измененных файлов