Compare changes

Choose any two refs to compare.

+2
.gitignore
···
/target
+
result
+
sounds
+7
Cargo.toml
···
[dependencies]
quad-snd = "0.2.8"
+
+
[profile.release]
+
strip = true
+
opt-level = "z"
+
lto = true
+
codegen-units = 1
+
panic = "abort"
+20
default.nix
···
+
{
+
lib,
+
rustPlatform,
+
alsa-lib,
+
...
+
}:
+
rustPlatform.buildRustPackage {
+
pname = "clickee";
+
version = "main";
+
+
buildInputs = [alsa-lib];
+
+
cargoLock.lockFile = ./Cargo.lock;
+
src = lib.fileset.toSource {
+
root = ./.;
+
fileset = lib.fileset.unions [./src ./Cargo.toml ./Cargo.lock];
+
};
+
+
doCheck = false;
+
}
+27
flake.lock
···
+
{
+
"nodes": {
+
"nixpkgs": {
+
"locked": {
+
"lastModified": 1756542300,
+
"narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=",
+
"owner": "nixos",
+
"repo": "nixpkgs",
+
"rev": "d7600c775f877cd87b4f5a831c28aa94137377aa",
+
"type": "github"
+
},
+
"original": {
+
"owner": "nixos",
+
"ref": "nixos-unstable",
+
"repo": "nixpkgs",
+
"type": "github"
+
}
+
},
+
"root": {
+
"inputs": {
+
"nixpkgs": "nixpkgs"
+
}
+
}
+
},
+
"root": "root",
+
"version": 7
+
}
+18
flake.nix
···
+
{
+
description = "A very basic flake";
+
+
inputs = {
+
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
+
};
+
+
outputs = inp: let
+
l = inp.nixpkgs.lib;
+
systems = ["x86_64-linux"];
+
pkgs' = l.genAttrs systems (s: inp.nixpkgs.legacyPackages.${s});
+
mkPackages = pkgs: {
+
default = pkgs.callPackage ./default.nix {};
+
};
+
in {
+
packages = l.mapAttrs (_: mkPackages) pkgs';
+
};
+
}
sounds/sound.ogg

This is a binary file and will not be displayed.

+62 -15
src/main.rs
···
+
#![windows_subsystem = "windows"]
+
use std::{
+
collections::HashMap,
io::{BufRead, BufReader, Write},
-
net::TcpListener,
+
net::{TcpListener, TcpStream},
};
use quad_snd::*;
-
const CLICK: &[u8] = include_bytes!("./sound.ogg");
-
fn main() {
let ctx = AudioContext::new();
-
let click = Sound::load(&ctx, CLICK);
+
let sounds = std::fs::read_dir("sounds")
+
.expect("cant read sounds")
+
.flat_map(|f| {
+
let p = f.ok()?.path();
+
let n = p.file_stem()?.to_string_lossy().into_owned();
+
Some((
+
n,
+
Sound::load(&ctx, &std::fs::read(p).expect("can't load sound")),
+
))
+
})
+
.collect::<HashMap<String, Sound>>();
+
+
let handle_request = |mut stream: TcpStream| {
+
let mut lines = BufReader::new(&stream)
+
.lines()
+
.flatten()
+
.take_while(|line| !line.is_empty());
+
+
let request_line = lines.next()?;
+
let query = parse_query_from_request(request_line.as_str());
+
let kind = query.get("kind").cloned().unwrap_or("sound");
+
+
if let Some(sound) = sounds.get(kind) {
+
sound.play(&ctx, PlaySoundParams::default());
+
}
+
+
// exhaust connection to not get "connection reset by peer"
+
lines.for_each(drop);
+
// this never "fails"
+
let response = "HTTP/1.1 200 OK\r\n\r\n";
+
let _ = stream.write_all(response.as_bytes());
+
+
Some(())
+
};
let port = std::env::var("PORT")
.ok()
···
let listener = TcpListener::bind(("0.0.0.0", port)).expect("cant bind");
for stream in listener.incoming() {
-
let Ok(mut stream) = stream else {
+
let Ok(stream) = stream else {
continue;
};
-
click.play(&ctx, PlaySoundParams::default());
-
// exhaust connection to not get "connection reset by peer"
-
BufReader::new(&stream)
-
.lines()
-
.flatten()
-
.take_while(|line| !line.is_empty())
-
.for_each(drop);
-
// this never "fails"
-
let response = "HTTP/1.1 200 OK\r\n\r\n";
-
let _ = stream.write_all(response.as_bytes());
+
handle_request(stream);
}
}
+
+
fn parse_query_from_request(request_line: &str) -> HashMap<&str, &str> {
+
request_line
+
.split_whitespace()
+
.nth(1)
+
.and_then(|path| path.split_once('?'))
+
.map(|(_, query)| {
+
query
+
.split('&')
+
.filter_map(|param| {
+
if let Some((key, value)) = param.split_once('=') {
+
Some((key, value))
+
} else if !param.is_empty() {
+
Some((param, ""))
+
} else {
+
None
+
}
+
})
+
.collect()
+
})
+
.unwrap_or_default()
+
}
src/sound.ogg

This is a binary file and will not be displayed.