use crate::client::{BlockingHttpClient, HttpError};
use chrono::{DateTime, NaiveDateTime, ParseError};
use log::warn;
use std::fs;
use std::io::Error;
use std::num::ParseIntError;
use std::path::Path;
use std::str::FromStr;
#[derive(Debug)]
pub struct Feed {
pub name: String,
pub metafile: Option<Metafile>,
}
#[derive(Debug)]
pub enum MetafileError {
FileError(Error),
LineError,
SplitError,
ParseIntError(ParseIntError),
ParseDateTimeError(ParseError),
FetchError(HttpError),
}
impl From<Error> for MetafileError {
fn from(error: Error) -> Self {
MetafileError::FileError(error)
}
}
impl From<ParseIntError> for MetafileError {
fn from(error: ParseIntError) -> Self {
MetafileError::ParseIntError(error)
}
}
#[derive(Debug)]
pub struct Metafile {
pub last_modified_date: NaiveDateTime,
pub size: u64,
pub zip_size: u64,
pub gz_size: u64,
pub sha256: String,
}
impl Metafile {
pub fn from_blocking_http_client<C: BlockingHttpClient>(
client: &C,
name: &str,
) -> Result<Self, MetafileError> {
match client.get_metafile(name) {
Ok(metafile_text) => Self::from_string(metafile_text),
Err(error) => Err(MetafileError::FetchError(error)),
}
}
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, MetafileError> {
Self::from_string(fs::read_to_string(path)?)
}
pub fn from_string(contents: String) -> Result<Self, MetafileError> {
macro_rules! next {
($lines:expr) => {
$lines
.next()
.ok_or(MetafileError::LineError)?
.split_once(':')
.ok_or(MetafileError::SplitError)?
.1
};
}
let mut lines = contents.lines();
Ok(Self {
last_modified_date: Self::parse_datetime(next!(lines)),
size: u64::from_str(next!(lines))?,
zip_size: u64::from_str(next!(lines))?,
gz_size: u64::from_str(next!(lines))?,
sha256: next!(lines).to_string(),
})
}
pub fn parse_datetime(datetime: &str) -> NaiveDateTime {
match DateTime::parse_from_rfc3339(datetime) {
Ok(parsed_dt) => parsed_dt.naive_utc(),
Err(_) => match NaiveDateTime::parse_from_str(datetime, "%Y-%m-%dT%H:%M:%S") {
Ok(parsed_ndt) => parsed_ndt,
Err(_) => {
warn!("Failed parsing datetime: {:?}", datetime);
NaiveDateTime::from_timestamp(0, 0)
}
},
}
}
pub fn format_last_modified_date(&self) -> String {
self.last_modified_date
.format("%Y-%m-%dT%H:%M:%S")
.to_string()
}
}