diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..5dabb24 --- /dev/null +++ b/config.toml @@ -0,0 +1,9 @@ +api_key = "" +tags_url = "https://platform.yepzon.com/tags" +states_url = "https://platform.yepzon.com/tags/{tag}/states" +locations_url = "https://platform.yepzon.com/tags/{tag}/locations/{state}" +timestamp_format = "%Y-%m-%dT%H:%M:%S%.fZ" +timedate_format = "%d.%m.%Y-%H:%M:%S" +date_format = "%d.%m.%Y" +time_format = "%H:%M:%S" +throttle = 9 diff --git a/src/cmd.rs b/src/cmd.rs index 95291a4..1bb8f85 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -11,22 +11,38 @@ pub struct EnvOpt { #[derive(FromArgs)] #[argh(subcommand)] pub enum Subcommand { - Run(RunOpt), + Since(SinceOpt), Init(InitOpt), } #[derive(FromArgs)] -#[argh(subcommand, name = "run", description = "Run the tool")] -pub struct RunOpt { +#[argh( + subcommand, + name = "since", + description = "fetch locations for a given section in time.\nsince and until in format dd.mm.yyy, OR hh:mm:ss, OR dd.mm.yyy-hh:mm:ss" +)] +pub struct SinceOpt { #[argh( option, short = 'c', - description = "otus", + description = "config.toml file path.", default = "PathBuf::from(\"config.toml\")" )] pub config: PathBuf, + #[argh( + positional, + short = 's', + description = "the oldest point in time to get locations from." + )] + pub since: String, + #[argh( + option, + short = 'u', + description = "the most recent point in time to get locations from, default = now." + )] + pub until: Option, } #[derive(FromArgs)] -#[argh(subcommand, name = "init", description = "Initialize a config file")] +#[argh(subcommand, name = "init", description = "initializes a config file")] pub struct InitOpt {} diff --git a/src/config.rs b/src/config.rs index 59a8be1..8e7c7dc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,9 @@ pub struct Config { pub locations_url: String, pub timestamp_format: String, - pub between_format: String, + pub timedate_format: String, + pub date_format: String, + pub time_format: String, pub throttle: u32, } @@ -24,7 +26,10 @@ impl Default for Config { locations_url: "https://platform.yepzon.com/tags/{tag}/locations/{state}".to_owned(), timestamp_format: "%Y-%m-%dT%H:%M:%S%.fZ".to_owned(), - between_format: "%d.%m.%Y %H:%M:%S".to_owned(), + + timedate_format: "%d.%m.%Y-%H:%M:%S".to_owned(), + date_format: "%d.%m.%Y".to_owned(), + time_format: "%H:%M:%S".to_owned(), throttle: 9, } diff --git a/src/errors.rs b/src/errors.rs index e63d946..8a31bdf 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -52,12 +52,15 @@ impl From for GenericError { impl Display for GenericError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { let err = match self { - GenericError::ChronoParseError(_) => "Chrono parse error".to_owned(), - GenericError::FromUTF8Error(_) => "UTF8 error".to_owned(), + GenericError::ChronoParseError(e) => format!("Date-Time value parse error: {}", e), + GenericError::FromUTF8Error(e) => format!("UTF-8 error: {}", e), GenericError::IOError(e) => format!("IO error: {}", e), - GenericError::MinreqError(_) => "Minreq error".to_owned(), - GenericError::TomlError(_) => "Toml error".to_owned(), - GenericError::YepzonServerError(_) => "Yepzon server error".to_owned(), + GenericError::MinreqError(e) => format!("Network error: {}", e), + GenericError::TomlError(e) => format!("Toml error: {}", e), + GenericError::YepzonServerError(e) => format!( + "Yepzon server error: {}", + e.message.as_ref().unwrap_or(&String::new()) + ), GenericError::MessagedError(msg, err) => format!("{}\n {}", msg, err), }; write!(f, "{}", err) diff --git a/src/main.rs b/src/main.rs index 9770870..0358716 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,8 @@ mod config; mod errors; use api::API; -use chrono::NaiveDateTime; +use chrono::offset::Local; +use chrono::{NaiveDate, NaiveDateTime, NaiveTime, ParseError}; use cmd::*; use config::Config; use errors::{GenericError, MessagedError}; @@ -23,7 +24,7 @@ fn main() { fn from_env(env: EnvOpt) -> Result<(), GenericError> { match env.subcommand { - Subcommand::Run(opt) => { + Subcommand::Since(opt) => { let mut file = File::open(&opt.config).with_msg(format!( "Could not find {}", opt.config.to_str().unwrap_or("") @@ -35,11 +36,14 @@ fn from_env(env: EnvOpt) -> Result<(), GenericError> { let config: Config = toml::from_str(&string).with_msg("given config file is not a valid config file")?; - run( - &config, - Some("1.1.2015 00:00:00".to_owned()), - Some("1.5.2021 00:00:00".to_owned()), - )?; + let since = Some(try_get_datetime(opt.since, &config)?); + + let until = match opt.until { + Some(until) => Some(try_get_datetime(until, &config)?), + None => None, + }; + + run(&config, since, until)?; Ok(()) } Subcommand::Init(_) => { @@ -53,12 +57,13 @@ fn from_env(env: EnvOpt) -> Result<(), GenericError> { } } -fn run(config: &Config, from: Option, to: Option) -> Result<(), GenericError> { +fn run( + config: &Config, + from: Option, + to: Option, +) -> Result<(), GenericError> { let mut api = API::new(config.clone()); - let from = get_opt(from.map(|f| NaiveDateTime::parse_from_str(&f, &config.between_format)))?; - let to = get_opt(to.map(|t| NaiveDateTime::parse_from_str(&t, &config.between_format)))?; - let tags = api.get_tags()?; let first_tag = tags[0].id.clone().unwrap(); let state_list = api.get_states(&first_tag)?; @@ -103,12 +108,12 @@ fn run(config: &Config, from: Option, to: Option) -> Result<(), println!("{:<100}", "Done!"); locations.sort_by(|loc1, loc2| loc2.timestamp.cmp(&loc1.timestamp)); - let _locs = API::get_between(&locations, from, to, false, &config); - /*dbg!( + let locs = API::get_between(&locations, from, to, false, &config); + dbg!( &locs.iter().map(|loc| loc.0).collect::>(), locs.len(), locations.len() - );*/ + ); Ok(()) } @@ -127,3 +132,16 @@ fn exp_time(api: &API, reqs_left: u64) -> Duration { let interval = 1_000 / api.config.throttle as u64; Duration::from_millis(interval * reqs_left) } + +fn try_get_datetime(parsed: String, config: &Config) -> Result { + match NaiveDateTime::parse_from_str(&parsed, &config.timedate_format) { + Ok(timedate) => Ok(timedate), + Err(_) => match NaiveDate::parse_from_str(&parsed, &config.date_format) { + Ok(date) => Ok(date.and_hms(0, 0, 0)), + Err(_) => match NaiveTime::parse_from_str(&parsed, &config.time_format) { + Ok(time) => Ok(Local::today().naive_local().and_time(time)), + Err(e) => Err(e), + }, + }, + } +}