rename argument mod to config; implement name, tracker config options

This commit is contained in:
yggverse 2025-09-08 15:11:52 +03:00
parent bdc5496d45
commit e8b409c4d6
2 changed files with 39 additions and 14 deletions

View file

@ -6,7 +6,15 @@ use std::{
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct Argument { pub struct Config {
/// Server name
#[arg(short, long, default_value_t = String::from("βtracker"))]
pub name: String,
/// Tracker(s) to join / scrape requests
#[arg(short, long)]
pub tracker: Option<Vec<String>>,
/// Bind server `host:port` to listen incoming connections on it /// Bind server `host:port` to listen incoming connections on it
#[arg(short, long, default_value_t = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1965)))] #[arg(short, long, default_value_t = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1965)))]
pub bind: SocketAddr, pub bind: SocketAddr,

View file

@ -1,11 +1,11 @@
mod argument; mod config;
mod format; mod format;
use anyhow::Result; use anyhow::Result;
use argument::Argument;
use btracker_fs::public::{Order, Public, Sort}; use btracker_fs::public::{Order, Public, Sort};
use chrono::Local; use chrono::Local;
use clap::Parser; use clap::Parser;
use config::Config;
use librqbit_core::torrent_metainfo::{TorrentMetaV1Owned, torrent_from_bytes}; use librqbit_core::torrent_metainfo::{TorrentMetaV1Owned, torrent_from_bytes};
use log::*; use log::*;
use native_tls::{HandshakeError, Identity, TlsAcceptor, TlsStream}; use native_tls::{HandshakeError, Identity, TlsAcceptor, TlsStream};
@ -34,33 +34,33 @@ fn main() -> Result<()> {
.init() .init()
} }
let argument = Arc::new(Argument::parse()); let config = Arc::new(Config::parse());
let public = let public = Arc::new(Public::init(&config.storage, config.limit, config.capacity).unwrap());
Arc::new(Public::init(&argument.storage, argument.limit, argument.capacity).unwrap());
// https://geminiprotocol.net/docs/protocol-specification.gmi#the-use-of-tls // https://geminiprotocol.net/docs/protocol-specification.gmi#the-use-of-tls
let acceptor = TlsAcceptor::new(Identity::from_pkcs12( let acceptor = TlsAcceptor::new(Identity::from_pkcs12(
&{ &{
let mut buffer = vec![]; let mut buffer = vec![];
File::open(&argument.identity)?.read_to_end(&mut buffer)?; File::open(&config.identity)?.read_to_end(&mut buffer)?;
buffer buffer
}, },
&argument.password, &config.password,
)?)?; )?)?;
let listener = TcpListener::bind(&argument.bind)?; let listener = TcpListener::bind(&config.bind)?;
info!("Server started on `{}`", argument.bind); info!("Server started on `{}`", config.bind);
for stream in listener.incoming() { for stream in listener.incoming() {
match stream { match stream {
Ok(stream) => { Ok(stream) => {
thread::spawn({ thread::spawn({
let config = config.clone();
let public = public.clone(); let public = public.clone();
let peer = stream.peer_addr()?; let peer = stream.peer_addr()?;
let connection = acceptor.accept(stream); let connection = acceptor.accept(stream);
move || handle(public, peer, connection) move || handle(config, public, peer, connection)
}); });
} }
Err(e) => error!("{e}"), Err(e) => error!("{e}"),
@ -70,6 +70,7 @@ fn main() -> Result<()> {
} }
fn handle( fn handle(
config: Arc<Config>,
public: Arc<Public>, public: Arc<Public>,
peer: SocketAddr, peer: SocketAddr,
connection: Result<TlsStream<TcpStream>, HandshakeError<TcpStream>>, connection: Result<TlsStream<TcpStream>, HandshakeError<TcpStream>>,
@ -108,7 +109,7 @@ fn handle(
if header_buffer.last().is_some_and(|&b| b == b'\n') { if header_buffer.last().is_some_and(|&b| b == b'\n') {
// header bytes contain valid Gemini **request** // header bytes contain valid Gemini **request**
if let Ok(request) = request::Gemini::from_bytes(&header_buffer) { if let Ok(request) = request::Gemini::from_bytes(&header_buffer) {
return response(request, &public, &peer, &mut stream); return response(request, &config, &public, &peer, &mut stream);
} }
// header bytes received but yet could not be parsed, // header bytes received but yet could not be parsed,
@ -146,6 +147,7 @@ fn handle(
fn response( fn response(
request: titanite::request::Gemini, request: titanite::request::Gemini,
config: &Config,
public: &Public, public: &Public,
peer: &SocketAddr, peer: &SocketAddr,
stream: &mut TlsStream<TcpStream>, stream: &mut TlsStream<TcpStream>,
@ -156,6 +158,7 @@ fn response(
if request.url.path().trim_end_matches("/").is_empty() { if request.url.path().trim_end_matches("/").is_empty() {
return send( return send(
&match index( &match index(
config,
public, public,
request.url.query_pairs().find_map(|a| { request.url.query_pairs().find_map(|a| {
if a.0 == "page" { if a.0 == "page" {
@ -207,7 +210,7 @@ fn send(data: &[u8], stream: &mut TlsStream<TcpStream>, callback: impl FnOnce(Re
})()); })());
} }
fn index(public: &Public, page: Option<usize>) -> Result<String> { fn index(config: &Config, public: &Public, page: Option<usize>) -> Result<String> {
let (total, torrents) = public.torrents( let (total, torrents) = public.torrents(
None, // @TODO None, // @TODO
Some((Sort::Modified, Order::Desc)), Some((Sort::Modified, Order::Desc)),
@ -215,7 +218,19 @@ fn index(public: &Public, page: Option<usize>) -> Result<String> {
Some(public.default_limit), Some(public.default_limit),
)?; )?;
let mut b = Vec::with_capacity(torrents.len()); let mut b = Vec::new();
b.push(format!("# {}\n", config.name));
if let Some(ref trackers) = config.tracker {
b.push("```".into());
for tracker in trackers {
b.push(tracker.clone());
}
b.push("```\n".into());
}
b.push("## Recent\n".into());
for torrent in torrents { for torrent in torrents {
let i: TorrentMetaV1Owned = torrent_from_bytes(&torrent.bytes)?; let i: TorrentMetaV1Owned = torrent_from_bytes(&torrent.bytes)?;
@ -236,6 +251,8 @@ fn index(public: &Public, page: Option<usize>) -> Result<String> {
)); ));
} }
b.push("## Navigation\n".into());
b.push(format!( b.push(format!(
"Page {} / {} ({total} {} total)", "Page {} / {} ({total} {} total)",
page.unwrap_or(1), page.unwrap_or(1),