Put model state into an Arc (#28)
Build Mumble Web 2 / macos_build (push) Successful in 1m14s
Build Mumble Web 2 / linux_build (push) Successful in 1m27s
Build Mumble Web 2 / windows_build (push) Successful in 2m56s
Build Mumble Web 2 / android_build (push) Successful in 4m39s

Previously the model state was in a `static STATE` to make it accessible to all the various subsystems. This moves it into an Arc and plumbs the reference around via function arguments. That allows us to do non-static initialization, eg based on user config. I also moved some things into dioxus context.

Co-authored-by: Sam Sartor <me@samsartor.com>
Co-committed-by: Sam Sartor <me@samsartor.com>
This commit was merged in pull request #28.
This commit is contained in:
2026-03-30 00:56:36 +00:00
committed by Sam Sartor
parent 7337b3e49b
commit f0ce15000e
9 changed files with 115 additions and 70 deletions
+24 -19
View File
@@ -1,7 +1,6 @@
use app::Chat;
use app::Command;
use app::ConnectionState;
use app::STATE;
use asynchronous_codec::FramedRead;
use asynchronous_codec::FramedWrite;
use color_eyre::eyre::{bail, Error};
@@ -27,6 +26,8 @@ use std::time::Duration;
use tracing::error;
use tracing::info;
use crate::app::SharedState;
use crate::app::State;
use crate::effects::AudioProcessor;
use crate::imp::{
AudioPlayer, AudioPlayerInterface as _, AudioSystem, AudioSystemInterface as _, Platform,
@@ -38,7 +39,7 @@ mod effects;
pub mod imp;
mod msghtml;
pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>, state: SharedState) {
loop {
let Some(Command::Connect {
address,
@@ -49,21 +50,23 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
panic!("did not receive connect command")
};
*STATE.server.write() = Default::default();
*STATE.status.write() = ConnectionState::Connecting;
*state.server.write_unchecked() = Default::default();
*state.status.write_unchecked() = ConnectionState::Connecting;
if let Err(error) =
Platform::network_connect(address, username, &mut event_rx, &config).await
Platform::network_connect(address, username, &mut event_rx, &config, state.clone())
.await
{
error!("could not connect {:?}", error);
*STATE.status.write() = ConnectionState::Failed(error.to_string());
*state.status.write_unchecked() = ConnectionState::Failed(error.to_string());
} else {
*STATE.status.write() = ConnectionState::Disconnected;
*state.status.write_unchecked() = ConnectionState::Disconnected;
}
}
}
pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin + 'static>(
username: String,
state: SharedState,
event_rx: &mut UnboundedReceiver<Command>,
mut reader: FramedRead<R, ControlCodec<Serverbound, Clientbound>>,
mut writer: FramedWrite<W, ControlCodec<Serverbound, Clientbound>>,
@@ -149,7 +152,7 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
if !matches!(msg, ControlPacket::UDPTunnel(_) | ControlPacket::Ping(_)) {
info!("receiving packet {:#?}", msg);
}
let res = accept_packet(msg, &mut audio, &mut decoder_map);
let res = accept_packet(msg, &mut audio, &mut decoder_map, &state);
if let Err(err) = res {
error!("error accepting packet {:?}", err)
}
@@ -168,7 +171,7 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
match command {
Some(Command::Disconnect) => break,
Some(command) => {
let res = accept_command(command, &mut send_chan, &mut audio);
let res = accept_command(command, &mut send_chan, &mut audio, &state);
if let Err(err) = res {
info!("error accepting command {:?}", err)
}
@@ -187,9 +190,10 @@ fn accept_command(
command: Command,
send_chan: &mut UnboundedSender<ControlPacket<mumble_protocol::Serverbound>>,
audio: &mut AudioSystem,
state: &State,
) -> Result<(), Error> {
use Command::*;
let Some(session) = STATE.server.read().session else {
let Some(session) = state.server.read().session else {
bail!("no session id")
};
@@ -212,7 +216,7 @@ fn accept_command(
};
{
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
let Some(me) = server.session else {
bail!("not signed in with a session id")
};
@@ -253,7 +257,7 @@ fn accept_command(
};
{
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
let Some(me) = server.session else {
bail!("not signed in with a session id")
};
@@ -304,6 +308,7 @@ fn accept_packet(
msg: ControlPacket<mumble_protocol::Clientbound>,
audio_context: &mut AudioSystem,
player_map: &mut HashMap<u32, AudioPlayer>,
state: &State,
) -> Result<(), Error> {
match msg {
ControlPacket::UDPTunnel(u) => {
@@ -340,15 +345,15 @@ fn accept_packet(
}
}
ControlPacket::ChannelState(u) => {
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
server.channels_state.update_from_channel_state(&u);
}
ControlPacket::ChannelRemove(u) => {
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
server.channels_state.update_from_channel_remove(&u);
}
ControlPacket::UserState(u) => {
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
let server = &mut *server;
let id = u.get_session();
@@ -392,7 +397,7 @@ fn accept_packet(
}
}
ControlPacket::UserRemove(u) => {
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
let id = u.get_session();
if let Some(state) = server.users.remove(&id) {
if let Some(parent) = server.channels_state.channels.get_mut(&state.channel) {
@@ -401,7 +406,7 @@ fn accept_packet(
}
}
ControlPacket::TextMessage(u) => {
let mut server = STATE.server.write();
let mut server = state.server.write_unchecked();
if u.has_message() {
let text = u.get_message().to_string();
server.chat.push(Chat {
@@ -416,8 +421,8 @@ fn accept_packet(
}
}
ControlPacket::ServerSync(u) => {
*STATE.status.write() = ConnectionState::Connected;
let mut server = STATE.server.write();
*state.status.write_unchecked() = ConnectionState::Connected;
let mut server = state.server.write_unchecked();
if u.has_welcome_text() {
let text = u.get_welcome_text().to_string();
server.chat.push(Chat {