use std::{collections::HashMap, fmt, ops::Deref};
use serde::{
Deserialize, Deserializer, Serialize,
de::{MapAccess, Visitor},
};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::parameters::TorrentState;
use crate::utilities::deserializers;
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct Torrent {
pub added_on: i64,
pub amount_left: i64,
pub auto_tmm: bool,
pub availability: f64,
pub category: String,
pub comment: String,
pub completed: i64,
pub completion_on: i64,
pub content_path: String,
pub root_path: String,
pub save_path: String,
pub download_path: String,
pub dl_limit: i64,
pub dlspeed: i64,
pub downloaded: i64,
pub downloaded_session: i64,
pub eta: i64,
pub f_l_piece_prio: bool,
pub force_start: bool,
pub has_metadata: bool,
pub hash: String,
pub seeding_time: i64,
pub seeding_time_limit: i64,
pub max_seeding_time: i64,
pub inactive_seeding_time_limit: i64,
pub max_inactive_seeding_time: i64,
pub ratio: f32,
pub ratio_limit: f32,
pub max_ratio: f32,
pub infohash_v1: String,
pub infohash_v2: String,
pub last_activity: i64,
pub magnet_uri: String,
pub name: String,
pub num_complete: i64,
pub num_incomplete: i64,
pub num_leechs: i64,
pub num_seeds: i64,
#[serde(deserialize_with = "deserializers::from_null_to_default")]
pub popularity: f64,
pub priority: i64,
pub private: Option<bool>,
pub progress: f32,
pub reannounce: i64,
pub seen_complete: i64,
pub seq_dl: bool,
pub size: i64,
pub state: TorrentState,
pub super_seeding: bool,
pub tags: String,
pub time_active: i64,
pub total_size: i64,
pub tracker: String,
pub trackers_count: i64,
pub up_limit: i64,
pub uploaded: i64,
pub uploaded_session: i64,
pub upspeed: i64,
}
#[derive(Debug, Serialize, Clone, Default, PartialEq)]
pub struct TorrentsMap(pub HashMap<String, Torrent>);
impl Deref for TorrentsMap {
type Target = HashMap<String, Torrent>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'de> Deserialize<'de> for TorrentsMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(TorrentMapVisitor)
}
}
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
struct TorrentMapVisitor;
impl<'de> Visitor<'de> for TorrentMapVisitor {
type Value = TorrentsMap;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map of torrent infohashes to torrent objects")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));
#[derive(Deserialize)]
struct TmpTorrent {
added_on: i64,
amount_left: i64,
auto_tmm: bool,
availability: f64,
category: String,
comment: String,
completed: i64,
completion_on: i64,
content_path: String,
dl_limit: i64,
dlspeed: i64,
download_path: String,
downloaded: i64,
downloaded_session: i64,
eta: i64,
f_l_piece_prio: bool,
force_start: bool,
has_metadata: bool,
inactive_seeding_time_limit: i64,
infohash_v1: String,
infohash_v2: String,
last_activity: i64,
max_inactive_seeding_time: i64,
magnet_uri: String,
max_ratio: f32,
max_seeding_time: i64,
name: String,
num_complete: i64,
num_incomplete: i64,
num_leechs: i64,
num_seeds: i64,
#[serde(deserialize_with = "deserializers::from_null_to_default")]
popularity: f64,
priority: i64,
private: Option<bool>,
progress: f32,
ratio: f32,
ratio_limit: f32,
reannounce: i64,
root_path: String,
save_path: String,
seeding_time: i64,
seeding_time_limit: i64,
seen_complete: i64,
seq_dl: bool,
size: i64,
state: TorrentState,
super_seeding: bool,
tags: String,
time_active: i64,
total_size: i64,
tracker: String,
trackers_count: i64,
up_limit: i64,
uploaded: i64,
uploaded_session: i64,
upspeed: i64,
}
while let Some(key) = access.next_key::<String>()? {
let temp_torrent: TmpTorrent = access.next_value()?;
let torrent = Torrent {
hash: key.clone(),
added_on: temp_torrent.added_on,
amount_left: temp_torrent.amount_left,
auto_tmm: temp_torrent.auto_tmm,
availability: temp_torrent.availability,
category: temp_torrent.category,
comment: temp_torrent.comment,
completed: temp_torrent.completed,
completion_on: temp_torrent.completion_on,
content_path: temp_torrent.content_path,
dl_limit: temp_torrent.dl_limit,
dlspeed: temp_torrent.dlspeed,
download_path: temp_torrent.download_path,
downloaded: temp_torrent.downloaded,
downloaded_session: temp_torrent.downloaded_session,
eta: temp_torrent.eta,
f_l_piece_prio: temp_torrent.f_l_piece_prio,
force_start: temp_torrent.force_start,
has_metadata: temp_torrent.has_metadata,
inactive_seeding_time_limit: temp_torrent.inactive_seeding_time_limit,
infohash_v1: temp_torrent.infohash_v1,
infohash_v2: temp_torrent.infohash_v2,
last_activity: temp_torrent.last_activity,
max_inactive_seeding_time: temp_torrent.max_inactive_seeding_time,
magnet_uri: temp_torrent.magnet_uri,
max_ratio: temp_torrent.max_ratio,
max_seeding_time: temp_torrent.max_seeding_time,
name: temp_torrent.name,
num_complete: temp_torrent.num_complete,
num_incomplete: temp_torrent.num_incomplete,
num_leechs: temp_torrent.num_leechs,
num_seeds: temp_torrent.num_seeds,
popularity: temp_torrent.popularity,
priority: temp_torrent.priority,
private: temp_torrent.private,
progress: temp_torrent.progress,
ratio: temp_torrent.ratio,
ratio_limit: temp_torrent.ratio_limit,
reannounce: temp_torrent.reannounce,
root_path: temp_torrent.root_path,
save_path: temp_torrent.save_path,
seeding_time: temp_torrent.seeding_time,
seeding_time_limit: temp_torrent.seeding_time_limit,
seen_complete: temp_torrent.seen_complete,
seq_dl: temp_torrent.seq_dl,
size: temp_torrent.size,
state: temp_torrent.state,
super_seeding: temp_torrent.super_seeding,
tags: temp_torrent.tags,
time_active: temp_torrent.time_active,
total_size: temp_torrent.total_size,
tracker: temp_torrent.tracker,
trackers_count: temp_torrent.trackers_count,
up_limit: temp_torrent.up_limit,
uploaded: temp_torrent.uploaded,
uploaded_session: temp_torrent.uploaded_session,
upspeed: temp_torrent.upspeed,
};
map.insert(key, torrent);
}
Ok(TorrentsMap(map))
}
}
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct TorrentProperties {
pub save_path: String,
pub creation_date: i64,
pub piece_size: i64,
pub comment: String,
pub total_wasted: i64,
pub total_uploaded: i64,
pub total_uploaded_session: i64,
pub total_downloaded: i64,
pub total_downloaded_session: i64,
pub up_limit: i64,
pub dl_limit: i64,
pub time_elapsed: i64,
pub seeding_time: i64,
pub nb_connections: i64,
pub nb_connections_limit: i64,
pub share_ratio: f32,
pub addition_date: i64,
pub completion_date: i64,
pub created_by: String,
pub dl_speed_avg: i64,
pub dl_speed: i64,
pub eta: i64,
pub last_seen: i64,
pub peers: i64,
pub peers_total: i64,
pub pieces_have: i64,
pub pieces_num: i64,
pub reannounce: i64,
pub seeds: i64,
pub seeds_total: i64,
pub total_size: i64,
pub up_speed_avg: i64,
pub up_speed: i64,
pub private: Option<bool>,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct Tracker {
pub url: String,
pub status: i64,
pub tier: i64,
pub num_peers: i64,
pub num_seeds: i64,
pub num_leeches: i64,
pub num_downloaded: i64,
pub msg: String,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct WebSeed {
pub url: String,
}
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct TorrentContent {
pub index: i64,
pub name: String,
pub size: i64,
pub progress: f64,
pub priority: FilePriority,
pub is_seed: Option<bool>,
pub piece_range: Vec<i64>,
pub availability: f64,
}
#[derive(Debug, Deserialize_repr, Serialize_repr, Clone, Default, PartialEq)]
#[repr(u8)]
pub enum FilePriority {
DoNotDownload = 0,
#[default]
Normal = 1,
High = 6,
Maximal = 7,
}
#[derive(Debug, Deserialize_repr, Serialize_repr, Clone, Default, PartialEq)]
#[repr(u8)]
pub enum PiecesState {
#[default]
NotDownloaded = 0,
Downloading = 1,
Downloaded = 2,
}