From d0f172b8ed3c11266e75a21c3d3e217fbffe9f14 Mon Sep 17 00:00:00 2001 From: FrenchGithubUser Date: Wed, 15 Oct 2025 20:27:14 +0200 Subject: [PATCH] tracker gets torrents from backend --- .../api/src/handlers/tracker/get_torrents.rs | 9 +++ backend/api/src/handlers/tracker/mod.rs | 2 + .../api/src/middlewares/auth_middleware.rs | 1 - ...2856d869d0bb2644a0fd0f8393c40fb03820d.json | 56 ++++++++++++++++++ .../src/repositories/tracker_repository.rs | 43 +++++++++++++- shared/src/tracker/models/mod.rs | 1 + shared/src/tracker/models/torrent.rs | 13 ++++ .../src/announce/models/torrent.rs | 4 -- .../arcadia_tracker/src/common/models/mod.rs | 1 + .../src/common/models/torrent.rs | 59 +++++++++++++++++++ tracker/arcadia_tracker/src/lib.rs | 7 +++ 11 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 backend/api/src/handlers/tracker/get_torrents.rs create mode 100644 backend/storage/.sqlx/query-f37f46d41fb39785542302f51442856d869d0bb2644a0fd0f8393c40fb03820d.json create mode 100644 shared/src/tracker/models/torrent.rs create mode 100644 tracker/arcadia_tracker/src/common/models/torrent.rs diff --git a/backend/api/src/handlers/tracker/get_torrents.rs b/backend/api/src/handlers/tracker/get_torrents.rs new file mode 100644 index 00000000..3c9a8e96 --- /dev/null +++ b/backend/api/src/handlers/tracker/get_torrents.rs @@ -0,0 +1,9 @@ +use crate::{handlers::tracker::binary_response, Arcadia}; +use actix_web::{web::Data, HttpResponse}; +use arcadia_common::error::Result; +use arcadia_storage::redis::RedisPoolInterface; + +pub async fn exec(arc: Data>) -> Result { + let torrents = arc.pool.find_torrents().await?; + binary_response(&torrents) +} diff --git a/backend/api/src/handlers/tracker/mod.rs b/backend/api/src/handlers/tracker/mod.rs index ee00999b..3d2473d3 100644 --- a/backend/api/src/handlers/tracker/mod.rs +++ b/backend/api/src/handlers/tracker/mod.rs @@ -1,3 +1,4 @@ +pub mod get_torrents; pub mod get_users; use actix_web::{ @@ -10,6 +11,7 @@ use bincode::config; pub fn config(cfg: &mut ServiceConfig) { cfg.service(resource("/users").route(get().to(self::get_users::exec::))); + cfg.service(resource("/torrents").route(get().to(self::get_torrents::exec::))); } fn binary_response(value: &T) -> Result { diff --git a/backend/api/src/middlewares/auth_middleware.rs b/backend/api/src/middlewares/auth_middleware.rs index c263e5ec..b678592a 100644 --- a/backend/api/src/middlewares/auth_middleware.rs +++ b/backend/api/src/middlewares/auth_middleware.rs @@ -130,7 +130,6 @@ fn validate_tracker_api_key( req: ServiceRequest, api_key: &str, ) -> std::result::Result { - println!("tracker req"); let arc = req.app_data::>>().expect("app data set"); if arc.env.tracker.api_key != api_key { diff --git a/backend/storage/.sqlx/query-f37f46d41fb39785542302f51442856d869d0bb2644a0fd0f8393c40fb03820d.json b/backend/storage/.sqlx/query-f37f46d41fb39785542302f51442856d869d0bb2644a0fd0f8393c40fb03820d.json new file mode 100644 index 00000000..6200bc54 --- /dev/null +++ b/backend/storage/.sqlx/query-f37f46d41fb39785542302f51442856d869d0bb2644a0fd0f8393c40fb03820d.json @@ -0,0 +1,56 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id,\n info_hash,\n upload_factor,\n download_factor,\n seeders,\n leechers,\n completed\n FROM torrents\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "info_hash", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "upload_factor", + "type_info": "Float8" + }, + { + "ordinal": 3, + "name": "download_factor", + "type_info": "Float8" + }, + { + "ordinal": 4, + "name": "seeders", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "leechers", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "completed", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ] + }, + "hash": "f37f46d41fb39785542302f51442856d869d0bb2644a0fd0f8393c40fb03820d" +} diff --git a/backend/storage/src/repositories/tracker_repository.rs b/backend/storage/src/repositories/tracker_repository.rs index a83a40ce..9ce6a7e1 100644 --- a/backend/storage/src/repositories/tracker_repository.rs +++ b/backend/storage/src/repositories/tracker_repository.rs @@ -1,6 +1,9 @@ use crate::connection_pool::ConnectionPool; use arcadia_common::error::Result; -use arcadia_shared::tracker::models::user::{Passkey, User}; +use arcadia_shared::tracker::models::{ + torrent::{InfoHash, Torrent}, + user::{Passkey, User}, +}; use std::borrow::Borrow; // This file contains functions for Arcadia's tracker @@ -11,6 +14,7 @@ impl ConnectionPool { // TODO: fix this // query_as!() doesn't work as it requires the FromString trait // which is implemented, but somehow still throws an error + // let rows = sqlx::query!( r#" SELECT @@ -42,4 +46,41 @@ impl ConnectionPool { Ok(users) } + + pub async fn find_torrents(&self) -> Result> { + // TODO: fix this + // query_as!() doesn't work as it requires the FromString trait + // which is implemented, but somehow still throws an error + let rows = sqlx::query!( + r#" + SELECT + id, + info_hash, + upload_factor, + download_factor, + seeders, + leechers, + completed + FROM torrents + "# + ) + .fetch_all(self.borrow()) + .await + .expect("could not get torrents"); + + let torrents = rows + .into_iter() + .map(|r| Torrent { + id: r.id as u32, + info_hash: InfoHash(r.info_hash.try_into().expect("invalid info hash length")), + upload_factor: r.upload_factor, + download_factor: r.download_factor, + seeders: r.seeders, + leechers: r.leechers, + completed: r.completed, + }) + .collect(); + + Ok(torrents) + } } diff --git a/shared/src/tracker/models/mod.rs b/shared/src/tracker/models/mod.rs index 22d12a38..bafd02bf 100644 --- a/shared/src/tracker/models/mod.rs +++ b/shared/src/tracker/models/mod.rs @@ -1 +1,2 @@ +pub mod torrent; pub mod user; diff --git a/shared/src/tracker/models/torrent.rs b/shared/src/tracker/models/torrent.rs new file mode 100644 index 00000000..c5631288 --- /dev/null +++ b/shared/src/tracker/models/torrent.rs @@ -0,0 +1,13 @@ +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, bincode::Encode, bincode::Decode)] +pub struct InfoHash(pub [u8; 20]); + +#[derive(Debug, Clone, bincode::Encode, bincode::Decode, PartialEq)] +pub struct Torrent { + pub id: u32, + pub info_hash: InfoHash, + pub upload_factor: f64, + pub download_factor: f64, + pub seeders: i64, + pub leechers: i64, + pub completed: i64, +} diff --git a/tracker/arcadia_tracker/src/announce/models/torrent.rs b/tracker/arcadia_tracker/src/announce/models/torrent.rs index bdb7aace..2d0477f6 100644 --- a/tracker/arcadia_tracker/src/announce/models/torrent.rs +++ b/tracker/arcadia_tracker/src/announce/models/torrent.rs @@ -1,9 +1,5 @@ -use serde::Deserialize; use strum::{Display, EnumString}; -#[derive(Clone, Copy, Deserialize, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub struct InfoHash(pub [u8; 20]); - #[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct PeerId(pub [u8; 20]); diff --git a/tracker/arcadia_tracker/src/common/models/mod.rs b/tracker/arcadia_tracker/src/common/models/mod.rs index 22d12a38..bafd02bf 100644 --- a/tracker/arcadia_tracker/src/common/models/mod.rs +++ b/tracker/arcadia_tracker/src/common/models/mod.rs @@ -1 +1,2 @@ +pub mod torrent; pub mod user; diff --git a/tracker/arcadia_tracker/src/common/models/torrent.rs b/tracker/arcadia_tracker/src/common/models/torrent.rs new file mode 100644 index 00000000..eab361a9 --- /dev/null +++ b/tracker/arcadia_tracker/src/common/models/torrent.rs @@ -0,0 +1,59 @@ +use std::ops::{Deref, DerefMut}; + +use arcadia_shared::tracker::models::torrent::{InfoHash, Torrent}; +use bincode::config; +use indexmap::IndexMap; +use reqwest::Client; + +#[derive(Debug)] +pub struct Map(IndexMap); + +impl Map { + pub async fn from_backend() -> Self { + let base_url = + std::env::var("ARCADIA_API_BASE_URL").expect("env var ARCADIA_API_BASE_URL not set"); + let url = format!("{}/api/tracker/torrents", base_url); + + let client = Client::new(); + let api_key = std::env::var("API_KEY").expect("env var API_KEY not set"); + let resp = client + .get(url) + .header("api_key", api_key) + .send() + .await + .expect("failed to fetch torrents"); + let bytes = resp + .bytes() + .await + .expect("failed to read torrents response body"); + + let config = config::standard(); + let (torrents, _): (Vec, usize) = + bincode::decode_from_slice(&bytes[..], config).unwrap(); + let mut map = IndexMap::new(); + for torrent in torrents { + map.insert(torrent.info_hash, torrent); + } + Self(map) + } +} + +impl Deref for Map { + type Target = IndexMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Map { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Default for Map { + fn default() -> Self { + Self(IndexMap::new()) + } +} diff --git a/tracker/arcadia_tracker/src/lib.rs b/tracker/arcadia_tracker/src/lib.rs index bb10a106..2586b23d 100644 --- a/tracker/arcadia_tracker/src/lib.rs +++ b/tracker/arcadia_tracker/src/lib.rs @@ -14,6 +14,7 @@ pub struct Tracker { env: Env, pub users: RwLock, + pub torrents: RwLock, } impl Deref for Tracker { @@ -31,9 +32,15 @@ impl Tracker { let users = common::models::user::Map::from_backend().await; log::info!("[Setup] Got {:?} users", users.len()); + log::info!("[Setup] Getting torrents..."); + std::io::stdout().flush().unwrap(); + let torrents = common::models::torrent::Map::from_backend().await; + log::info!("[Setup] Got {:?} torrents", torrents.len()); + Self { env, users: RwLock::new(users), + torrents: RwLock::new(torrents), } } }