intermodal/src/torrent_summary.rs

122 lines
2.7 KiB
Rust
Raw Normal View History

use crate::common::*;
pub(crate) struct TorrentSummary {
metainfo: Metainfo,
infohash: sha1::Digest,
size: Bytes,
}
impl TorrentSummary {
fn new(bytes: &[u8], metainfo: Metainfo) -> Result<Self, Error> {
let value = bencode::Value::decode(&bytes).unwrap();
let infohash = if let bencode::Value::Dict(items) = value {
let info = items
.iter()
.find(|(key, _value)| key == b"info")
.unwrap()
.1
.encode();
Sha1::from(info).digest()
} else {
unreachable!()
};
Ok(Self {
size: Bytes::from(bytes.len().into_u64()),
infohash,
metainfo,
})
}
pub(crate) fn from_metainfo(metainfo: Metainfo) -> Result<Self, Error> {
let bytes = metainfo.serialize()?;
Self::new(&bytes, metainfo)
}
pub(crate) fn load(path: &Path) -> Result<Self, Error> {
let bytes = fs::read(path).context(error::Filesystem { path })?;
let metainfo = Metainfo::deserialize(path, &bytes)?;
Self::new(&bytes, metainfo)
}
pub(crate) fn write(&self, env: &mut Env) -> Result<(), Error> {
let table = self.table();
table
.write_human_readable(&mut env.out)
.context(error::Stdout)?;
Ok(())
}
fn table(&self) -> Table {
let mut table = Table::new();
table.row("Name", &self.metainfo.info.name);
if let Some(comment) = &self.metainfo.comment {
table.row("Comment", comment);
}
if let Some(creation_date) = self.metainfo.creation_date {
#[allow(clippy::as_conversions)]
table.row(
"Created",
Utc.timestamp(
creation_date
.min(i64::max_value() as u64)
.try_into()
.unwrap(),
0,
),
);
}
table.row("Info Hash", self.infohash);
table.row("Torrent Size", self.size);
table.row("Content Size", self.metainfo.info.mode.total_size());
table.row(
"Private",
if self.metainfo.info.private.unwrap_or(0) == 1 {
"yes"
} else {
"no"
},
);
match &self.metainfo.announce_list {
Some(tiers) => {
let mut value = Vec::new();
value.push(("Main".to_owned(), vec![self.metainfo.announce.clone()]));
for (i, tier) in tiers.iter().enumerate() {
value.push((format!("Tier {}", i + 1), tier.clone()));
}
table.tiers("Trackers", value);
}
None => table.row("Tracker", &self.metainfo.announce),
}
table.row("Piece Size", Bytes::from(self.metainfo.info.piece_length));
table.row("Piece Count", self.metainfo.info.pieces.len() / 20);
table.row(
"File Count",
match &self.metainfo.info.mode {
Mode::Single { .. } => 1,
Mode::Multiple { files } => files.len(),
},
);
table
}
}