87 lines
3.0 KiB
Rust
87 lines
3.0 KiB
Rust
use snafu::prelude::*;
|
|
|
|
use imdl::infohash::Infohash;
|
|
use imdl::input::Input;
|
|
use imdl::input_target::InputTarget;
|
|
use imdl::magnet_link::MagnetLink;
|
|
use imdl::metainfo::Metainfo;
|
|
use imdl::torrent_summary::TorrentSummary;
|
|
|
|
use std::path::Path;
|
|
use std::net::TcpListener;
|
|
|
|
use crate::error::{Error, InvalidMagnetSnafu as InvalidMagnet, InvalidTorrentSnafu as InvalidTorrent, FailedToReadFileSnafu as FailedToReadFile, OtherTorrentSnafu as OtherTorrentError};
|
|
|
|
/// Helper method for imdl functions which expect an imdl::Input type
|
|
pub fn input_path<T: AsRef<Path>>(path: T) -> Result<Input, Error> {
|
|
let path = path.as_ref();
|
|
let absolute = path.canonicalize().context(FailedToReadFile { path: path.to_path_buf() })?;
|
|
let data = std::fs::read(absolute).context(FailedToReadFile { path: path.to_path_buf() })?;
|
|
Ok(Input::new(
|
|
InputTarget::Path(path.to_path_buf()),
|
|
data
|
|
))
|
|
}
|
|
|
|
/// Extracts the infohash of a magnet link
|
|
pub fn magnet_hash<T: AsRef<str>>(magnet: T) -> Result<String, Error> {
|
|
let magnet = magnet.as_ref();
|
|
let magnet = MagnetLink::parse(magnet).context(InvalidMagnet { magnet: magnet.to_string() })?;
|
|
let bytes = magnet.infohash.inner.bytes.clone();
|
|
let mut s = String::new();
|
|
for byte in bytes {
|
|
s.push_str(&format!("{:02x}", byte));
|
|
}
|
|
Ok(s)
|
|
}
|
|
|
|
/// Extracts the name of a magnet link
|
|
pub fn magnet_name<T: AsRef<str>>(magnet: T) -> Result<Option<String>, Error> {
|
|
let magnet = magnet.as_ref();
|
|
let magnet = MagnetLink::parse(magnet).context(InvalidMagnet { magnet })?;
|
|
Ok(magnet.name)
|
|
}
|
|
|
|
/// Extracts the infohash of a torrent file
|
|
pub fn torrent_hash<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
|
|
let torrent = torrent.as_ref();
|
|
let input = input_path(torrent)?;
|
|
let summary = TorrentSummary::from_input(&input).context(InvalidTorrent { torrent })?;
|
|
Ok(summary.torrent_summary_data().info_hash)
|
|
}
|
|
|
|
/// Extracts the name of a torrent file
|
|
pub fn torrent_name<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
|
|
let torrent = torrent.as_ref();
|
|
let input = input_path(torrent)?;
|
|
let summary = TorrentSummary::from_input(&input).context(InvalidTorrent { torrent })?;
|
|
Ok(summary.torrent_summary_data().name)
|
|
}
|
|
|
|
/// Turns a torrent file into a magnet link
|
|
pub fn torrent_to_magnet<T: AsRef<Path>>(torrent: T) -> Result<String, Error> {
|
|
let torrent = torrent.as_ref();
|
|
let input = input_path(torrent)?;
|
|
let infohash = Infohash::from_input(&input).context(InvalidTorrent { torrent })?;
|
|
let metainfo = Metainfo::from_input(&input).context(InvalidTorrent { torrent })?;
|
|
|
|
let mut link = MagnetLink::with_infohash(infohash);
|
|
|
|
link.set_name(&metainfo.info.name);
|
|
|
|
for result in metainfo.trackers() {
|
|
let result = result.context(OtherTorrentError { torrent })?;
|
|
link.add_tracker(result);
|
|
}
|
|
|
|
Ok(link.to_url().to_string())
|
|
|
|
}
|
|
|
|
// Fallible: only used in tests
|
|
#[allow(dead_code)]
|
|
pub fn find_free_port() -> u16 {
|
|
let bind = TcpListener::bind("127.0.0.1:0").unwrap();
|
|
bind.local_addr().unwrap().port()
|
|
}
|