#[macro_use] extern crate serde_json; use async_std::task; use async_std::net::{TcpListener, TcpStream}; use futures::prelude::*; use glob::glob; use handlebars::Handlebars; use log::*; use rodio::Source; use serde::Deserialize; use tide::{Body, Request, StatusCode}; use std::fs::File; use std::io::BufReader; #[derive(Debug, Deserialize)] struct Query { admin: String, } async fn index(req: Request<()>) -> Result { let mut hb = Handlebars::new(); if let Err(failure) = hb.register_templates_directory(".hbs", "views") { error!("Failed to render: {:?}", failure); return Err(tide::Error::from_str(StatusCode::InternalServerError, "Could not render templates")) } let mut admin = false; if let Ok(query) = req.query::() { info!("admin: {:?}", query); admin = query.admin == "rtyler"; } let mut sounds = vec![]; for sound in glob("sounds/*.wav").expect("Failed to glob sounds") { if let Ok(sound) = sound { if let Some(name) = sound.as_path().file_stem() { // factory whistle is a special admin only sound ^_^ if name != "factorywhistle" { sounds.push(name.to_os_string().into_string().unwrap()); } } } } info!("sounds: {:?}", sounds); let view = hb.render("index", &json!({"sounds": sounds, "admin" : admin})) .expect("Failed to render"); let mut body = Body::from_string(view); body.set_mime("text/html"); Ok(body) } async fn play(req: Request<()>) -> tide::Result { if let Ok(sound) = req.param::("sound") { let device = rodio::default_output_device().unwrap(); let file = File::open(format!("sounds/{}.wav", sound)).unwrap(); let source = rodio::Decoder::new(BufReader::new(file)).unwrap(); rodio::play_raw(&device, source.convert_samples()); Ok(tide::Redirect::new("/").into()) } else { Err(tide::Error::from_str(StatusCode::NotFound, "Could not find sound")) } } async fn handle_websocket(stream: TcpStream) { let addr = stream .peer_addr() .expect("connected streams should have a peer address"); info!("Peer address: {}", addr); let ws_stream = async_tungstenite::accept_async(stream) .await .expect("Error during the websocket handshake occurred"); info!("New WebSocket connection: {}", addr); let (write, read) = ws_stream.split(); read.forward(write) .await .expect("Failed to forward message") } #[async_std::main] async fn main() -> Result<(), tide::Error> { pretty_env_logger::init(); let mut app = tide::new(); app.at("/play/:sound").post(play); app.at("/").get(index); app.at("/assets").serve_dir("assets/"); task::spawn(async move { let addr = "0.0.0.0:9078"; // Create the event loop and TCP listener we'll accept connections on. let try_socket = TcpListener::bind(&addr).await; let listener = try_socket.expect("Failed to bind"); info!("Listening on: {}", addr); while let Ok((stream, _)) = listener.accept().await { task::spawn(handle_websocket(stream)); } }); Ok(app.listen("0.0.0.0:9077").await?) }