Refactor everything

This commit is contained in:
Silvio Braendle 2025-01-06 14:37:22 +01:00
parent 81ed297b2e
commit d5a1897699
No known key found for this signature in database
GPG key ID: 553A5A37BA69D8AE
12 changed files with 144 additions and 181 deletions

BIN
audios/augh.mp3 Normal file

Binary file not shown.

View file

@ -1,31 +0,0 @@
use std::sync::Arc;
use crate::{
network_dispatcher::NetworkDispatcher, network_handler::NetworkHandler,
sound_engine::SoundEngine,
};
pub struct AppService {
network_handler: NetworkHandler,
network_dispatcher: NetworkDispatcher,
}
impl AppService {
pub fn new() -> Self {
let sound_engine = Arc::new(SoundEngine::new());
Self {
network_handler: NetworkHandler::new(sound_engine.clone()),
network_dispatcher: NetworkDispatcher::new(),
}
}
pub fn dispatch_sample(&self) {
self.network_dispatcher
.dispatch_sound("localhost:3000".to_owned(), 1, "sound".to_owned())
.unwrap();
}
pub fn listen(&self) {
self.network_handler.listen();
}
}

Binary file not shown.

37
src/client_handler.rs Normal file
View file

@ -0,0 +1,37 @@
use crate::protocol::Message;
use crate::sound_scheduler::SoundScheduler;
use std::io::Read;
use std::net::{TcpListener, TcpStream};
pub struct ClientHandler;
impl ClientHandler {
fn handle_client(mut stream: TcpStream) {
println!("Handling client: {:?}", stream);
let mut buf: Vec<u8> = Vec::new();
stream
.read_to_end(buf.as_mut())
.expect("Could not read from stream");
let message = bincode::deserialize::<Message>(&buf).expect("Could not deserialize message");
match message {
Message::PlaySound(play_sound) => {
SoundScheduler::handle_scheduled_sound(play_sound);
}
}
}
pub fn listen() {
let listener = TcpListener::bind("127.0.0.1:3000").expect("Could not bind to address");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
ClientHandler::handle_client(stream);
}
Err(e) => {
eprintln!("Error: {}", e);
}
}
}
}
}

25
src/dispatcher.rs Normal file
View file

@ -0,0 +1,25 @@
use std::io::Write;
use std::net::TcpStream;
use std::time::SystemTime;
use crate::protocol::{Message, PlaySound};
pub struct Dispatcher;
impl Dispatcher {
pub fn handle_dispatch_sample() {
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_micros();
let timestamp = now + 10000000;
let addr = "localhost:3000".to_owned();
let msg = Message::PlaySound(PlaySound {
timestamp: timestamp,
sound_source: "augh.mp3".to_owned(),
});
let mut sock = TcpStream::connect(addr).expect("Failed to connect");
let buf = bincode::serialize(&msg).expect("Failed to serialize");
sock.write_all(&buf).unwrap();
}
}

View file

@ -1,21 +1,28 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use client_handler::ClientHandler;
use std::thread;
use ui_app::UIApp;
use eframe::egui; use eframe::egui;
use std::{sync::Arc, thread};
mod app_service; mod client_handler;
mod network_dispatcher; mod dispatcher;
mod network_handler;
mod protocol; mod protocol;
mod sound_engine; mod sound_player;
mod sound_scheduler;
use crate::app_service::AppService; mod ui_app;
fn main() -> eframe::Result { fn main() -> eframe::Result {
let options = eframe::NativeOptions { let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]), viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
..Default::default() ..Default::default()
}; };
thread::spawn(move || {
ClientHandler::listen();
});
eframe::run_native( eframe::run_native(
"My egui App", "My egui App",
options, options,
@ -27,31 +34,3 @@ fn main() -> eframe::Result {
}), }),
) )
} }
struct UIApp {
app_service: Arc<AppService>,
}
impl Default for UIApp {
fn default() -> Self {
let app_service = Arc::new(AppService::new());
let app_service_listener = Arc::clone(&app_service);
thread::spawn(move || {
app_service_listener.listen();
});
Self {
app_service: app_service,
}
}
}
impl eframe::App for UIApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui Application");
ui.label("Hello");
});
}
}

View file

@ -1,21 +0,0 @@
use std::{io::Write, net::TcpStream};
use crate::protocol::{Message, PlaySound};
pub struct NetworkDispatcher {}
impl NetworkDispatcher {
pub fn new() -> Self {
Self {}
}
pub fn dispatch_sound(&self, addr: String, timestamp: u128, sound_source: String) -> std::io::Result<()> {
let msg = Message::PlaySound(PlaySound {
timestamp: timestamp,
sound_source: sound_source,
});
let mut sock = TcpStream::connect(addr).expect("Failed to connect");
let buf = bincode::serialize(&msg).expect("Failed to serialize");
sock.write_all(&buf)
}
}

View file

@ -1,71 +0,0 @@
use std::{
io::Read,
net::{TcpListener, TcpStream},
sync::Arc,
thread::sleep,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use crate::{
protocol::{Message, PlaySound},
sound_engine::SoundEngine,
};
pub struct NetworkHandler {
sound_engine: Arc<SoundEngine>,
}
impl NetworkHandler {
pub fn new(sound_engine: Arc<SoundEngine>) -> Self {
Self { sound_engine }
}
fn handle_scheduled_sound(&self, play_msg: PlaySound) {
let PlaySound {
sound_source,
timestamp,
} = play_msg;
println!("Scheduled sound: {:?} at {:?}", sound_source, timestamp);
let now_micros = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Could not get time")
.as_micros();
let wait = timestamp as i128 - now_micros as i128;
if wait <= 0 {
println!("Too late to play sound");
return;
}
sleep(Duration::from_micros(wait as u64));
println!("Playing sound: {:?}", sound_source);
self.sound_engine.play_sound(sound_source);
}
fn handle_client(&self, mut stream: TcpStream) {
println!("Handling client: {:?}", stream);
let mut buf: Vec<u8> = Vec::new();
stream
.read_to_end(buf.as_mut())
.expect("Could not read from stream");
let message = bincode::deserialize::<Message>(&buf).expect("Could not deserialize message");
match message {
Message::PlaySound(play_sound) => {
self.handle_scheduled_sound(play_sound);
}
}
}
pub fn listen(&self) {
let listener = TcpListener::bind("127.0.0.1:3000").expect("Could not bind to address");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
self.handle_client(stream);
}
Err(e) => {
eprintln!("Error: {}", e);
}
}
}
}
}

View file

@ -1,23 +0,0 @@
use std::{fs::File, io::BufReader};
use rodio::{Decoder, OutputStream, OutputStreamHandle, Source};
pub struct SoundEngine {
stream_handle: OutputStreamHandle,
}
impl SoundEngine {
pub fn new() -> Self {
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
Self { stream_handle }
}
pub fn play_sound(&self, sound_source: String) {
let path = format!("./audios/{}", sound_source);
let file = BufReader::new(File::open(path).unwrap());
let source = Decoder::new(file).unwrap();
self.stream_handle
.play_raw(source.convert_samples())
.unwrap();
}
}

17
src/sound_player.rs Normal file
View file

@ -0,0 +1,17 @@
use rodio::{Decoder, OutputStream, Sink};
use std::{fs::File, io::BufReader};
pub struct SoundPlayer;
impl SoundPlayer {
pub fn play_sound(sound_source: String) {
let path = format!("./audios/{}", sound_source);
let file = BufReader::new(File::open(path).unwrap());
let source = Decoder::new(file).unwrap();
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap();
sink.append(source);
sink.sleep_until_end();
}
}

28
src/sound_scheduler.rs Normal file
View file

@ -0,0 +1,28 @@
use crate::protocol::PlaySound;
use crate::sound_player::SoundPlayer;
use std::thread::sleep;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub struct SoundScheduler;
impl SoundScheduler {
pub fn handle_scheduled_sound(play_msg: PlaySound) {
let PlaySound {
sound_source,
timestamp,
} = play_msg;
println!("Scheduled sound: {:?} at {:?}", sound_source, timestamp);
let now_micros = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Could not get time")
.as_micros();
let wait = timestamp as i128 - now_micros as i128;
if wait <= 0 {
println!("Too late to play sound");
return;
}
sleep(Duration::from_micros(wait as u64));
println!("Playing sound: {:?}", sound_source);
SoundPlayer::play_sound(sound_source);
}
}

23
src/ui_app.rs Normal file
View file

@ -0,0 +1,23 @@
use eframe::egui;
use crate::dispatcher::Dispatcher;
pub struct UIApp {}
impl Default for UIApp {
fn default() -> Self {
Self {}
}
}
impl eframe::App for UIApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui Application");
ui.label("Hello");
if ui.button("Dispatch sample").clicked() {
Dispatcher::handle_dispatch_sample();
}
});
}
}