Compare commits
2 Commits
main
...
swarfield/vibing
| Author | SHA1 | Date | |
|---|---|---|---|
| 51f05593ac | |||
| eab8f1d6a7 |
+3
-4
@@ -1,10 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||||
pub struct ClientConfig {
|
pub struct ProxyOverides {
|
||||||
pub proxy_url: Option<String>,
|
pub proxy_url: String,
|
||||||
pub cert_hash: Option<Vec<u8>>,
|
pub cert_hash: Vec<u8>,
|
||||||
pub any_server: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||||
|
|||||||
+18
-12
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
use mumble_web2_common::{ClientConfig, ServerStatus};
|
use mumble_web2_common::{ProxyOverides, ServerStatus};
|
||||||
use ordermap::OrderSet;
|
use ordermap::OrderSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ pub enum Command {
|
|||||||
Connect {
|
Connect {
|
||||||
address: String,
|
address: String,
|
||||||
username: String,
|
username: String,
|
||||||
config: ClientConfig,
|
config: ProxyOverides,
|
||||||
},
|
},
|
||||||
SendChat {
|
SendChat {
|
||||||
markdown: String,
|
markdown: String,
|
||||||
@@ -309,7 +309,7 @@ pub fn ChatView() -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ControlView(config: Resource<ClientConfig>) -> Element {
|
pub fn ControlView(config: Resource<Option<ProxyOverides>>) -> 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();
|
||||||
@@ -331,7 +331,8 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
|
|||||||
let proxy_url = config
|
let proxy_url = config
|
||||||
.read_unchecked()
|
.read_unchecked()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|gui_config| gui_config.proxy_url.clone());
|
.and_then(|opt| opt.as_ref())
|
||||||
|
.map(|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)";
|
||||||
@@ -508,7 +509,7 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ServerView(config: Resource<ClientConfig>) -> Element {
|
pub fn ServerView(config: Resource<Option<ProxyOverides>>) -> 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 {
|
||||||
@@ -546,7 +547,7 @@ pub fn ServerView(config: Resource<ClientConfig>) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
pub fn LoginView(config: Resource<Option<ProxyOverides>>) -> 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>>);
|
||||||
@@ -564,7 +565,8 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
|||||||
addr.clone()
|
addr.clone()
|
||||||
} else {
|
} else {
|
||||||
config()
|
config()
|
||||||
.and_then(|c| c.proxy_url.clone())
|
.flatten()
|
||||||
|
.map(|c| c.proxy_url.clone())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -575,13 +577,13 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
|||||||
let do_connect = move |_| {
|
let do_connect = move |_| {
|
||||||
//let _ = set_default_username(&username.read());
|
//let _ = set_default_username(&username.read());
|
||||||
let _ = imp::set_default_username(&username.read());
|
let _ = imp::set_default_username(&username.read());
|
||||||
if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
|
if config.read().as_ref().is_some_and(|opt| opt.is_none()) {
|
||||||
imp::set_default_server(&address.read());
|
imp::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: config.read().clone().unwrap_or_default(),
|
config: config.read().clone().flatten().unwrap_or_default(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let status = &STATE.status;
|
let status = &STATE.status;
|
||||||
@@ -626,7 +628,7 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
|
|||||||
None => rsx!(),
|
None => rsx!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
|
if config.read().as_ref().is_some_and(|opt| opt.is_none()) {
|
||||||
div {
|
div {
|
||||||
label {
|
label {
|
||||||
for: "address-entry",
|
for: "address-entry",
|
||||||
@@ -723,9 +725,9 @@ pub fn app() -> Element {
|
|||||||
|
|
||||||
use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
|
use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
|
||||||
let config = use_resource(|| async move {
|
let config = use_resource(|| async move {
|
||||||
match imp::load_config().await {
|
match imp::load_proxy_overides().await {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(_) => ClientConfig::default(),
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -734,9 +736,13 @@ pub fn app() -> Element {
|
|||||||
document::Link{ rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" }
|
document::Link{ rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" }
|
||||||
document::Link{ rel: "stylesheet", href: STYLE }
|
document::Link{ rel: "stylesheet", href: STYLE }
|
||||||
|
|
||||||
|
if config.read().is_none() {
|
||||||
|
div { class: "loading", "Loading..." }
|
||||||
|
} else {
|
||||||
match *STATE.status.read() {
|
match *STATE.status.read() {
|
||||||
Connected => rsx!(ServerView { config }),
|
Connected => rsx!(ServerView { config }),
|
||||||
_ => rsx!(LoginView { config }),
|
_ => rsx!(LoginView { config }),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use dioxus::hooks::UnboundedReceiver;
|
|||||||
use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
|
use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
|
||||||
use futures::io::{AsyncRead, AsyncWrite};
|
use futures::io::{AsyncRead, AsyncWrite};
|
||||||
use mumble_protocol::control::ClientControlCodec;
|
use mumble_protocol::control::ClientControlCodec;
|
||||||
use mumble_web2_common::{ClientConfig, ServerStatus};
|
use mumble_web2_common::{ProxyOverides, ServerStatus};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
@@ -284,7 +284,7 @@ pub async fn network_connect(
|
|||||||
address: String,
|
address: String,
|
||||||
username: String,
|
username: String,
|
||||||
event_rx: &mut UnboundedReceiver<Command>,
|
event_rx: &mut UnboundedReceiver<Command>,
|
||||||
gui_config: &ClientConfig,
|
gui_config: &ProxyOverides,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
info!("connecting");
|
info!("connecting");
|
||||||
|
|
||||||
@@ -366,12 +366,8 @@ pub fn load_server_url() -> Option<String> {
|
|||||||
config.get("server").cloned()
|
config.get("server").cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_config() -> color_eyre::Result<ClientConfig> {
|
pub async fn load_proxy_overides() -> color_eyre::Result<Option<ProxyOverides>> {
|
||||||
Ok(ClientConfig {
|
Ok(None)
|
||||||
proxy_url: None,
|
|
||||||
cert_hash: None,
|
|
||||||
any_server: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
|
pub async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
|
||||||
|
|||||||
+7
-7
@@ -6,7 +6,7 @@ use futures::{AsyncRead, AsyncWrite};
|
|||||||
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::{ClientConfig, ServerStatus};
|
use mumble_web2_common::{ProxyOverides, ServerStatus};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -329,7 +329,7 @@ pub async fn network_connect(
|
|||||||
address: String,
|
address: String,
|
||||||
username: String,
|
username: String,
|
||||||
event_rx: &mut UnboundedReceiver<Command>,
|
event_rx: &mut UnboundedReceiver<Command>,
|
||||||
gui_config: &ClientConfig,
|
gui_config: &ProxyOverides,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
info!("connecting");
|
info!("connecting");
|
||||||
|
|
||||||
@@ -342,8 +342,8 @@ pub async fn network_connect(
|
|||||||
)
|
)
|
||||||
.ey()?;
|
.ey()?;
|
||||||
|
|
||||||
if let Some(server_hash) = &gui_config.cert_hash {
|
if !gui_config.cert_hash.is_empty() {
|
||||||
let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice());
|
let hash = web_sys::js_sys::Uint8Array::from(gui_config.cert_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()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ pub fn absolute_url(path: &str) -> Result<Url, Error> {
|
|||||||
Ok(Url::parse(&location.href().ey()?)?.join(path)?)
|
Ok(Url::parse(&location.href().ey()?)?.join(path)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_config() -> color_eyre::Result<ClientConfig> {
|
pub async fn load_proxy_overides() -> color_eyre::Result<Option<ProxyOverides>> {
|
||||||
let config_url = match option_env!("MUMBLE_WEB2_GUI_CONFIG_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("config")?,
|
None => absolute_url("config")?,
|
||||||
@@ -431,10 +431,10 @@ pub async fn load_config() -> color_eyre::Result<ClientConfig> {
|
|||||||
|
|
||||||
let config = reqwest::get(config_url)
|
let config = reqwest::get(config_url)
|
||||||
.await?
|
.await?
|
||||||
.json::<ClientConfig>()
|
.json::<ProxyOverides>()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(config)
|
Ok(Some(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
|
pub async fn get_status(client: &reqwest::Client) -> color_eyre::Result<ServerStatus> {
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ use mumble_protocol::voice::VoicePacket;
|
|||||||
use mumble_protocol::voice::VoicePacketPayload;
|
use mumble_protocol::voice::VoicePacketPayload;
|
||||||
use mumble_protocol::Clientbound;
|
use mumble_protocol::Clientbound;
|
||||||
use mumble_protocol::Serverbound;
|
use mumble_protocol::Serverbound;
|
||||||
use mumble_web2_common::ClientConfig;
|
use mumble_web2_common::ProxyOverides;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|||||||
+11
-11
@@ -1,5 +1,5 @@
|
|||||||
use color_eyre::eyre::{anyhow, bail, Context, Result};
|
use color_eyre::eyre::{anyhow, bail, Context, Result};
|
||||||
use mumble_web2_common::{ClientConfig, ServerStatus};
|
use mumble_web2_common::{ProxyOverides, 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};
|
||||||
@@ -77,13 +77,13 @@ 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 client_config = ClientConfig {
|
let mut client_config = ProxyOverides {
|
||||||
proxy_url: match &server_config.proxy_url {
|
proxy_url: server_config
|
||||||
Some(url) => Some(url.to_string()),
|
.proxy_url
|
||||||
None => None,
|
.as_ref()
|
||||||
},
|
.map(|url| url.to_string())
|
||||||
cert_hash: None,
|
.unwrap_or_default(),
|
||||||
any_server: false,
|
cert_hash: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cert, key) = match (&server_config.cert_path, &server_config.key_path) {
|
let (cert, key) = match (&server_config.cert_path, &server_config.key_path) {
|
||||||
@@ -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());
|
||||||
client_config.cert_hash = Some(hash.into());
|
client_config.cert_hash = hash.into();
|
||||||
|
|
||||||
(cert.pem().into(), key_pair.serialize_pem().into())
|
(cert.pem().into(), key_pair.serialize_pem().into())
|
||||||
}
|
}
|
||||||
@@ -252,13 +252,13 @@ impl StatusCraft {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ConfigCraft {
|
pub struct ConfigCraft {
|
||||||
server_config: Arc<Config>,
|
server_config: Arc<Config>,
|
||||||
client_config: ClientConfig,
|
client_config: ProxyOverides,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[craft]
|
#[craft]
|
||||||
impl ConfigCraft {
|
impl ConfigCraft {
|
||||||
#[craft(handler)]
|
#[craft(handler)]
|
||||||
async fn get_config(&self) -> Json<ClientConfig> {
|
async fn get_config(&self) -> Json<ProxyOverides> {
|
||||||
Json(self.client_config.clone())
|
Json(self.client_config.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user