click
1use std::{
2 collections::HashMap,
3 io::{BufRead, BufReader, Write},
4 net::{TcpListener, TcpStream},
5};
6
7use quad_snd::*;
8
9fn main() {
10 let ctx = AudioContext::new();
11 let sounds = std::fs::read_dir("sounds")
12 .expect("cant read sounds")
13 .flat_map(|f| {
14 let p = f.ok()?.path();
15 let n = p.file_stem()?.to_string_lossy().into_owned();
16 Some((
17 n,
18 Sound::load(&ctx, &std::fs::read(p).expect("can't load sound")),
19 ))
20 })
21 .collect::<HashMap<String, Sound>>();
22
23 let handle_request = |mut stream: TcpStream| {
24 let mut lines = BufReader::new(&stream)
25 .lines()
26 .flatten()
27 .take_while(|line| !line.is_empty());
28
29 let request_line = lines.next()?;
30 let query = parse_query_from_request(request_line.as_str());
31 let kind = query.get("kind").cloned().unwrap_or("sound");
32
33 if let Some(sound) = sounds.get(kind) {
34 sound.play(&ctx, PlaySoundParams::default());
35 }
36
37 // exhaust connection to not get "connection reset by peer"
38 lines.for_each(drop);
39 // this never "fails"
40 let response = "HTTP/1.1 200 OK\r\n\r\n";
41 let _ = stream.write_all(response.as_bytes());
42
43 Some(())
44 };
45
46 let port = std::env::var("PORT")
47 .ok()
48 .and_then(|p| p.parse::<u16>().ok())
49 .unwrap_or(8668);
50 let listener = TcpListener::bind(("0.0.0.0", port)).expect("cant bind");
51
52 for stream in listener.incoming() {
53 let Ok(stream) = stream else {
54 continue;
55 };
56 handle_request(stream);
57 }
58}
59
60fn parse_query_from_request(request_line: &str) -> HashMap<&str, &str> {
61 request_line
62 .split_whitespace()
63 .nth(1)
64 .and_then(|path| path.split_once('?'))
65 .map(|(_, query)| {
66 query
67 .split('&')
68 .filter_map(|param| {
69 if let Some((key, value)) = param.split_once('=') {
70 Some((key, value))
71 } else if !param.is_empty() {
72 Some((param, ""))
73 } else {
74 None
75 }
76 })
77 .collect()
78 })
79 .unwrap_or_default()
80}