tracker gets torrents from backend

This commit is contained in:
FrenchGithubUser
2025-10-15 20:27:14 +02:00
parent f004786997
commit d0f172b8ed
11 changed files with 190 additions and 6 deletions

View File

@@ -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<R: RedisPoolInterface + 'static>(arc: Data<Arcadia<R>>) -> Result<HttpResponse> {
let torrents = arc.pool.find_torrents().await?;
binary_response(&torrents)
}

View File

@@ -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<R: RedisPoolInterface + 'static>(cfg: &mut ServiceConfig) {
cfg.service(resource("/users").route(get().to(self::get_users::exec::<R>)));
cfg.service(resource("/torrents").route(get().to(self::get_torrents::exec::<R>)));
}
fn binary_response<T: bincode::Encode>(value: &T) -> Result<HttpResponse> {

View File

@@ -130,7 +130,6 @@ fn validate_tracker_api_key<R: RedisPoolInterface + 'static>(
req: ServiceRequest,
api_key: &str,
) -> std::result::Result<ServiceRequest, (actix_web::Error, ServiceRequest)> {
println!("tracker req");
let arc = req.app_data::<Data<Arcadia<R>>>().expect("app data set");
if arc.env.tracker.api_key != api_key {

View File

@@ -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"
}

View File

@@ -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<Vec<Torrent>> {
// 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)
}
}

View File

@@ -1 +1,2 @@
pub mod torrent;
pub mod user;

View File

@@ -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,
}

View File

@@ -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]);

View File

@@ -1 +1,2 @@
pub mod torrent;
pub mod user;

View File

@@ -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<InfoHash, Torrent>);
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<Torrent>, 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<InfoHash, Torrent>;
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())
}
}

View File

@@ -14,6 +14,7 @@ pub struct Tracker {
env: Env,
pub users: RwLock<common::models::user::Map>,
pub torrents: RwLock<common::models::torrent::Map>,
}
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),
}
}
}