From 4dd4ef6f554deba25e661f045e6d9bdf89f105b3 Mon Sep 17 00:00:00 2001 From: yggverse Date: Tue, 9 Sep 2025 00:12:34 +0300 Subject: [PATCH] implement public storage preview --- Cargo.toml | 1 + src/main.rs | 43 +++++++++++++++++++++++++++++++++++++++---- src/route.rs | 16 +++++++++++----- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ebf5689..f470a30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,4 @@ regex = "1.11.2" # development [patch.crates-io] btracker-fs = { git = "https://github.com/YGGverse/btracker-fs.git" } +# btracker-fs = { path = "../btracker-fs" } diff --git a/src/main.rs b/src/main.rs index 8a08de2..87a4fce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,7 +157,33 @@ fn response( use titanite::response::*; debug!("Incoming request from `{peer}` to `{}`", request.url.path()); send( - &match Route::from_url(&request.url) { + &match Route::from_url(&request.url, public) { + Route::File(ref path) => success::Default { + data: &std::fs::read(path).unwrap(), + meta: success::default::Meta { + mime: match path.extension() { + Some(extension) => { + let e = extension.to_ascii_lowercase(); + if e == "jpeg" || e == "jpg" { + "image/jpeg" + } else if e == "gif" { + "image/gif" + } else if e == "png" { + "image/png" + } else if e == "webp" { + "image/webp" + } else if e == "txt" || e == "log" { + "text/plain" + } else { + todo!() + } + } + None => todo!(), + } + .to_string(), + }, + } + .into_bytes(), Route::List { page, keyword } => match list(config, public, keyword.as_deref(), page) { Ok(data) => success::Default { data: data.as_bytes(), @@ -179,7 +205,7 @@ fn response( }) .into_bytes(), Route::Info(id) => match public.torrent(id) { - Some(torrent) => match info(config, torrent) { + Some(torrent) => match info(config, public, torrent) { Ok(data) => success::Default { data: data.as_bytes(), meta: success::default::Meta { @@ -337,7 +363,7 @@ fn list( Ok(b.join("\n")) } -fn info(config: &Config, torrent: Torrent) -> Result { +fn info(config: &Config, public: &Public, torrent: Torrent) -> Result { struct File { path: Option, length: u64, @@ -396,7 +422,16 @@ fn info(config: &Config, torrent: Torrent) -> Result { }) { b.push("## Files\n".into()); for file in files { - b.push(format!("* {} ({})", file.path(), format::size(file.length))); + let p = file.path(); + b.push(match public.href(&i.info_hash.as_string(), &p) { + Some(href) => format!( + "=> {} {} ({})", + urlencoding::encode(&href), + p, + format::size(file.length) + ), + None => format!("{} ({})", p, format::size(file.length)), // * ? + }) } } diff --git a/src/route.rs b/src/route.rs index 8cad82f..24addbe 100644 --- a/src/route.rs +++ b/src/route.rs @@ -1,10 +1,11 @@ -use std::str::FromStr; - +use btracker_fs::public::Public; use librqbit_core::Id20; use regex::Regex; +use std::{path::PathBuf, str::FromStr}; use url::Url; pub enum Route { + File(PathBuf), Info(Id20), List { keyword: Option, @@ -15,8 +16,9 @@ pub enum Route { } impl Route { - pub fn from_url(url: &Url) -> Self { - let p = url.path().to_lowercase(); + pub fn from_url(url: &Url, public: &Public) -> Self { + let p = urlencoding::decode(url.path()).ok().unwrap_or_default(); + let t = p.trim_matches('/'); let q = url.query(); if p.is_empty() { @@ -26,7 +28,11 @@ impl Route { }; } - if let Ok(id) = Id20::from_str(p.trim_matches('/')) { + if let Some(path) = public.filepath(t) { + return Self::File(path); + } + + if let Ok(id) = Id20::from_str(t) { return Self::Info(id); }