8 Commits

Author SHA1 Message Date
liamwarfield 5f3466546e Add some Trait doc comments
Build Mumble Web 2 / windows_build (push) Successful in 2m25s
Build Mumble Web 2 / linux_build (push) Successful in 1m18s
Build Mumble Web 2 / android_build (push) Successful in 5m47s
Added comments to Audio(System|Player)Interface traits.
2026-02-17 21:28:05 -07:00
liamwarfield 8170383278 Remove connection::* import. 2026-02-17 21:28:05 -07:00
sam 2e86f68a3c some more review changes 2026-02-17 21:28:05 -07:00
sam 35b2a06e64 some ideas including stub 2026-02-17 21:28:05 -07:00
sam 09985e6031 move audio stuff into trait 2026-02-17 21:28:01 -07:00
sam 056a673bc0 all platform traits implemented & dumb async runtime imports 2026-02-17 21:26:03 -07:00
sam 411d923c2a wip improved trait shit 2026-02-17 21:26:03 -07:00
liamwarfield ff14f577fe Add Platform trait.
I did some more thinking about the whole trait/boundary stuff and reallized that we don't need the GUI to handle the generic-ness of a trait object since only 1 platform will ever be used in a binary. What do you think of the following:

1. Define a platform trait
2. Each platform defines a zero-sized struct implementing the trait (ex `WebPlatform`).
3. Create an ifdef'd type alias on those structs:

```
     // gui/src/platform/mod.rs
     #[cfg(feature = "web")]
     pub type CurrentPlatform = web::WebPlatform;
     #[cfg(feature = "desktop")]
     pub type CurrentPlatform = desktop::DesktopPlatform;
     #[cfg(feature = "mobile")]
     pub type CurrentPlatform = mobile::MobilePlatform;
```

4. Add a compile time assertion that `CurrentPlatform` implements `Platform`.

Pros:

- We don't end up working around async trait objects
- We define what functions are needed for a platform
- We save a little on binary size by avoiding a fully generic solution.

Cons:

- The trait does not really do much other than being a collection of functions.
- In some ways it seems like what we're currently doing but with extra steps.
2026-02-17 21:26:03 -07:00
12 changed files with 75 additions and 110 deletions
-41
View File
@@ -42,47 +42,6 @@ jobs:
path: target/release/mumble-web2-proxy path: target/release/mumble-web2-proxy
retention-days: 5 retention-days: 5
macos_build:
runs-on: macos
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Restore Rust cache
uses: actions/cache/restore@v4
with:
path: |
~/.cargo
./target
key: rust-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-
- name: Install cargo binstall
run: curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
- name: Install dioxus-cli
run: cargo binstall dioxus-cli --version 0.7.3 --no-confirm
- name: Build dioxus project
run: dx bundle --platform macos --release -p mumble-web2-gui
- name: Save Rust cache
if: always()
uses: actions/cache/save@v4
with:
path: |
~/.cargo
./target
key: rust-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
- name: Upload mumble-web2-gui Artifact
uses: https://gitea.com/actions/gitea-upload-artifact@v4
with:
name: mumble-web2-gui-macos-arm64
path: gui/dist
retention-days: 5
windows_build: windows_build:
runs-on: windows runs-on: windows
steps: steps:
+1 -1
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize, Default)] #[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct ProxyOverrides { pub struct ClientConfig {
pub proxy_url: Option<String>, pub proxy_url: Option<String>,
pub cert_hash: Option<Vec<u8>>, pub cert_hash: Option<Vec<u8>>,
pub any_server: bool, pub any_server: bool,
+9 -7
View File
@@ -1,12 +1,14 @@
localhost:64444 { localhost:64444 {
tls internal tls internal
# Proxy /config path to mumble-web2-proxy # Proxy /config path to mumble-web2-proxy
reverse_proxy /overrides http://127.0.0.1:4400 reverse_proxy /config http://127.0.0.1:4400
# Proxy /status path to mumble-web2-proxy # Proxy /status path to mumble-web2-proxy
reverse_proxy /status http://127.0.0.1:4400 reverse_proxy /status http://127.0.0.1:4400
# Proxy root path to dx-serve
reverse_proxy http://127.0.0.1:8080
# Proxy root path to dx-serve
reverse_proxy http://127.0.0.1:8080
} }
+1 -1
View File
@@ -20,7 +20,7 @@ services:
# volumes: # volumes:
# - ..:/app # - ..:/app
# environment: # environment:
# - MUMBLE_WEB2_PROXY_OVERRIDES_URL=https://localhost:64444/overrides # - MUMBLE_WEB2_GUI_CONFIG_URL=https://localhost:64444/config
# stdin_open: true # stdin_open: true
# tty: true # tty: true
# command: > # command: >
+18 -18
View File
@@ -2,7 +2,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use mime_guess::Mime; use mime_guess::Mime;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use ordermap::OrderSet; use ordermap::OrderSet;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@@ -23,7 +23,7 @@ pub enum Command {
Connect { Connect {
address: String, address: String,
username: String, username: String,
config: ProxyOverrides, config: ClientConfig,
}, },
SendChat { SendChat {
markdown: String, markdown: String,
@@ -454,7 +454,7 @@ pub fn ChatView() -> Element {
} }
#[component] #[component]
pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element { pub fn ControlView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let status = &STATE.status; let status = &STATE.status;
let server = STATE.server.read(); let server = STATE.server.read();
@@ -474,10 +474,10 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
let current_channel_name = server.channels_state.channels[&channel].name.clone(); let current_channel_name = server.channels_state.channels[&channel].name.clone();
let proxy_url = overrides let proxy_url = config
.read_unchecked() .read_unchecked()
.as_ref() .as_ref()
.and_then(|overrides| overrides.proxy_url.clone()); .and_then(|gui_config| gui_config.proxy_url.clone());
let connecting_color = "yellow"; let connecting_color = "yellow";
let connected_color = "oklch(0.55 0.1184 141.35)"; let connected_color = "oklch(0.55 0.1184 141.35)";
@@ -645,7 +645,7 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
} }
#[component] #[component]
pub fn ServerView(overrides: Resource<ProxyOverrides>) -> Element { pub fn ServerView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let server = STATE.server.read(); let server = STATE.server.read();
let Some(&UserState { let Some(&UserState {
@@ -676,14 +676,14 @@ pub fn ServerView(overrides: Resource<ProxyOverrides>) -> Element {
} }
div { div {
class: "server_control_box", class: "server_control_box",
ControlView { overrides } ControlView { config }
} }
} }
) )
} }
#[component] #[component]
pub fn LoginView(overrides: Resource<ProxyOverrides>) -> Element { pub fn LoginView(config: Resource<ClientConfig>) -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
let last_status = use_signal(|| None::<color_eyre::Result<ServerStatus>>); let last_status = use_signal(|| None::<color_eyre::Result<ServerStatus>>);
@@ -700,7 +700,7 @@ pub fn LoginView(overrides: Resource<ProxyOverrides>) -> Element {
if let Some(addr) = address_input() { if let Some(addr) = address_input() {
addr.clone() addr.clone()
} else { } else {
overrides() config()
.and_then(|c| c.proxy_url.clone()) .and_then(|c| c.proxy_url.clone())
.unwrap_or_default() .unwrap_or_default()
} }
@@ -712,13 +712,13 @@ pub fn LoginView(overrides: Resource<ProxyOverrides>) -> Element {
let do_connect = move |_| { let do_connect = move |_| {
//let _ = set_default_username(&username.read()); //let _ = set_default_username(&username.read());
let _ = Platform::set_default_username(&username.read()); let _ = Platform::set_default_username(&username.read());
if overrides.read().as_ref().is_some_and(|cfg| cfg.any_server) { if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
Platform::set_default_server(&address.read()); Platform::set_default_server(&address.read());
} }
net.send(Connect { net.send(Connect {
address: address.read().clone(), address: address.read().clone(),
username: username.read().clone(), username: username.read().clone(),
config: overrides.read().clone().unwrap_or_default(), config: config.read().clone().unwrap_or_default(),
}) })
}; };
let status = &STATE.status; let status = &STATE.status;
@@ -763,7 +763,7 @@ pub fn LoginView(overrides: Resource<ProxyOverrides>) -> Element {
None => rsx!(), None => rsx!(),
} }
} }
if overrides.read().as_ref().is_some_and(|cfg| cfg.any_server) { if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
div { div {
label { label {
for: "address-entry", for: "address-entry",
@@ -859,10 +859,10 @@ pub fn app() -> Element {
static STYLE: Asset = asset!("/assets/main.scss"); static STYLE: Asset = asset!("/assets/main.scss");
use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx)); use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
let overrides = use_resource(|| async move { let config = use_resource(|| async move {
match Platform::load_proxy_overrides().await { match Platform::load_config().await {
Ok(overrides) => overrides, Ok(config) => config,
Err(_) => ProxyOverrides::default(), Err(_) => ClientConfig::default(),
} }
}); });
@@ -874,8 +874,8 @@ pub fn app() -> Element {
document::Link{ rel: "stylesheet", href: STYLE } document::Link{ rel: "stylesheet", href: STYLE }
match *STATE.status.read() { match *STATE.status.read() {
Connected => rsx!(ServerView { overrides }), Connected => rsx!(ServerView { config }),
_ => rsx!(LoginView { overrides }), _ => rsx!(LoginView { config }),
} }
) )
} }
+4 -4
View File
@@ -8,13 +8,13 @@ use tokio::net::TcpStream;
use tokio_rustls::rustls; use tokio_rustls::rustls;
use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier};
use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use tokio_rustls::rustls::ClientConfig; use tokio_rustls::rustls::ClientConfig as RlsClientConfig;
use tokio_rustls::rustls::DigitallySignedStruct; use tokio_rustls::rustls::DigitallySignedStruct;
use tokio_rustls::TlsConnector; use tokio_rustls::TlsConnector;
use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _}; use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _};
use tracing::{info, instrument}; use tracing::{info, instrument};
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
#[derive(Debug)] #[derive(Debug)]
struct NoCertificateVerification; struct NoCertificateVerification;
@@ -73,11 +73,11 @@ pub async fn network_connect(
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
info!("connecting"); info!("connecting");
let config = ClientConfig::builder() let config = RlsClientConfig::builder()
.dangerous() .dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_custom_certificate_verifier(Arc::new(NoCertificateVerification))
.with_no_client_auth(); .with_no_client_auth();
+5 -5
View File
@@ -2,7 +2,7 @@ use crate::app::Command;
use color_eyre::eyre::Error; use color_eyre::eyre::Error;
use dioxus::hooks::UnboundedReceiver; use dioxus::hooks::UnboundedReceiver;
use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs}; use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration; use std::time::Duration;
@@ -16,8 +16,8 @@ impl super::PlatformInterface for DesktopPlatform {
tokio::time::sleep(duration).await; tokio::time::sleep(duration).await;
} }
async fn load_proxy_overrides() -> color_eyre::Result<ProxyOverrides> { async fn load_config() -> color_eyre::Result<ClientConfig> {
Ok(ProxyOverrides { Ok(ClientConfig {
proxy_url: None, proxy_url: None,
cert_hash: None, cert_hash: None,
any_server: true, any_server: true,
@@ -50,9 +50,9 @@ impl super::PlatformInterface for DesktopPlatform {
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
super::connect::network_connect(address, username, event_rx, overrides).await super::connect::network_connect(address, username, event_rx, gui_config).await
} }
async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> { async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
+6 -5
View File
@@ -1,7 +1,8 @@
use crate::app::Command; use crate::app::Command;
use color_eyre::eyre::Error; use color_eyre::eyre::Error;
use dioxus::hooks::UnboundedReceiver; use dioxus::hooks::UnboundedReceiver;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use std::future::Future;
use std::time::Duration; use std::time::Duration;
/// Mobile platform implementation using Tokio, native audio, and Android permissions. /// Mobile platform implementation using Tokio, native audio, and Android permissions.
@@ -10,8 +11,8 @@ pub struct MobilePlatform;
impl super::PlatformInterface for MobilePlatform { impl super::PlatformInterface for MobilePlatform {
type AudioSystem = super::native_audio::NativeAudioSystem; type AudioSystem = super::native_audio::NativeAudioSystem;
async fn load_proxy_overrides() -> color_eyre::Result<ProxyOverrides> { async fn load_config() -> color_eyre::Result<ClientConfig> {
Ok(ProxyOverrides { Ok(ClientConfig {
proxy_url: None, proxy_url: None,
cert_hash: None, cert_hash: None,
any_server: true, any_server: true,
@@ -38,9 +39,9 @@ impl super::PlatformInterface for MobilePlatform {
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
super::connect::network_connect(address, username, event_rx, overrides).await super::connect::network_connect(address, username, event_rx, gui_config).await
} }
async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> { async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
+3 -3
View File
@@ -7,7 +7,7 @@
use crate::{app::Command, effects::AudioProcessor}; use crate::{app::Command, effects::AudioProcessor};
use color_eyre::eyre::Error; use color_eyre::eyre::Error;
use dioxus::hooks::UnboundedReceiver; use dioxus::hooks::UnboundedReceiver;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use std::future::Future; use std::future::Future;
use std::time::Duration; use std::time::Duration;
@@ -67,7 +67,7 @@ pub trait PlatformInterface {
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
proxy_overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> impl Future<Output = Result<(), Error>>; ) -> impl Future<Output = Result<(), Error>>;
/// Get server status (user count, version, etc.). /// Get server status (user count, version, etc.).
@@ -76,7 +76,7 @@ pub trait PlatformInterface {
) -> impl Future<Output = color_eyre::Result<ServerStatus>>; ) -> impl Future<Output = color_eyre::Result<ServerStatus>>;
/// Load the proxy overrides (proxy URL, cert hash, etc.). /// Load the proxy overrides (proxy URL, cert hash, etc.).
fn load_proxy_overrides() -> impl Future<Output = color_eyre::Result<ProxyOverrides>>; fn load_config() -> impl Future<Output = color_eyre::Result<ClientConfig>>;
/// Load saved username. /// Load saved username.
fn load_username() -> Option<String>; fn load_username() -> Option<String>;
+3 -3
View File
@@ -3,7 +3,7 @@
use crate::effects::AudioProcessor; use crate::effects::AudioProcessor;
use color_eyre::eyre::Error; use color_eyre::eyre::Error;
use dioxus::hooks::UnboundedReceiver; use dioxus::hooks::UnboundedReceiver;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use std::future::Future; use std::future::Future;
pub struct StubPlatform; pub struct StubPlatform;
@@ -23,7 +23,7 @@ impl super::PlatformInterface for StubPlatform {
_address: String, _address: String,
_username: String, _username: String,
_event_rx: &mut UnboundedReceiver<crate::app::Command>, _event_rx: &mut UnboundedReceiver<crate::app::Command>,
_overrides: &ProxyOverrides, _gui_config: &ClientConfig,
) -> impl Future<Output = Result<(), Error>> { ) -> impl Future<Output = Result<(), Error>> {
async { panic!("stubbed platform") } async { panic!("stubbed platform") }
} }
@@ -34,7 +34,7 @@ impl super::PlatformInterface for StubPlatform {
async { panic!("stubbed platform") } async { panic!("stubbed platform") }
} }
fn load_proxy_overrides() -> impl Future<Output = color_eyre::Result<ProxyOverrides>> { fn load_config() -> impl Future<Output = color_eyre::Result<ClientConfig>> {
async { panic!("stubbed platform") } async { panic!("stubbed platform") }
} }
+11 -11
View File
@@ -6,7 +6,7 @@ use dioxus::prelude::*;
use gloo_timers::future::TimeoutFuture; use gloo_timers::future::TimeoutFuture;
use js_sys::Float32Array; use js_sys::Float32Array;
use mumble_protocol::control::ClientControlCodec; use mumble_protocol::control::ClientControlCodec;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use reqwest::Url; use reqwest::Url;
use std::future::Future; use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
@@ -89,16 +89,16 @@ impl super::PlatformInterface for WebPlatform {
// No-op on web // No-op on web
} }
async fn load_proxy_overrides() -> color_eyre::Result<ProxyOverrides> { async fn load_config() -> color_eyre::Result<ClientConfig> {
let overrides = match option_env!("MUMBLE_WEB2_PROXY_OVERRIDES_URL") { let config_url = match option_env!("MUMBLE_WEB2_GUI_CONFIG_URL") {
Some(url) => Url::parse(url)?, Some(url) => Url::parse(url)?,
None => absolute_url("overrides")?, None => absolute_url("config")?,
}; };
info!("loading config from {}", overrides); info!("loading config from {}", config_url);
let config = reqwest::get(overrides) let config = reqwest::get(config_url)
.await? .await?
.json::<ProxyOverrides>() .json::<ClientConfig>()
.await?; .await?;
Ok(config) Ok(config)
@@ -133,9 +133,9 @@ impl super::PlatformInterface for WebPlatform {
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
network_connect(address, username, event_rx, overrides).await network_connect(address, username, event_rx, gui_config).await
} }
async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> { async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
@@ -456,7 +456,7 @@ pub async fn network_connect(
address: String, address: String,
username: String, username: String,
event_rx: &mut UnboundedReceiver<Command>, event_rx: &mut UnboundedReceiver<Command>,
overrides: &ProxyOverrides, gui_config: &ClientConfig,
) -> Result<(), Error> { ) -> Result<(), Error> {
info!("connecting"); info!("connecting");
@@ -469,7 +469,7 @@ pub async fn network_connect(
) )
.ey()?; .ey()?;
if let Some(server_hash) = &overrides.cert_hash { if let Some(server_hash) = &gui_config.cert_hash {
let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice()); let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice());
web_sys::js_sys::Reflect::set(&object, &"value".into(), &hash).ey()?; web_sys::js_sys::Reflect::set(&object, &"value".into(), &hash).ey()?;
} }
+14 -11
View File
@@ -1,5 +1,5 @@
use color_eyre::eyre::{anyhow, bail, Context, Result}; use color_eyre::eyre::{anyhow, bail, Context, Result};
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ClientConfig, ServerStatus};
use rand::Rng; use rand::Rng;
use salvo::conn::rustls::{Keycert, RustlsConfig}; use salvo::conn::rustls::{Keycert, RustlsConfig};
use salvo::cors::{AllowOrigin, Cors}; use salvo::cors::{AllowOrigin, Cors};
@@ -16,7 +16,7 @@ use tokio::net::TcpStream;
use tokio::pin; use tokio::pin;
use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier};
use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use tokio_rustls::rustls::{ClientConfig, DigitallySignedStruct}; use tokio_rustls::rustls::{ClientConfig as RlsClientConfig, DigitallySignedStruct};
use tokio_rustls::{rustls, TlsConnector}; use tokio_rustls::{rustls, TlsConnector};
use tracing::info; use tracing::info;
use tracing::info_span; use tracing::info_span;
@@ -77,7 +77,7 @@ async fn main() -> Result<()> {
.install_default() .install_default()
.map_err(|e| anyhow!("could not install crypto provider {e:?}"))?; .map_err(|e| anyhow!("could not install crypto provider {e:?}"))?;
let mut overrides = ProxyOverrides { let mut client_config = ClientConfig {
proxy_url: match &server_config.proxy_url { proxy_url: match &server_config.proxy_url {
Some(url) => Some(url.to_string()), Some(url) => Some(url.to_string()),
None => None, None => None,
@@ -102,7 +102,7 @@ async fn main() -> Result<()> {
let cert = cert_params.self_signed(&key_pair)?; let cert = cert_params.self_signed(&key_pair)?;
let hash = hmac_sha256::Hash::hash(cert.der().as_ref()); let hash = hmac_sha256::Hash::hash(cert.der().as_ref());
overrides.cert_hash = Some(hash.into()); client_config.cert_hash = Some(hash.into());
(cert.pem().into(), key_pair.serialize_pem().into()) (cert.pem().into(), key_pair.serialize_pem().into())
} }
@@ -122,11 +122,14 @@ async fn main() -> Result<()> {
}; };
let rustls_config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice())); let rustls_config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));
info!("proxy overrides:\n{}", toml::to_string_pretty(&overrides)?); info!(
"client config:\n{}",
toml::to_string_pretty(&client_config)?
);
let config_craft = ConfigCraft { let config_craft = ConfigCraft {
server_config: server_config.clone(), server_config: server_config.clone(),
overrides, client_config,
}; };
let status_craft = StatusCraft { let status_craft = StatusCraft {
@@ -136,7 +139,7 @@ async fn main() -> Result<()> {
// Server routing // Server routing
let mut router = Router::new() let mut router = Router::new()
.push(Router::with_path("/proxy").goal(config_craft.connect_proxy())) .push(Router::with_path("/proxy").goal(config_craft.connect_proxy()))
.push(Router::with_path("/overrides").get(config_craft.get_overrides())) .push(Router::with_path("/config").get(config_craft.get_config()))
.push(Router::with_path("/status").get(status_craft.get_status())) .push(Router::with_path("/status").get(status_craft.get_status()))
.hoop(Logger::new()); .hoop(Logger::new());
if let Some(gui_path) = server_config.gui_path.clone() { if let Some(gui_path) = server_config.gui_path.clone() {
@@ -249,14 +252,14 @@ impl StatusCraft {
#[derive(Clone)] #[derive(Clone)]
pub struct ConfigCraft { pub struct ConfigCraft {
server_config: Arc<Config>, server_config: Arc<Config>,
overrides: ProxyOverrides, client_config: ClientConfig,
} }
#[craft] #[craft]
impl ConfigCraft { impl ConfigCraft {
#[craft(handler)] #[craft(handler)]
async fn get_overrides(&self) -> Json<ProxyOverrides> { async fn get_config(&self) -> Json<ClientConfig> {
Json(self.overrides.clone()) Json(self.client_config.clone())
} }
#[craft(handler)] #[craft(handler)]
@@ -317,7 +320,7 @@ async fn connect_proxy_impl(
) -> Result<()> { ) -> Result<()> {
info!("connecting to Mumble server..."); info!("connecting to Mumble server...");
let config = ClientConfig::builder() let config = RlsClientConfig::builder()
.dangerous() .dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_custom_certificate_verifier(Arc::new(NoCertificateVerification))
.with_no_client_auth(); .with_no_client_auth();