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