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"
|
||||
states_url = "https://platform.yepzon.com/tags/{tag}/states"
|
||||
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::GenericError;
|
||||
use chrono::format::ParseError;
|
||||
use chrono::NaiveDateTime;
|
||||
use minreq::{Error, Response};
|
||||
@ -10,6 +11,12 @@ pub trait Timestamped {
|
||||
fn timestamp(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ErrorModel {
|
||||
#[serde(rename(deserialize = "Message"))]
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct TagModel {
|
||||
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())?;
|
||||
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))?;
|
||||
response.json()
|
||||
Ok(response.json()?)
|
||||
}
|
||||
|
||||
pub fn get_locations(
|
||||
&mut self,
|
||||
tag_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(&url, "{state}", &state_id);
|
||||
let response = self.request(url)?;
|
||||
response.json()
|
||||
Ok(response.json()?)
|
||||
}
|
||||
|
||||
pub fn get_between<T: Timestamped>(
|
||||
@ -131,7 +144,7 @@ impl API {
|
||||
timestamped
|
||||
}
|
||||
|
||||
fn request(&mut self, url: String) -> Result<Response, Error> {
|
||||
fn request(&mut self, url: String) -> Result<Response, GenericError> {
|
||||
let before = Instant::now();
|
||||
let response = minreq::get(url)
|
||||
.with_header("content-type", "application/json")
|
||||
@ -144,7 +157,7 @@ impl API {
|
||||
if min_time > duration {
|
||||
sleep(min_time - duration);
|
||||
}
|
||||
response
|
||||
response.map_err(GenericError::from)
|
||||
}
|
||||
|
||||
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 cmd;
|
||||
mod config;
|
||||
mod errors;
|
||||
|
||||
use api::API;
|
||||
use chrono::{NaiveDateTime, ParseError};
|
||||
use chrono::NaiveDateTime;
|
||||
use cmd::*;
|
||||
use config::Config;
|
||||
use errors::GenericError;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn main() {
|
||||
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 {
|
||||
Subcommand::Run(opt) => {
|
||||
let mut file = match 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 file = File::open("config.toml")?;
|
||||
let mut string = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut string) {
|
||||
eprintln!("Config file data not valid UTF-8: {}", e);
|
||||
return;
|
||||
}
|
||||
file.read_to_string(&mut string)?;
|
||||
|
||||
let config: Config = match toml::from_str(&string) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
eprintln!("Config file could not be parsed: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config: Config = toml::from_str(&string)?;
|
||||
|
||||
run(&config, None, None).ok();
|
||||
run(&config, None, None)?;
|
||||
Ok(())
|
||||
}
|
||||
Subcommand::Init(opt) => {
|
||||
let config = Config::default();
|
||||
|
||||
let mut file = File::create("config.toml").unwrap();
|
||||
if let Err(e) = file.write_all(&toml::to_vec(&config).unwrap()) {
|
||||
eprintln!("Could not write to file: {}", e);
|
||||
}
|
||||
file.write_all(&toml::to_vec(&config).unwrap())?;
|
||||
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 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().unwrap();
|
||||
let tags = api.get_tags()?;
|
||||
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 len = states.len();
|
||||
@ -64,9 +57,7 @@ fn run(config: &Config, from: Option<String>, to: Option<String>) -> Result<(),
|
||||
let mut locations = Vec::new();
|
||||
for (idx, (_, state)) in states.iter().enumerate() {
|
||||
println!("Expected {}s left", exp_time(&api, (len - idx) as u32));
|
||||
let mut location_list = api
|
||||
.get_locations(&first_tag, state.id.as_ref().unwrap())
|
||||
.unwrap();
|
||||
let mut location_list = api.get_locations(&first_tag, state.id.as_ref().unwrap())?;
|
||||
locations.append(&mut location_list);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user