From 5092f01affb053212e7b821c4df62bb9e48e5f4b Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 15:46:32 -0400 Subject: [PATCH 1/6] add flake --- .gitignore | 2 ++ flake.lock | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 66 +++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index 38051f6577..ad81a2f2e3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ target/ # dotenv environment variables file .env +.envrc +.direnv # .vscode workspace settings file .vscode/settings.json diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..bfafb5a7a3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,100 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1755585599, + "narHash": "sha256-tl/0cnsqB/Yt7DbaGMel2RLa7QG5elA8lkaOXli6VdY=", + "owner": "nix-community", + "repo": "fenix", + "rev": "6ed03ef4c8ec36d193c18e06b9ecddde78fb7e42", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1755186698, + "narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1755504847, + "narHash": "sha256-VX0B9hwhJypCGqncVVLC+SmeMVd/GAYbJZ0MiiUn2Pk=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "a905e3b21b144d77e1b304e49f3264f6f8d4db75", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..73e3bb2dd6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,66 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + fenix.url = "github:nix-community/fenix"; + fenix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + fenix, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { + system = system; + }; + + packages = with pkgs; [ + curl + wget + pkg-config + + cargo-tauri + cargo-info + cargo-udeps + + ( + with fenix.packages.${system}; + combine [ + complete.rustc + complete.rust-src + complete.cargo + complete.clippy + complete.rustfmt + complete.rust-analyzer + ] + ) + ]; + + libraries = with pkgs; [ + gtk3 + libsoup_3 + webkitgtk_4_1 + cairo + gdk-pixbuf + glib + dbus + openssl + librsvg + ]; + in + { + devShell = pkgs.mkShell { + buildInputs = packages ++ libraries; + + LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath libraries}:$LD_LIBRARY_PATH"; + XDG_DATA_DIRS = "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:$XDG_DATA_DIRS"; + }; + } + ); +} From 2465565a8ea0f82f7d194d6c56db5512dfe1d77a Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 15:46:32 -0400 Subject: [PATCH 2/6] add merge headers method --- plugins/websocket/src/lib.rs | 56 ++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/plugins/websocket/src/lib.rs b/plugins/websocket/src/lib.rs index f75817b612..2c39899190 100644 --- a/plugins/websocket/src/lib.rs +++ b/plugins/websocket/src/lib.rs @@ -9,13 +9,16 @@ html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png" )] -use futures_util::{stream::SplitSink, SinkExt, StreamExt}; -use http::header::{HeaderName, HeaderValue}; -use serde::{ser::Serializer, Deserialize, Serialize}; +use futures_util::{SinkExt, StreamExt, stream::SplitSink}; +use http::{ + HeaderMap, Request, + header::{HeaderName, HeaderValue}, +}; +use serde::{Deserialize, Serialize, ser::Serializer}; use tauri::{ + AppHandle, Manager, Runtime, State, Url, Window, ipc::Channel, plugin::{Builder as PluginBuilder, TauriPlugin}, - Manager, Runtime, State, Window, }; use tokio::{net::TcpStream, sync::Mutex}; #[cfg(any(feature = "rustls-tls", feature = "native-tls"))] @@ -23,16 +26,16 @@ use tokio_tungstenite::connect_async_tls_with_config; #[cfg(not(any(feature = "rustls-tls", feature = "native-tls")))] use tokio_tungstenite::connect_async_with_config; use tokio_tungstenite::{ + Connector, MaybeTlsStream, WebSocketStream, tungstenite::{ + Message, client::IntoClientRequest, protocol::{CloseFrame as ProtocolCloseFrame, WebSocketConfig}, - Message, }, - Connector, MaybeTlsStream, WebSocketStream, }; -use std::collections::HashMap; use std::str::FromStr; +use std::{collections::HashMap, marker::PhantomData}; type Id = u32; type WebSocket = WebSocketStream>; @@ -157,6 +160,10 @@ async fn connect( } } + if let Some(state) = window.app_handle().try_state::>() { + (state.inner().0)(&mut request, window.app_handle()); + } + #[cfg(any(feature = "rustls-tls", feature = "native-tls"))] let tls_connector = match window.try_state::() { Some(tls_connector) => tls_connector.0.lock().await.clone(), @@ -242,31 +249,56 @@ async fn send( } pub fn init() -> TauriPlugin { - Builder::default().build() + Builder::new().build() } -#[derive(Default)] -pub struct Builder { +/// Struct to provide concrete type for the manager +struct RequestCallback( + Box, &AppHandle) + Send + Sync + 'static>, +); + +pub struct Builder { tls_connector: Option, + merge_headers: Option>, } -impl Builder { +impl Builder +where + R: Runtime, +{ pub fn new() -> Self { Self { tls_connector: None, + merge_headers: None, } } + /// add a callback which is able to modify the initial headers of the http upgrade request. + /// This is useful for scenarios where the frontend may not know all the required headers that must be sent. + /// e.g. in the scenario of http-only cookies + pub fn merge_header_callback( + mut self, + cb: Box, &AppHandle) + Send + Sync + 'static>, + ) -> Self { + self.merge_headers.replace(RequestCallback(cb)); + self + } + pub fn tls_connector(mut self, connector: Connector) -> Self { self.tls_connector.replace(connector); self } - pub fn build(self) -> TauriPlugin { + pub fn build(self) -> TauriPlugin { PluginBuilder::new("websocket") .invoke_handler(tauri::generate_handler![connect, send]) .setup(|app, _api| { app.manage(ConnectionManager::default()); + + if let Some(cb) = self.merge_headers { + app.manage(cb); + } + #[cfg(any(feature = "rustls-tls", feature = "native-tls"))] app.manage(TlsConnector(Mutex::new(self.tls_connector))); Ok(()) From 87582448162725e09b0ec4fa5b3560dc78293c38 Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 16:31:47 -0400 Subject: [PATCH 3/6] make http client state accessible --- plugins/http/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/http/src/lib.rs b/plugins/http/src/lib.rs index 5acc2b474a..24bcb7713d 100644 --- a/plugins/http/src/lib.rs +++ b/plugins/http/src/lib.rs @@ -6,8 +6,8 @@ pub use reqwest; use tauri::{ - plugin::{Builder, TauriPlugin}, Manager, Runtime, + plugin::{Builder, TauriPlugin}, }; pub use error::{Error, Result}; @@ -21,9 +21,9 @@ mod scope; #[cfg(feature = "cookies")] const COOKIES_FILENAME: &str = ".cookies"; -pub(crate) struct Http { +pub struct Http { #[cfg(feature = "cookies")] - cookies_jar: std::sync::Arc, + pub cookies_jar: std::sync::Arc, } pub fn init() -> TauriPlugin { From 31ee69a0a1ecbb18298f36cb36266702dc1fa062 Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 16:40:32 -0400 Subject: [PATCH 4/6] remove unused imports --- plugins/websocket/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/websocket/src/lib.rs b/plugins/websocket/src/lib.rs index 2c39899190..f220167a75 100644 --- a/plugins/websocket/src/lib.rs +++ b/plugins/websocket/src/lib.rs @@ -11,12 +11,12 @@ use futures_util::{SinkExt, StreamExt, stream::SplitSink}; use http::{ - HeaderMap, Request, + Request, header::{HeaderName, HeaderValue}, }; use serde::{Deserialize, Serialize, ser::Serializer}; use tauri::{ - AppHandle, Manager, Runtime, State, Url, Window, + AppHandle, Manager, Runtime, State, Window, ipc::Channel, plugin::{Builder as PluginBuilder, TauriPlugin}, }; @@ -34,8 +34,8 @@ use tokio_tungstenite::{ }, }; +use std::collections::HashMap; use std::str::FromStr; -use std::{collections::HashMap, marker::PhantomData}; type Id = u32; type WebSocket = WebSocketStream>; From aaf1e3ae1f5f30d3746db2a17611b864b3ecd760 Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 17:10:27 -0400 Subject: [PATCH 5/6] change cb signature --- plugins/websocket/src/lib.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/websocket/src/lib.rs b/plugins/websocket/src/lib.rs index f220167a75..6e9fc4540f 100644 --- a/plugins/websocket/src/lib.rs +++ b/plugins/websocket/src/lib.rs @@ -11,7 +11,7 @@ use futures_util::{SinkExt, StreamExt, stream::SplitSink}; use http::{ - Request, + HeaderMap, header::{HeaderName, HeaderValue}, }; use serde::{Deserialize, Serialize, ser::Serializer}; @@ -150,7 +150,7 @@ async fn connect( config: Option, ) -> Result { let id = rand::random(); - let mut request = url.into_client_request()?; + let mut request = url.as_str().into_client_request()?; if let Some(headers) = config.as_ref().and_then(|c| c.headers.as_ref()) { for (k, v) in headers { @@ -161,7 +161,7 @@ async fn connect( } if let Some(state) = window.app_handle().try_state::>() { - (state.inner().0)(&mut request, window.app_handle()); + (state.inner().0)(url, request.headers_mut(), window.app_handle()); } #[cfg(any(feature = "rustls-tls", feature = "native-tls"))] @@ -252,10 +252,11 @@ pub fn init() -> TauriPlugin { Builder::new().build() } +type RqCb = + Box, &AppHandle) + Send + Sync + 'static>; + /// Struct to provide concrete type for the manager -struct RequestCallback( - Box, &AppHandle) + Send + Sync + 'static>, -); +struct RequestCallback(RqCb); pub struct Builder { tls_connector: Option, @@ -276,10 +277,7 @@ where /// add a callback which is able to modify the initial headers of the http upgrade request. /// This is useful for scenarios where the frontend may not know all the required headers that must be sent. /// e.g. in the scenario of http-only cookies - pub fn merge_header_callback( - mut self, - cb: Box, &AppHandle) + Send + Sync + 'static>, - ) -> Self { + pub fn merge_header_callback(mut self, cb: RqCb) -> Self { self.merge_headers.replace(RequestCallback(cb)); self } From 41a10c2912be75a4a17307295f42e08aeae17989 Mon Sep 17 00:00:00 2001 From: Sean Aye Date: Tue, 19 Aug 2025 21:00:20 -0400 Subject: [PATCH 6/6] update readme to reflect the homepage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdf239bcf5..196c548840 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This repo and all plugins require a Rust version of at least **1.77.2** | [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? | | [updater](plugins/updater) | In-app updates for Tauri applications. | ✅ | ✅ | ✅ | ❌ | ❌ | | [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ✅ | ✅ | -| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? | +| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ✅ | ✅ | | [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ❌ | ❌ | - ✅: (Partially) Supported