From 825ae85aea9913ac05436e27f0f507a9f6449bb5 Mon Sep 17 00:00:00 2001 From: steinuil Date: Fri, 21 Jul 2023 15:56:23 +0200 Subject: [PATCH] upload files --- Cargo.lock | 257 ++++++++++++++++++++++++++++++++++------ Cargo.toml | 4 + src/main.rs | 19 ++- src/mpv_ipc.rs | 6 +- src/server_endpoints.rs | 68 ++++++++++- src/server_hyper.rs | 9 +- 6 files changed, 314 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 334832f..a469eb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,7 +114,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -135,6 +135,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf1e6e5492f8f0830c37f301f6349e0dac8b2466e4fe89eef90e9eef906cd046" +dependencies = [ + "crypto-common", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -155,6 +164,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "env_logger" version = "0.9.3" @@ -213,11 +228,26 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -225,31 +255,63 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -450,7 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -462,7 +524,7 @@ dependencies = [ "hermit-abi 0.2.6", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -476,13 +538,17 @@ name = "kameloso" version = "0.1.0" dependencies = [ "clap", + "crypto", "env_logger", + "futures", + "local-ip-address", "log", "qrcode", "serde", "serde_json", "thiserror", "tokio", + "uuid", "warp", ] @@ -498,6 +564,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "local-ip-address" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2815836665de176ba66deaa449ada98fdf208d84730d1a84a22cbeed6151a6fa" +dependencies = [ + "libc", + "neli", + "thiserror", + "windows-sys 0.48.0", +] + [[package]] name = "lock_api" version = "0.4.9" @@ -548,7 +626,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -569,6 +647,31 @@ dependencies = [ "twoway", ] +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.107", +] + [[package]] name = "num_cpus" version = "1.15.0" @@ -611,7 +714,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -637,7 +740,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -667,7 +770,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.107", "version_check", ] @@ -684,9 +787,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -708,9 +811,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.23" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -782,7 +885,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -835,7 +938,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -934,6 +1037,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.4.0" @@ -944,7 +1058,7 @@ dependencies = [ "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -973,7 +1087,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1008,7 +1122,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1019,7 +1133,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -1173,6 +1287,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom", +] + [[package]] name = "version_check" version = "0.9.4" @@ -1263,13 +1386,37 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.0", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm 0.42.0", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -1278,38 +1425,80 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml index 2bdc1b9..e83ebc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,15 @@ edition = "2021" [dependencies] clap = { version = "4.0", features = ["derive"] } +crypto = "0.5.1" env_logger = "0.9.0" +futures = "0.3.28" +local-ip-address = "0.5.3" log = "0.4.17" qrcode = { version = "0.12.0", default_features = false } serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.82" thiserror = "1.0.31" tokio = { version = "1.19.2", features = ["full"] } +uuid = { version = "1.4.1", features = ["v4"] } warp = "0.3.3" diff --git a/src/main.rs b/src/main.rs index 776b49f..4456138 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,8 @@ mod server_endpoints; mod server_hyper; mod server_state; -use std::path::PathBuf; - use clap::Parser; +use std::{net::SocketAddr, path::PathBuf}; #[derive(Debug, Parser)] #[command(version)] @@ -31,7 +30,10 @@ struct CliOptions { async fn main() { let mut opts: CliOptions = CliOptions::parse(); - // tide::log::start(); + let bind_address: SocketAddr = opts.bind_address.parse().unwrap(); + let local_ip = local_ip_address::local_ip().unwrap(); + + let _ = tokio::fs::create_dir("/tmp/kameloso").await; // TODO: add logic for Windows let runtime_dir = std::path::PathBuf::from( @@ -82,8 +84,9 @@ async fn main() { .expect("Could not connect to mpv socket"); { - let qr_code = - qrcode::QrCode::new(format!("http://{}", opts.bind_address).as_bytes()).unwrap(); + let qr_code_address = format!("http://{}:{}", local_ip, bind_address.port()); + + let qr_code = qrcode::QrCode::new(qr_code_address.as_bytes()).unwrap(); let qr_code_path = runtime_dir.join("qr-code.bgra"); @@ -108,12 +111,8 @@ async fn main() { .unwrap(); } - // let server = server::new(mpv_ipc, opts.serve_dir); - - // let server_handle = tokio::spawn(server.listen(opts.bind_address)); - let server_handle = tokio::spawn(server_hyper::start( - opts.bind_address.parse().unwrap(), + bind_address, server_state::ServerState::new(mpv_ipc, opts.serve_dir), )); diff --git a/src/mpv_ipc.rs b/src/mpv_ipc.rs index d266684..9a82119 100644 --- a/src/mpv_ipc.rs +++ b/src/mpv_ipc.rs @@ -59,9 +59,9 @@ impl MpvIpc { Ok(()) } - pub async fn loadfile(&mut self, url: &str) -> Result { - self.command_reply(&["loadfile", url]).await - } + // pub async fn loadfile(&mut self, url: &str) -> Result { + // self.command_reply(&["loadfile", url]).await + // } pub async fn loadfile_append_play(&mut self, url: &str) -> Result<(), IpcError> { self.command_empty(&["loadfile", url, "append-play"]).await diff --git a/src/server_endpoints.rs b/src/server_endpoints.rs index 70dbad0..be704a8 100644 --- a/src/server_endpoints.rs +++ b/src/server_endpoints.rs @@ -1,6 +1,12 @@ +use std::ffi::OsStr; +use std::path::Path; + +use futures::TryStreamExt; use serde::Serialize; +use tokio::io::AsyncWriteExt; use warp::http::StatusCode; -use warp::reply; +use warp::multipart::FormData; +use warp::{reply, Buf}; use crate::mpv_error; use crate::server_state::ServerState; @@ -71,6 +77,66 @@ pub async fn enqueue_url( )) } +pub async fn upload_file( + form: FormData, + state: ServerState, +) -> Result { + let parts: Vec<_> = form + .try_collect() + .await + .map_err(|_| warp::reject::reject())?; + + for p in parts { + if p.name() == "file" { + let extension = match p.filename() { + None => return Err(warp::reject::reject()), + Some(fname) => Path::new(fname) + .extension() + .and_then(OsStr::to_str) + .ok_or_else(warp::reject::reject)?, + }; + + let out_filename = format!("/tmp/kameloso/{}.{}", uuid::Uuid::new_v4(), extension); + + { + let mut out = tokio::fs::File::create(&out_filename) + .await + .map_err(|_| warp::reject::reject())?; + + let mut stream = p.stream(); + loop { + match stream + .try_next() + .await + .map_err(|_| warp::reject::reject())? + { + None => break, + Some(chunk) => { + out.write_all(chunk.chunk()) + .await + .map_err(|_| warp::reject::reject())?; + } + } + } + } + + state + .ipc() + .await + .loadfile_append_play(&out_filename) + .await + .map_err(|_| warp::reject::reject())?; + } else { + return Err(warp::reject::reject()); + } + } + + Ok(warp::reply::with_status( + warp::reply::with_header(warp::reply(), "Location", "/"), + StatusCode::SEE_OTHER, + )) +} + pub async fn get_playlist(state: ServerState) -> Result { let playlist = state .ipc() diff --git a/src/server_hyper.rs b/src/server_hyper.rs index 517682f..fb6fe8a 100644 --- a/src/server_hyper.rs +++ b/src/server_hyper.rs @@ -24,6 +24,13 @@ pub async fn start(addr: SocketAddr, state: ServerState) { .and(with_arg(state.clone())) .and_then(crate::server_endpoints::enqueue_url); + let upload_file = warp::path("upload") + .and(warp::path::end()) + .and(warp::post()) + .and(warp::multipart::form()) + .and(with_arg(state.clone())) + .and_then(crate::server_endpoints::upload_file); + let get_playlist = warp::get() .and(with_arg(state.clone())) .and_then(crate::server_endpoints::get_playlist); @@ -38,7 +45,7 @@ pub async fn start(addr: SocketAddr, state: ServerState) { .or(warp::path("next").and(warp::path::end()).and(playlist_next)), ); - let api_routes = warp::path("api").and(enqueue.or(playlist)); + let api_routes = warp::path("api").and(enqueue.or(upload_file).or(playlist)); let static_files = warp::path("static").and(warp::fs::dir(state.serve_dir.join("static"))); let index_html = warp::path::end().and(warp::fs::file(state.serve_dir.join("index.html")));