diff --git a/Cargo.lock b/Cargo.lock index d7d47d8..6b36474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,7 +127,29 @@ dependencies = [ "serde_repr", "tokio", "url", - "zbus", + "zbus 4.0.1", +] + +[[package]] +name = "ashpd" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" +dependencies = [ + "async-fs", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.8.5", + "raw-window-handle 0.6.2", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus 5.4.0", ] [[package]] @@ -154,6 +176,30 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + [[package]] name = "async-io" version = "2.4.0" @@ -184,6 +230,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + [[package]] name = "async-process" version = "2.3.0" @@ -1262,7 +1319,7 @@ dependencies = [ "objc", "objc_id", "once_cell", - "rfd", + "rfd 0.14.1", "rustc-hash 1.1.0", "serde", "serde_json", @@ -1574,6 +1631,15 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.5", +] + [[package]] name = "dlopen2" version = "0.7.0" @@ -1597,6 +1663,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.1" @@ -1695,12 +1767,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3418,6 +3490,7 @@ name = "mumble-web2-gui" version = "0.1.0" dependencies = [ "asynchronous-codec", + "base64 0.22.1", "byteorder", "color-eyre", "cpal", @@ -3434,12 +3507,14 @@ dependencies = [ "lol_html 2.2.0", "markdown", "merge-io", + "mime_guess", "mumble-protocol-2x", "mumble-web2-common", "ogg", "once_cell", "opus", "ordermap", + "rfd 0.15.2", "serde", "serde-wasm-bindgen 0.6.5", "serde_json", @@ -3575,6 +3650,7 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", + "memoffset", ] [[package]] @@ -3771,6 +3847,7 @@ checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ "bitflags 2.6.0", "block2", + "dispatch", "libc", "objc2", ] @@ -4241,6 +4318,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "polyval" version = "0.6.2" @@ -4303,6 +4386,15 @@ dependencies = [ "toml_edit 0.20.2", ] +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4379,6 +4471,15 @@ dependencies = [ "protobuf-codegen", ] +[[package]] +name = "quick-xml" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.5" @@ -4660,7 +4761,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" dependencies = [ - "ashpd", + "ashpd 0.8.1", "block", "dispatch", "js-sys", @@ -4668,7 +4769,7 @@ dependencies = [ "objc", "objc-foundation", "objc_id", - "pollster", + "pollster 0.3.0", "raw-window-handle 0.6.2", "urlencoding", "wasm-bindgen", @@ -4677,6 +4778,30 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rfd" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a24763657bff09769a8ccf12c8b8a50416fb035fe199263b4c5071e4e3f006f" +dependencies = [ + "ashpd 0.10.2", + "block2", + "core-foundation 0.10.0", + "core-foundation-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "pollster 0.4.0", + "raw-window-handle 0.6.2", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.59.0", +] + [[package]] name = "ring" version = "0.17.8" @@ -4772,15 +4897,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5053,6 +5178,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -6425,6 +6556,66 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.72" @@ -6930,6 +7121,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" @@ -7087,9 +7287,45 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.0.1", + "zbus_names 3.0.0", + "zvariant 4.0.0", +] + +[[package]] +name = "zbus" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbddd8b6cb25d5d8ec1b23277b45299a98bfb220f1761ca11e186d5c702507f8" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-util", + "hex", + "nix 0.29.0", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.7.2", + "xdg-home", + "zbus_macros 5.4.0", + "zbus_names 4.2.0", + "zvariant 5.4.0", ] [[package]] @@ -7103,7 +7339,22 @@ dependencies = [ "quote", "regex", "syn 1.0.109", - "zvariant_utils", + "zvariant_utils 1.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac404d48b4e9cf193c8b49589f3280ceca5ff63519e7e64f55b4cf9c47ce146" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", + "zbus_names 4.2.0", + "zvariant 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -7114,7 +7365,19 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.0.0", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.7.2", + "zvariant 5.4.0", ] [[package]] @@ -7198,7 +7461,23 @@ dependencies = [ "serde", "static_assertions", "url", - "zvariant_derive", + "zvariant_derive 4.0.0", +] + +[[package]] +name = "zvariant" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "winnow 0.7.2", + "zvariant_derive 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -7211,7 +7490,20 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "zvariant_utils", + "zvariant_utils 1.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.87", + "zvariant_utils 3.2.0", ] [[package]] @@ -7224,3 +7516,17 @@ dependencies = [ "quote", "syn 1.0.109", ] + +[[package]] +name = "zvariant_utils" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.87", + "winnow 0.7.2", +] diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 4da226d..dcd84ec 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -90,6 +90,9 @@ tracing = "0.1.40" color-eyre = "0.6.3" crossbeam-queue = "0.3.11" lol_html = "2.2.0" +rfd = "0.15.2" +base64 = "0.22" +mime_guess = "2.0.5" [features] web = [ diff --git a/gui/src/app.rs b/gui/src/app.rs index ea0749c..11c575a 100644 --- a/gui/src/app.rs +++ b/gui/src/app.rs @@ -1,6 +1,8 @@ #![allow(non_snake_case)] +use base64::{display::Base64Display, prelude::BASE64_URL_SAFE}; use dioxus::prelude::*; +use mime_guess::Mime; use ordermap::OrderSet; use sir::{css, global_css}; use std::collections::HashMap; @@ -27,6 +29,12 @@ pub enum Command { markdown: String, channels: Vec, }, + SendFile { + bytes: Vec, + name: String, + mime: Option, + channels: Vec, + }, SetMute { mute: bool, }, @@ -243,6 +251,28 @@ pub fn Channel(id: ChannelId) -> Element { ) } +pub fn pick_and_send_file(net: &Coroutine) { + let channels = if let Some(user) = STATE.server.read().this_user() { + vec![user.channel] + } else { + return; + }; + let dialog = rfd::AsyncFileDialog::new().pick_file(); + let sender = net.tx(); + spawn(async move { + let Some(handle) = dialog.await else { return }; + let name = handle.file_name(); + let bytes = handle.read().await; + let mime = mime_guess::from_path(&name).first(); + let _ = sender.unbounded_send(SendFile { + bytes, + name, + mime, + channels, + }); + }); +} + #[component] pub fn ChatView() -> Element { let net: Coroutine = use_coroutine_handle(); @@ -321,6 +351,10 @@ pub fn ChatView() -> Element { } } } + button { + onclick: move |_| pick_and_send_file(&net), + "File" + } button { onclick: move |_| do_send(), "Send" diff --git a/gui/src/lib.rs b/gui/src/lib.rs index 5114d2f..734d267 100644 --- a/gui/src/lib.rs +++ b/gui/src/lib.rs @@ -217,6 +217,47 @@ fn accept_command( u.set_channel_id(channels); let _ = send_chan.unbounded_send(u.into()); } + SendFile { + ref bytes, + name, + mime, + channels, + } => { + use base64::{display::Base64Display, prelude::BASE64_STANDARD}; + let html = match mime { + Some(mime) if mime.type_() == "image" => format!( + "", + mime, + Base64Display::new(bytes, &BASE64_STANDARD) + ), + Some(mime) => format!( + "{name}", + mime, + Base64Display::new(bytes, &BASE64_STANDARD) + ), + None => format!( + "{name}", + Base64Display::new(bytes, &BASE64_STANDARD) + ), + }; + + { + let mut server = STATE.server.write(); + let Some(me) = server.session else { + bail!("not signed in with a session id") + }; + server.chat.push(Chat { + raw: "".to_string(), + dangerous_html: html.clone(), + sender: Some(me), + }) + } + + let mut u = msgs::TextMessage::new(); + u.set_message(html); + u.set_channel_id(channels); + let _ = send_chan.unbounded_send(u.into()); + } SetMute { mute } => { let mut u = msgs::UserState::new(); u.set_session(session);