refactor: state

This commit is contained in:
Gabor Körber 2023-10-27 13:13:22 +02:00
parent cb0272b790
commit fa22be6e0e
6 changed files with 64 additions and 32 deletions

11
Justfile Normal file
View File

@ -0,0 +1,11 @@
default:
@just hello
run:
@cargo run main
bin args='':
@cargo run --bin {{args}}
hello:
@echo "Hello, world!"

View File

@ -1,2 +1,3 @@
pub mod soundclips;
pub mod state;
pub mod vbplay;

View File

@ -1,7 +1,8 @@
use axum::extract::{FromRef, State};
use axum::extract::State;
use axum::{routing, Router};
use axum_template::{engine::Engine, Key, RenderHtml};
use minijinja::{path_loader, Environment};
use state::{AppState, TemplateEngine};
use std::net::SocketAddr;
use serde::Serialize;
@ -10,23 +11,9 @@ use std::sync::{Arc, Mutex};
use vbplay::AudioThread;
mod soundclips;
mod state;
mod vbplay;
type AppEngine = Engine<Environment<'static>>;
#[derive(Clone)]
pub struct AppState {
pub engine: AppEngine,
pub clips: Vec<soundclips::SoundClip>,
pub player: Arc<Mutex<AudioThread>>,
}
impl FromRef<AppState> for AppEngine {
fn from_ref(state: &AppState) -> Self {
state.engine.clone()
}
}
#[tokio::main]
async fn main() {
let mut jinja = Environment::new();
@ -36,7 +23,7 @@ async fn main() {
let audio = vbplay::audio_thread();
let audio: Arc<Mutex<AudioThread>> = Arc::new(Mutex::new(audio));
let state = AppState {
let app_state = AppState {
engine: template_engine,
clips: soundclips::scan_directory_for_clips("E:/sounds/soundboard", &["mp3"])
.expect("No Soundclips found."),
@ -51,7 +38,7 @@ async fn main() {
.route("/", routing::get(home))
.route("/play/:hash", routing::get(play_handler))
.route("/stop", routing::get(stop_handler))
.with_state(state);
.with_state(app_state);
println!("listening on {}", addr);
@ -67,7 +54,7 @@ struct TemplateContext {
clips: Vec<soundclips::SoundClip>,
}
async fn home(engine: AppEngine, state: State<AppState>) -> impl axum::response::IntoResponse {
async fn home(engine: TemplateEngine, state: State<AppState>) -> impl axum::response::IntoResponse {
let clips = state.0.clone().clips; // this is not ideal.
let context = TemplateContext { clips: clips };
RenderHtml(Key("index.html".to_owned()), engine, context)

View File

@ -58,15 +58,17 @@ pub fn scan_directory_for_clips(directory: &str, extensions: &[&str]) -> Option<
if path.is_file() {
if let Some(ext) = path.extension() {
if extensions.iter().any(|&e| ext == OsStr::new(e)) {
let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
/*
the calls to unwrap() are more or less "safe" because:
if let Some(file_name) = path.file_name().unwrap().to_str() {
/*
the calls to unwrap() are more or less "safe" because:
file_name() only returns None if the path ends in "..", which won't be the case for paths returned by read_dir.
to_str() only returns None if the file name isn't valid Unicode, which is quite rare on most modern file systems.
*/
let sound_clip = SoundClip::new(file_name, directory.to_owned());
sound_clips.push(sound_clip);
file_name() only returns None if the path ends in "..", which won't be the case for paths returned by read_dir.
to_str() only returns None if the file name isn't valid Unicode, which is quite rare on most modern file systems.
*/
let sound_clip =
SoundClip::new(file_name.to_string(), directory.to_owned());
sound_clips.push(sound_clip);
}
}
}
}

21
src/state.rs Normal file
View File

@ -0,0 +1,21 @@
use crate::soundclips::SoundClip;
use crate::vbplay::AudioThread;
use axum::extract::FromRef;
use axum_template::engine::Engine;
use minijinja::Environment;
use std::sync::{Arc, Mutex};
pub type TemplateEngine = Engine<Environment<'static>>;
#[derive(Clone)]
pub struct AppState {
pub engine: TemplateEngine,
pub clips: Vec<SoundClip>,
pub player: Arc<Mutex<AudioThread>>,
}
impl FromRef<AppState> for TemplateEngine {
fn from_ref(state: &AppState) -> Self {
state.engine.clone()
}
}

View File

@ -13,10 +13,20 @@
</script>
</head>
<body>
{% for clip in clips %}
<button onclick="play('{{clip.hash}}')">{{clip.file_name}}</button><br />
{% endfor %}
<button onclick="stop()">Stop.</button>
<div class="container">
<div class="categories">
<span class="category">Category 1</span>
<!-- More categories -->
<button class="more">More</button>
</div>
<div class="soundclips">
{% for clip in clips %}
<button onclick="play('{{clip.hash}}')">{{clip.file_name}}</button>
{% endfor %}
</div>
<div class="player">
<button onclick="stop()">Stop.</button>
</div>
</div>
</body>
</html>