aboutsummaryrefslogtreecommitdiffstats
path: root/mumd
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-06-19 22:42:21 +0200
committerGustav Sörnäs <gustav@sornas.net>2021-06-19 22:42:21 +0200
commitaabf3a3b458b88eefd8b18ebc5ed9e593d4a694f (patch)
tree7029d7473ab30eab5fec866f65e736a26320dde8 /mumd
parent99ed190ca9691a46719c8a88d3f2437ba8e3c2ff (diff)
parent9002462953e7cba70d5aafee7ed2a87087252f49 (diff)
downloadmum-aabf3a3b458b88eefd8b18ebc5ed9e593d4a694f.tar.gz
Merge remote-tracking branch 'origin/main' into ogg
Diffstat (limited to 'mumd')
-rw-r--r--mumd/Cargo.toml4
-rw-r--r--mumd/src/audio.rs11
-rw-r--r--mumd/src/audio/input.rs16
-rw-r--r--mumd/src/audio/output.rs18
-rw-r--r--mumd/src/audio/transformers.rs1
-rw-r--r--mumd/src/client.rs2
-rw-r--r--mumd/src/error.rs6
-rw-r--r--mumd/src/main.rs43
-rw-r--r--mumd/src/network.rs4
-rw-r--r--mumd/src/network/tcp.rs41
-rw-r--r--mumd/src/network/udp.rs19
-rw-r--r--mumd/src/state.rs43
-rw-r--r--mumd/src/state/server.rs2
-rw-r--r--mumd/src/state/user.rs2
14 files changed, 142 insertions, 70 deletions
diff --git a/mumd/Cargo.toml b/mumd/Cargo.toml
index 6de74fa..02a069c 100644
--- a/mumd/Cargo.toml
+++ b/mumd/Cargo.toml
@@ -24,8 +24,6 @@ cpal = "0.13"
bytes = "1.0"
dasp_interpolate = { version = "0.11", features = ["linear"] }
dasp_signal = "0.11"
-dasp_frame = "0.11"
-dasp_sample = "0.11"
dasp_ring_buffer = "0.11"
futures-util = { version = "0.3", features = ["sink"]}
futures-channel = "0.3"
@@ -33,13 +31,11 @@ hound = "3.4"
log = "0.4"
mumble-protocol = "0.4.1"
native-tls = "0.2"
-openssl = { version = "0.10" }
opus = "0.2"
serde = { version = "1.0", features = ["derive"] }
strum = "0.20"
strum_macros = "0.20"
tokio = { version = "1.0", features = ["macros", "rt", "rt-multi-thread", "sync", "net", "time", "fs"] }
-tokio-stream = "0.1.0"
tokio-native-tls = "0.3"
tokio-util = { version = "0.6", features = ["codec", "net"] }
bincode = "1.3.2"
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs
index fb22b44..bbaf2e1 100644
--- a/mumd/src/audio.rs
+++ b/mumd/src/audio.rs
@@ -17,6 +17,7 @@ use mumble_protocol::voice::{VoicePacket, VoicePacketPayload};
use mumble_protocol::Serverbound;
use mumlib::config::SoundEffect;
use std::collections::{hash_map::Entry, HashMap};
+use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use tokio::sync::watch;
@@ -77,6 +78,16 @@ impl AudioInput {
}
}
+impl Debug for AudioInput {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("AudioInput")
+ .field("device", &self.device)
+ .field("channel_receiver", &"receiver")
+ .finish()
+ }
+}
+
+#[derive(Debug)]
/// Audio output state. The audio is received from each client over the network,
/// decoded, merged and finally played to an [AudioOutputDevice] (e.g. speaker,
/// headphones, ...).
diff --git a/mumd/src/audio/input.rs b/mumd/src/audio/input.rs
index 37ea60a..4dfc465 100644
--- a/mumd/src/audio/input.rs
+++ b/mumd/src/audio/input.rs
@@ -2,6 +2,7 @@
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{InputCallbackInfo, Sample, SampleFormat, SampleRate, StreamConfig};
use log::*;
+use std::fmt::Debug;
use tokio::sync::watch;
use crate::audio::SAMPLE_RATE;
@@ -171,13 +172,13 @@ impl AudioInputDevice for DefaultAudioInputDevice {
fn play(&self) -> Result<(), AudioError> {
self.stream
.play()
- .map_err(|e| AudioError::InputPlayError(e))
+ .map_err(AudioError::InputPlayError)
}
fn pause(&self) -> Result<(), AudioError> {
self.stream
.pause()
- .map_err(|e| AudioError::InputPauseError(e))
+ .map_err(AudioError::InputPauseError)
}
fn set_volume(&self, volume: f32) {
@@ -192,3 +193,14 @@ impl AudioInputDevice for DefaultAudioInputDevice {
self.channels as usize
}
}
+
+impl Debug for DefaultAudioInputDevice {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("DefaultAudioInputDevice")
+ .field("sample_receiver", &self.sample_receiver)
+ .field("channels", &self.channels)
+ .field("volume_sender", &self.volume_sender)
+ .field("stream", &"cpal::Stream")
+ .finish()
+ }
+}
diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs
index 6aa67dd..980e65f 100644
--- a/mumd/src/audio/output.rs
+++ b/mumd/src/audio/output.rs
@@ -11,6 +11,7 @@ use dasp_ring_buffer::Bounded;
use log::*;
use mumble_protocol::voice::VoicePacketPayload;
use std::collections::{HashMap, VecDeque};
+use std::fmt::Debug;
use std::iter;
use std::ops::AddAssign;
use std::sync::{Arc, Mutex};
@@ -19,6 +20,7 @@ use tokio::sync::watch;
type ClientStreamKey = (VoiceStreamType, u32);
/// State for decoding audio received from another user.
+#[derive(Debug)]
pub struct ClientAudioData {
buf: Bounded<Vec<f32>>,
output_channels: opus::Channels,
@@ -66,6 +68,7 @@ impl ClientAudioData {
}
/// Collected state for client opus decoders and sound effects.
+#[derive(Debug)]
pub struct ClientStream {
buffer_clients: HashMap<ClientStreamKey, ClientAudioData>,
buffer_effects: VecDeque<f32>,
@@ -243,13 +246,13 @@ impl AudioOutputDevice for DefaultAudioOutputDevice {
fn play(&self) -> Result<(), AudioError> {
self.stream
.play()
- .map_err(|e| AudioError::OutputPlayError(e))
+ .map_err(AudioError::OutputPlayError)
}
fn pause(&self) -> Result<(), AudioError> {
self.stream
.pause()
- .map_err(|e| AudioError::OutputPauseError(e))
+ .map_err(AudioError::OutputPauseError)
}
fn set_volume(&self, volume: f32) {
@@ -298,3 +301,14 @@ pub fn callback<T: Sample + AddAssign + SaturatingAdd + std::fmt::Display>(
}
}
}
+
+impl Debug for DefaultAudioOutputDevice {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("DefaultAudioInputDevice")
+ .field("client_streams", &self.client_streams)
+ .field("config", &self.config)
+ .field("volume_sender", &self.volume_sender)
+ .field("stream", &"cpal::Stream")
+ .finish()
+ }
+}
diff --git a/mumd/src/audio/transformers.rs b/mumd/src/audio/transformers.rs
index 91cf3ac..21a71b5 100644
--- a/mumd/src/audio/transformers.rs
+++ b/mumd/src/audio/transformers.rs
@@ -6,6 +6,7 @@ pub trait Transformer {
}
/// A struct representing a noise gate transform.
+#[derive(Debug)]
pub struct NoiseGate {
alltime_high: f32,
open: usize,
diff --git a/mumd/src/client.rs b/mumd/src/client.rs
index 9e8ca18..753583f 100644
--- a/mumd/src/client.rs
+++ b/mumd/src/client.rs
@@ -33,7 +33,7 @@ pub async fn handle(
packet_sender.clone(),
packet_receiver,
event_queue.clone(),
- ).fuse() => r.map_err(|e| ClientError::TcpError(e)),
+ ).fuse() => r.map_err(ClientError::TcpError),
_ = udp::handle(
Arc::clone(&state),
connection_info_receiver.clone(),
diff --git a/mumd/src/error.rs b/mumd/src/error.rs
index da1bdd3..4277d7f 100644
--- a/mumd/src/error.rs
+++ b/mumd/src/error.rs
@@ -5,6 +5,7 @@ use tokio::sync::mpsc;
pub type ServerSendError = mpsc::error::SendError<ControlPacket<Serverbound>>;
+#[derive(Debug)]
pub enum TcpError {
NoConnectionInfoReceived,
TlsConnectorBuilderError(native_tls::Error),
@@ -40,6 +41,7 @@ impl From<ServerSendError> for TcpError {
}
}
+#[derive(Debug)]
pub enum UdpError {
NoConnectionInfoReceived,
DisconnectBeforeCryptSetup,
@@ -53,6 +55,7 @@ impl From<std::io::Error> for UdpError {
}
}
+#[derive(Debug)]
pub enum ClientError {
TcpError(TcpError),
}
@@ -65,6 +68,7 @@ impl fmt::Display for ClientError {
}
}
+#[derive(Debug)]
pub enum AudioStream {
Input,
Output,
@@ -79,6 +83,7 @@ impl fmt::Display for AudioStream {
}
}
+#[derive(Debug)]
pub enum AudioError {
NoDevice(AudioStream),
NoConfigs(AudioStream, cpal::SupportedStreamConfigsError),
@@ -105,6 +110,7 @@ impl fmt::Display for AudioError {
}
}
+#[derive(Debug)]
pub enum StateError {
AudioError(AudioError),
ConfigError(ConfigError),
diff --git a/mumd/src/main.rs b/mumd/src/main.rs
index bc72779..479c568 100644
--- a/mumd/src/main.rs
+++ b/mumd/src/main.rs
@@ -1,10 +1,25 @@
-mod audio;
-mod client;
-mod command;
-mod error;
-mod network;
-mod notifications;
-mod state;
+#![warn(elided_lifetimes_in_paths)]
+#![warn(meta_variable_misuse)]
+#![warn(missing_debug_implementations)]
+#![warn(single_use_lifetimes)]
+#![warn(unreachable_pub)]
+#![warn(unused_crate_dependencies)]
+#![warn(unused_import_braces)]
+#![warn(unused_lifetimes)]
+#![warn(unused_qualifications)]
+#![deny(macro_use_extern_crate)]
+#![deny(missing_abi)]
+#![deny(future_incompatible)]
+#![forbid(unsafe_code)]
+#![forbid(non_ascii_idents)]
+
+pub mod audio;
+pub mod client;
+pub mod command;
+pub mod error;
+pub mod network;
+pub mod notifications;
+pub mod state;
use crate::state::State;
@@ -22,10 +37,7 @@ use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
#[tokio::main]
async fn main() {
- if std::env::args()
- .find(|s| s.as_str() == "--version")
- .is_some()
- {
+ if std::env::args().any(|s| s.as_str() == "--version") {
println!("mumd {}", env!("VERSION"));
return;
}
@@ -79,12 +91,9 @@ async fn main() {
_ = receive_commands(command_sender).fuse() => Ok(()),
};
- match run {
- Err(e) => {
- error!("mumd: {}", e);
- std::process::exit(1);
- }
- _ => {}
+ if let Err(e) = run {
+ error!("mumd: {}", e);
+ std::process::exit(1);
}
}
diff --git a/mumd/src/network.rs b/mumd/src/network.rs
index 2b803c0..1066fef 100644
--- a/mumd/src/network.rs
+++ b/mumd/src/network.rs
@@ -30,8 +30,8 @@ impl ConnectionInfo {
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum VoiceStreamType {
- TCP,
- UDP,
+ Tcp,
+ Udp,
}
async fn run_until<F, R>(
diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs
index f620a32..0fdc4c5 100644
--- a/mumd/src/network/tcp.rs
+++ b/mumd/src/network/tcp.rs
@@ -14,6 +14,7 @@ use mumble_protocol::{Clientbound, Serverbound};
use mumlib::command::MumbleEventKind;
use std::collections::HashMap;
use std::convert::{Into, TryInto};
+use std::fmt::Debug;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use tokio::net::TcpStream;
@@ -31,8 +32,8 @@ type TcpSender = SplitSink<
type TcpReceiver =
SplitStream<Framed<TlsStream<TcpStream>, ControlCodec<Serverbound, Clientbound>>>;
-pub(crate) type TcpEventCallback = Box<dyn FnOnce(TcpEventData)>;
-pub(crate) type TcpEventSubscriber = Box<dyn FnMut(TcpEventData) -> bool>; //the bool indicates if it should be kept or not
+pub(crate) type TcpEventCallback = Box<dyn FnOnce(TcpEventData<'_>)>;
+pub(crate) type TcpEventSubscriber = Box<dyn FnMut(TcpEventData<'_>) -> bool>; //the bool indicates if it should be kept or not
/// Why the TCP was disconnected.
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
@@ -57,15 +58,15 @@ pub enum TcpEvent {
/// Having two different types might feel a bit confusing. Essentially, a
/// callback _registers_ to a [TcpEvent] but _takes_ a [TcpEventData] as
/// parameter.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum TcpEventData<'a> {
Connected(Result<&'a msgs::ServerSync, mumlib::Error>),
Disconnected(DisconnectedReason),
TextMessage(&'a msgs::TextMessage),
}
-impl<'a> From<&TcpEventData<'a>> for TcpEvent {
- fn from(t: &TcpEventData) -> Self {
+impl From<&TcpEventData<'_>> for TcpEvent {
+ fn from(t: &TcpEventData<'_>) -> Self {
match t {
TcpEventData::Connected(_) => TcpEvent::Connected,
TcpEventData::Disconnected(reason) => TcpEvent::Disconnected(*reason),
@@ -74,7 +75,7 @@ impl<'a> From<&TcpEventData<'a>> for TcpEvent {
}
}
-#[derive(Clone)]
+#[derive(Clone, Default)]
pub struct TcpEventQueue {
callbacks: Arc<RwLock<HashMap<TcpEvent, Vec<TcpEventCallback>>>>,
subscribers: Arc<RwLock<HashMap<TcpEvent, Vec<TcpEventSubscriber>>>>,
@@ -111,7 +112,7 @@ impl TcpEventQueue {
/// Fires all callbacks related to a specific TCP event and removes them from the event queue.
/// Also calls all event subscribers, but keeps them in the queue
- pub fn resolve<'a>(&self, data: TcpEventData<'a>) {
+ pub fn resolve(&self, data: TcpEventData<'_>) {
if let Some(vec) = self
.callbacks
.write()
@@ -139,6 +140,13 @@ impl TcpEventQueue {
}
}
+impl Debug for TcpEventQueue {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("TcpEventQueue")
+ .finish()
+ }
+}
+
pub async fn handle(
state: Arc<RwLock<State>>,
mut connection_info_receiver: watch::Receiver<Option<ConnectionInfo>>,
@@ -148,13 +156,14 @@ pub async fn handle(
event_queue: TcpEventQueue,
) -> Result<(), TcpError> {
loop {
- let connection_info = 'data: loop {
- while connection_info_receiver.changed().await.is_ok() {
+ let connection_info = loop {
+ if connection_info_receiver.changed().await.is_ok() {
if let Some(data) = connection_info_receiver.borrow().clone() {
- break 'data data;
+ break data;
}
+ } else {
+ return Err(TcpError::NoConnectionInfoReceived);
}
- return Err(TcpError::NoConnectionInfoReceived);
};
let connect_result = connect(
connection_info.socket_addr,
@@ -242,12 +251,12 @@ async fn connect(
builder.danger_accept_invalid_certs(accept_invalid_cert);
let connector: TlsConnector = builder
.build()
- .map_err(|e| TcpError::TlsConnectorBuilderError(e))?
+ .map_err(TcpError::TlsConnectorBuilderError)?
.into();
let tls_stream = connector
.connect(&server_host, stream)
.await
- .map_err(|e| TcpError::TlsConnectError(e))?;
+ .map_err(TcpError::TlsConnectError)?;
debug!("TLS connected");
// Wrap the TLS stream with Mumble's client-side control-channel codec
@@ -304,13 +313,13 @@ async fn send_voice(
inner_phase_watcher.changed().await.unwrap();
if matches!(
*inner_phase_watcher.borrow(),
- StatePhase::Connected(VoiceStreamType::TCP)
+ StatePhase::Connected(VoiceStreamType::Tcp)
) {
break;
}
}
run_until(
- |phase| !matches!(phase, StatePhase::Connected(VoiceStreamType::TCP)),
+ |phase| !matches!(phase, StatePhase::Connected(VoiceStreamType::Tcp)),
async {
loop {
packet_sender.send(
@@ -465,7 +474,7 @@ async fn listen(
..
} => {
state.read().unwrap().audio_output().decode_packet_payload(
- VoiceStreamType::TCP,
+ VoiceStreamType::Tcp,
session_id,
payload,
);
diff --git a/mumd/src/network/udp.rs b/mumd/src/network/udp.rs
index 95dcf33..0f78638 100644
--- a/mumd/src/network/udp.rs
+++ b/mumd/src/network/udp.rs
@@ -37,13 +37,14 @@ pub async fn handle(
let receiver = state.read().unwrap().audio_input().receiver();
loop {
- let connection_info = 'data: loop {
- while connection_info_receiver.changed().await.is_ok() {
+ let connection_info = loop {
+ if connection_info_receiver.changed().await.is_ok() {
if let Some(data) = connection_info_receiver.borrow().clone() {
- break 'data data;
+ break data;
}
+ } else {
+ return Err(UdpError::NoConnectionInfoReceived);
}
- return Err(UdpError::NoConnectionInfoReceived);
};
let (sink, source) = connect(&mut crypt_state_receiver).await?;
@@ -136,7 +137,7 @@ async fn listen(
state
.read()
.unwrap()
- .broadcast_phase(StatePhase::Connected(VoiceStreamType::UDP));
+ .broadcast_phase(StatePhase::Connected(VoiceStreamType::Udp));
last_ping_recv.store(timestamp, Ordering::Relaxed);
}
VoicePacket::Audio {
@@ -147,7 +148,7 @@ async fn listen(
..
} => {
state.read().unwrap().audio_output().decode_packet_payload(
- VoiceStreamType::UDP,
+ VoiceStreamType::Udp,
session_id,
payload,
);
@@ -173,7 +174,7 @@ async fn send_pings(
state
.read()
.unwrap()
- .broadcast_phase(StatePhase::Connected(VoiceStreamType::TCP));
+ .broadcast_phase(StatePhase::Connected(VoiceStreamType::Tcp));
}
match sink
.lock()
@@ -208,13 +209,13 @@ async fn send_voice(
inner_phase_watcher.changed().await.unwrap();
if matches!(
*inner_phase_watcher.borrow(),
- StatePhase::Connected(VoiceStreamType::UDP)
+ StatePhase::Connected(VoiceStreamType::Udp)
) {
break;
}
}
run_until(
- |phase| !matches!(phase, StatePhase::Connected(VoiceStreamType::UDP)),
+ |phase| !matches!(phase, StatePhase::Connected(VoiceStreamType::Udp)),
async {
let mut receiver = receiver.lock().await;
loop {
diff --git a/mumd/src/state.rs b/mumd/src/state.rs
index 8512715..ba461fd 100644
--- a/mumd/src/state.rs
+++ b/mumd/src/state.rs
@@ -18,6 +18,7 @@ use mumble_protocol::voice::Serverbound;
use mumlib::command::{ChannelTarget, Command, CommandResponse, MessageTarget, MumbleEvent, MumbleEventKind};
use mumlib::config::Config;
use mumlib::Error;
+use std::fmt::Debug;
use std::iter;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{Arc, RwLock};
@@ -26,7 +27,7 @@ use tokio::sync::{mpsc, watch};
macro_rules! at {
( $( $event:expr => $generator:expr ),+ $(,)? ) => {
ExecutionContext::TcpEventCallback(vec![
- $( ($event, Box::new($generator)), )*
+ $( ($event, Box::new($generator)), )+
])
};
}
@@ -39,18 +40,18 @@ macro_rules! now {
type Responses = Box<dyn Iterator<Item = mumlib::error::Result<Option<CommandResponse>>>>;
+type TcpEventCallback = Box<dyn FnOnce(TcpEventData<'_>) -> Responses>;
+type TcpEventSubscriberCallback = Box<
+ dyn FnMut(
+ TcpEventData<'_>,
+ &mut mpsc::UnboundedSender<mumlib::error::Result<Option<CommandResponse>>>,
+ ) -> bool
+>;
+
//TODO give me a better name
pub enum ExecutionContext {
- TcpEventCallback(Vec<(TcpEvent, Box<dyn FnOnce(TcpEventData) -> Responses>)>),
- TcpEventSubscriber(
- TcpEvent,
- Box<
- dyn FnMut(
- TcpEventData,
- &mut mpsc::UnboundedSender<mumlib::error::Result<Option<CommandResponse>>>,
- ) -> bool,
- >,
- ),
+ TcpEventCallback(Vec<(TcpEvent, TcpEventCallback)>),
+ TcpEventSubscriber(TcpEvent, TcpEventSubscriberCallback),
Now(Box<dyn FnOnce() -> Responses>),
Ping(
Box<dyn FnOnce() -> mumlib::error::Result<SocketAddr>>,
@@ -60,6 +61,17 @@ pub enum ExecutionContext {
),
}
+impl Debug for ExecutionContext {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple(match self {
+ ExecutionContext::TcpEventCallback(_) => "TcpEventCallback",
+ ExecutionContext::TcpEventSubscriber(_, _) => "TcpEventSubscriber",
+ ExecutionContext::Now(_) => "Now",
+ ExecutionContext::Ping(_, _) => "Ping",
+ }).finish()
+ }
+}
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StatePhase {
Disconnected,
@@ -67,6 +79,7 @@ pub enum StatePhase {
Connected(VoiceStreamType),
}
+#[derive(Debug)]
pub struct State {
config: Config,
server: Option<Server>,
@@ -87,9 +100,9 @@ impl State {
config.audio.input_volume.unwrap_or(1.0),
phase_watcher.1.clone(),
)
- .map_err(|e| StateError::AudioError(e))?;
+ .map_err(StateError::AudioError)?;
let audio_output = AudioOutput::new(config.audio.output_volume.unwrap_or(1.0))
- .map_err(|e| StateError::AudioError(e))?;
+ .map_err(StateError::AudioError)?;
let mut state = Self {
config,
server: None,
@@ -305,7 +318,7 @@ impl State {
}
pub fn initialized(&self) {
- self.broadcast_phase(StatePhase::Connected(VoiceStreamType::TCP));
+ self.broadcast_phase(StatePhase::Connected(VoiceStreamType::Tcp));
self.audio_output
.play_effect(NotificationEvents::ServerConnect);
}
@@ -770,7 +783,7 @@ pub fn handle_command(
.unwrap()
.users()
.iter()
- .find(|(_, user)| user.name() == &name)
+ .find(|(_, user)| user.name() == name)
.map(|(e, _)| *e);
let id = match id {
diff --git a/mumd/src/state/server.rs b/mumd/src/state/server.rs
index 4abde49..5d49457 100644
--- a/mumd/src/state/server.rs
+++ b/mumd/src/state/server.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
-#[derive(Clone, Debug, Deserialize, Serialize)]
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Server {
channels: HashMap<u32, Channel>,
users: HashMap<u32, User>,
diff --git a/mumd/src/state/user.rs b/mumd/src/state/user.rs
index 5770bca..0ffde90 100644
--- a/mumd/src/state/user.rs
+++ b/mumd/src/state/user.rs
@@ -78,7 +78,7 @@ impl User {
}
}
- pub fn apply_user_diff(&mut self, diff: &crate::state::user::UserDiff) {
+ pub fn apply_user_diff(&mut self, diff: &UserDiff) {
if let Some(comment) = diff.comment.clone() {
self.comment = Some(comment);
}