mirror of
https://github.com/YGGverse/btracker-gemini.git
synced 2026-03-31 17:15:30 +00:00
rename argument mod to config; implement name, tracker config options
This commit is contained in:
parent
bdc5496d45
commit
e8b409c4d6
2 changed files with 39 additions and 14 deletions
|
|
@ -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,
|
||||||
43
src/main.rs
43
src/main.rs
|
|
@ -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),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue