use url::Url;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum PeerSource {
DHT,
PEX,
LSD,
Tracker(Tracker),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Tracker {
scheme: TrackerScheme,
url: String,
}
impl Tracker {
pub fn scheme(&self) -> &TrackerScheme {
&self.scheme
}
pub fn url(&self) -> &str {
&self.url
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum TrackerScheme {
Websocket,
Http,
UDP,
}
#[derive(Clone, Debug, PartialEq)]
pub enum TrackerError {
InvalidURL { source: url::ParseError },
InvalidScheme { scheme: String },
}
impl std::fmt::Display for TrackerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TrackerError::InvalidURL { source } => write!(f, "Invalid URL: {source}"),
TrackerError::InvalidScheme { scheme } => write!(f, "Invalid scheme: {scheme}"),
}
}
}
impl std::error::Error for TrackerError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
TrackerError::InvalidURL { source } => Some(source),
TrackerError::InvalidScheme { scheme: _ } => None,
}
}
}
impl From<url::ParseError> for TrackerError {
fn from(e: url::ParseError) -> TrackerError {
TrackerError::InvalidURL { source: e }
}
}
impl PeerSource {
pub fn new(url: &str) -> Result<PeerSource, TrackerError> {
Ok(Tracker::new(url)?.to_peer_source())
}
pub fn from_url(url: &Url) -> Result<PeerSource, TrackerError> {
Ok(Tracker::from_url(url)?.to_peer_source())
}
pub fn from_tracker(tracker: &Tracker) -> PeerSource {
PeerSource::Tracker(tracker.clone())
}
}
impl Tracker {
pub fn new(url: &str) -> Result<Tracker, TrackerError> {
let url = Url::parse(url)?;
Tracker::from_url(&url)
}
pub fn from_url(url: &Url) -> Result<Tracker, TrackerError> {
let scheme = match url.scheme() {
"http" | "https" => TrackerScheme::Http,
"wss" => TrackerScheme::Websocket,
"udp" => TrackerScheme::UDP,
_ => {
return Err(TrackerError::InvalidScheme {
scheme: url.scheme().to_string(),
});
}
};
Ok(Tracker {
scheme,
url: url.as_str().to_string(),
})
}
pub fn to_peer_source(&self) -> PeerSource {
PeerSource::from_tracker(self)
}
}
pub trait TryIntoTracker {
fn try_into_tracker(&self) -> Result<Tracker, TrackerError>;
}