Add GenericError
This commit is contained in:
parent
fa77f315a1
commit
96c03ae7ed
@ -1,4 +1,4 @@
|
|||||||
api_key = "E3GrOiQAnY61BP623XXzt9Fo87A1IQrS1FFzD57P"
|
api_key = ""
|
||||||
tags_url = "https://platform.yepzon.com/tags"
|
tags_url = "https://platform.yepzon.com/tags"
|
||||||
states_url = "https://platform.yepzon.com/tags/{tag}/states"
|
states_url = "https://platform.yepzon.com/tags/{tag}/states"
|
||||||
locations_url = "https://platform.yepzon.com/tags/{tag}/locations/{state}"
|
locations_url = "https://platform.yepzon.com/tags/{tag}/locations/{state}"
|
||||||
|
29
src/api.rs
29
src/api.rs
@ -1,4 +1,5 @@
|
|||||||
use super::Config;
|
use super::Config;
|
||||||
|
use super::GenericError;
|
||||||
use chrono::format::ParseError;
|
use chrono::format::ParseError;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use minreq::{Error, Response};
|
use minreq::{Error, Response};
|
||||||
@ -10,6 +11,12 @@ pub trait Timestamped {
|
|||||||
fn timestamp(&self) -> Option<String>;
|
fn timestamp(&self) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct ErrorModel {
|
||||||
|
#[serde(rename(deserialize = "Message"))]
|
||||||
|
pub message: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct TagModel {
|
pub struct TagModel {
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
@ -70,25 +77,31 @@ impl API {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tags(&mut self) -> Result<Vec<TagModel>, Error> {
|
pub fn get_tags(&mut self) -> Result<Vec<TagModel>, GenericError> {
|
||||||
let response = self.request(self.config.tags_url.clone())?;
|
let response = self.request(self.config.tags_url.clone())?;
|
||||||
response.json()
|
let tags = response.json();
|
||||||
|
if let Err(_) = tags {
|
||||||
|
let err: ErrorModel = response.json()?;
|
||||||
|
Err(GenericError::from(err))
|
||||||
|
} else {
|
||||||
|
tags.map_err(GenericError::from)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_states(&mut self, tag_id: &String) -> Result<Vec<StateModel>, Error> {
|
pub fn get_states(&mut self, tag_id: &String) -> Result<Vec<StateModel>, GenericError> {
|
||||||
let response = self.request(str::replace(&self.config.states_url, "{tag}", &tag_id))?;
|
let response = self.request(str::replace(&self.config.states_url, "{tag}", &tag_id))?;
|
||||||
response.json()
|
Ok(response.json()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_locations(
|
pub fn get_locations(
|
||||||
&mut self,
|
&mut self,
|
||||||
tag_id: &String,
|
tag_id: &String,
|
||||||
state_id: &String,
|
state_id: &String,
|
||||||
) -> Result<Vec<LocationModel>, Error> {
|
) -> Result<Vec<LocationModel>, GenericError> {
|
||||||
let url = str::replace(&self.config.locations_url, "{tag}", &tag_id);
|
let url = str::replace(&self.config.locations_url, "{tag}", &tag_id);
|
||||||
let url = str::replace(&url, "{state}", &state_id);
|
let url = str::replace(&url, "{state}", &state_id);
|
||||||
let response = self.request(url)?;
|
let response = self.request(url)?;
|
||||||
response.json()
|
Ok(response.json()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_between<T: Timestamped>(
|
pub fn get_between<T: Timestamped>(
|
||||||
@ -131,7 +144,7 @@ impl API {
|
|||||||
timestamped
|
timestamped
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request(&mut self, url: String) -> Result<Response, Error> {
|
fn request(&mut self, url: String) -> Result<Response, GenericError> {
|
||||||
let before = Instant::now();
|
let before = Instant::now();
|
||||||
let response = minreq::get(url)
|
let response = minreq::get(url)
|
||||||
.with_header("content-type", "application/json")
|
.with_header("content-type", "application/json")
|
||||||
@ -144,7 +157,7 @@ impl API {
|
|||||||
if min_time > duration {
|
if min_time > duration {
|
||||||
sleep(min_time - duration);
|
sleep(min_time - duration);
|
||||||
}
|
}
|
||||||
response
|
response.map_err(GenericError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_timestamp(
|
fn parse_timestamp(
|
||||||
|
41
src/errors.rs
Normal file
41
src/errors.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use super::api::ErrorModel;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GenericError {
|
||||||
|
TomlError(toml::de::Error),
|
||||||
|
YepzonServerError(ErrorModel),
|
||||||
|
MinreqError(minreq::Error),
|
||||||
|
ChronoParseError(chrono::ParseError),
|
||||||
|
IOError(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<toml::de::Error> for GenericError {
|
||||||
|
fn from(error: toml::de::Error) -> Self {
|
||||||
|
GenericError::TomlError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<minreq::Error> for GenericError {
|
||||||
|
fn from(error: minreq::Error) -> Self {
|
||||||
|
GenericError::MinreqError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<chrono::ParseError> for GenericError {
|
||||||
|
fn from(error: chrono::ParseError) -> Self {
|
||||||
|
GenericError::ChronoParseError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorModel> for GenericError {
|
||||||
|
fn from(error: ErrorModel) -> Self {
|
||||||
|
GenericError::YepzonServerError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for GenericError {
|
||||||
|
fn from(error: io::Error) -> Self {
|
||||||
|
GenericError::IOError(error)
|
||||||
|
}
|
||||||
|
}
|
49
src/main.rs
49
src/main.rs
@ -1,62 +1,55 @@
|
|||||||
mod api;
|
mod api;
|
||||||
mod cmd;
|
mod cmd;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod errors;
|
||||||
|
|
||||||
use api::API;
|
use api::API;
|
||||||
use chrono::{NaiveDateTime, ParseError};
|
use chrono::NaiveDateTime;
|
||||||
use cmd::*;
|
use cmd::*;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use errors::GenericError;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let env: EnvOpt = argh::from_env();
|
let env: EnvOpt = argh::from_env();
|
||||||
|
if let Err(e) = from_env(env) {
|
||||||
|
eprintln!("Error: {:?}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_env(env: EnvOpt) -> Result<(), GenericError> {
|
||||||
match env.subcommand {
|
match env.subcommand {
|
||||||
Subcommand::Run(opt) => {
|
Subcommand::Run(opt) => {
|
||||||
let mut file = match File::open("config.toml") {
|
let mut file = File::open("config.toml")?;
|
||||||
Ok(file) => file,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Could not read config file: {}\nMake sure one exists with init subcommand.", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
if let Err(e) = file.read_to_string(&mut string) {
|
file.read_to_string(&mut string)?;
|
||||||
eprintln!("Config file data not valid UTF-8: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let config: Config = match toml::from_str(&string) {
|
let config: Config = toml::from_str(&string)?;
|
||||||
Ok(config) => config,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Config file could not be parsed: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
run(&config, None, None).ok();
|
run(&config, None, None)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Subcommand::Init(opt) => {
|
Subcommand::Init(opt) => {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
|
|
||||||
let mut file = File::create("config.toml").unwrap();
|
let mut file = File::create("config.toml").unwrap();
|
||||||
if let Err(e) = file.write_all(&toml::to_vec(&config).unwrap()) {
|
file.write_all(&toml::to_vec(&config).unwrap())?;
|
||||||
eprintln!("Could not write to file: {}", e);
|
Ok(())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(config: &Config, from: Option<String>, to: Option<String>) -> Result<(), ParseError> {
|
fn run(config: &Config, from: Option<String>, to: Option<String>) -> Result<(), GenericError> {
|
||||||
let mut api = API::new(config.clone());
|
let mut api = API::new(config.clone());
|
||||||
|
|
||||||
let from = get_opt(from.map(|f| NaiveDateTime::parse_from_str(&f, &config.between_format)))?;
|
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 to = get_opt(to.map(|t| NaiveDateTime::parse_from_str(&t, &config.between_format)))?;
|
||||||
|
|
||||||
let tags = api.get_tags().unwrap();
|
let tags = api.get_tags()?;
|
||||||
let first_tag = tags[0].id.clone().unwrap();
|
let first_tag = tags[0].id.clone().unwrap();
|
||||||
let state_list = api.get_states(&first_tag).unwrap();
|
let state_list = api.get_states(&first_tag)?;
|
||||||
|
|
||||||
let states = API::get_between(state_list.clone(), from, to, true, &config);
|
let states = API::get_between(state_list.clone(), from, to, true, &config);
|
||||||
let len = states.len();
|
let len = states.len();
|
||||||
@ -64,9 +57,7 @@ fn run(config: &Config, from: Option<String>, to: Option<String>) -> Result<(),
|
|||||||
let mut locations = Vec::new();
|
let mut locations = Vec::new();
|
||||||
for (idx, (_, state)) in states.iter().enumerate() {
|
for (idx, (_, state)) in states.iter().enumerate() {
|
||||||
println!("Expected {}s left", exp_time(&api, (len - idx) as u32));
|
println!("Expected {}s left", exp_time(&api, (len - idx) as u32));
|
||||||
let mut location_list = api
|
let mut location_list = api.get_locations(&first_tag, state.id.as_ref().unwrap())?;
|
||||||
.get_locations(&first_tag, state.id.as_ref().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
locations.append(&mut location_list);
|
locations.append(&mut location_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user