Refactor everything
This commit is contained in:
parent
81ed297b2e
commit
d5a1897699
12 changed files with 144 additions and 181 deletions
BIN
audios/augh.mp3
Normal file
BIN
audios/augh.mp3
Normal file
Binary file not shown.
|
|
@ -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
37
src/client_handler.rs
Normal 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
25
src/dispatcher.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main.rs
49
src/main.rs
|
|
@ -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");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
17
src/sound_player.rs
Normal 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
28
src/sound_scheduler.rs
Normal 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
23
src/ui_app.rs
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue