Initial commit

This commit is contained in:
Sofia 2020-08-23 01:53:49 +03:00
commit 4a6922c2c1
7 changed files with 698 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

427
Cargo.lock generated Normal file
View File

@ -0,0 +1,427 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "argh"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca1877e24cecacd700d469066e0160c4f8497cc5635367163f50c8beec820154"
dependencies = [
"argh_derive",
"argh_shared",
]
[[package]]
name = "argh_derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e742194e0f43fc932bcb801708c2b279d3ec8f527e3acda05a6a9f342c5ef764"
dependencies = [
"argh_shared",
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "argh_shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1ba68f4276a778591e36a0c348a269888f3a177c8d2054969389e3b59611ff5"
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
"byteorder",
]
[[package]]
name = "bumpalo"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "cc"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
dependencies = [
"num-integer",
"num-traits",
"time",
]
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "itoa"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]]
name = "js-sys"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
[[package]]
name = "log"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
]
[[package]]
name = "minreq"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab229c252995e9d56cc66857f3ab2c41e3138b1a6c92089f013698388e64d6bd"
dependencies = [
"lazy_static",
"rustls",
"serde",
"serde_json",
"webpki",
"webpki-roots",
]
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
[[package]]
name = "proc-macro2"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ring"
version = "0.16.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rustls"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e"
dependencies = [
"base64",
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "sct"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "serde"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "syn"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "thingy"
version = "0.1.0"
dependencies = [
"argh",
"chrono",
"minreq",
"serde",
"toml",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "toml"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
dependencies = [
"serde",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "wasm-bindgen"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092"
[[package]]
name = "web-sys"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4"
dependencies = [
"webpki",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "thingy"
version = "0.1.0"
authors = ["Teascade <teascade@gmail.com>"]
edition = "2018"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
minreq = { version = "2.2.0", features = ["https", "json-using-serde"] }
chrono = "0.4"
argh = "0.1"

7
config.toml Normal file
View File

@ -0,0 +1,7 @@
api_key = "E3GrOiQAnY61BP623XXzt9Fo87A1IQrS1FFzD57P"
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"
between_format = "%d.%m.%Y %H:%M:%S"
throttle = 110

163
src/api.rs Normal file
View File

@ -0,0 +1,163 @@
use super::Config;
use chrono::format::ParseError;
use chrono::NaiveDateTime;
use minreq::{Error, Response};
use serde::Deserialize;
use std::thread::sleep;
use std::time::{Duration, Instant};
pub trait Timestamped {
fn timestamp(&self) -> Option<String>;
}
#[derive(Deserialize, Debug)]
pub struct TagModel {
pub id: Option<String>,
pub imei: Option<String>,
#[serde(rename(deserialize = "batteryValue"))]
pub battery_value: Option<i32>,
#[serde(rename(deserialize = "btId"))]
pub bt_id: Option<String>,
#[serde(rename(deserialize = "nfcId"))]
pub nfc_id: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct StateModel {
pub id: Option<String>,
pub timestamp: Option<String>,
#[serde(skip_deserializing)]
pub state: Option<String>,
#[serde(rename(deserialize = "realState"))]
pub real_state: Option<String>,
}
impl Timestamped for StateModel {
fn timestamp(&self) -> Option<String> {
self.timestamp.clone()
}
}
#[derive(Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct LocationModel {
pub timestamp: Option<String>,
#[serde(rename(deserialize = "type"))]
pub loc_type: Option<String>,
#[serde(rename(deserialize = "coordinateLat"))]
pub lat: Option<f32>,
#[serde(rename(deserialize = "coordinateLng"))]
pub lon: Option<f32>,
pub accuracy: Option<f32>,
}
impl Timestamped for LocationModel {
fn timestamp(&self) -> Option<String> {
self.timestamp.clone()
}
}
pub struct API {
config: Config,
pub last_response_ping: u32,
}
impl API {
pub fn new(config: Config) -> API {
API {
last_response_ping: config.throttle,
config: config,
}
}
pub fn get_tags(&mut self) -> Result<Vec<TagModel>, Error> {
let response = self.request(self.config.tags_url.clone())?;
response.json()
}
pub fn get_states(&mut self, tag_id: &String) -> Result<Vec<StateModel>, Error> {
let response = self.request(str::replace(&self.config.states_url, "{tag}", &tag_id))?;
response.json()
}
pub fn get_locations(
&mut self,
tag_id: &String,
state_id: &String,
) -> Result<Vec<LocationModel>, Error> {
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()
}
pub fn get_between<T: Timestamped>(
list: Vec<T>,
from: Option<NaiveDateTime>,
to: Option<NaiveDateTime>,
inclusive_from: bool,
config: &Config,
) -> Vec<(NaiveDateTime, T)> {
let mut timestamped = Vec::new();
for item in list {
if let Some(res) = API::parse_timestamp(&item.timestamp(), config) {
match res {
Ok(t) => {
if let Some(to) = to {
if t > to {
continue;
}
}
let mut too_old = false;
if let Some(from) = from {
if t < from {
too_old = true;
}
}
if too_old {
if inclusive_from {
timestamped.push((t.clone(), item));
}
break;
}
timestamped.push((t.clone(), item));
}
Err(e) => panic!(e),
}
} else {
println!("Skipped item, did not have timestmap");
}
}
timestamped
}
fn request(&mut self, url: String) -> Result<Response, Error> {
let before = Instant::now();
let response = minreq::get(url)
.with_header("content-type", "application/json")
.with_header("x-api-key", &self.config.api_key)
.send();
let after = Instant::now();
let min_time = Duration::new(0, self.config.throttle * 1_000_000);
let duration = after.duration_since(before);
self.last_response_ping = (duration.as_millis() as u32).max(self.config.throttle);
if min_time > duration {
sleep(min_time - duration);
}
response
}
fn parse_timestamp(
timestamp: &Option<String>,
config: &Config,
) -> Option<Result<NaiveDateTime, ParseError>> {
if let Some(timestamp) = &timestamp {
Some(NaiveDateTime::parse_from_str(
&timestamp,
&config.timestamp_format,
))
} else {
None
}
}
}

32
src/config.rs Normal file
View File

@ -0,0 +1,32 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub api_key: String,
pub tags_url: String,
pub states_url: String,
pub locations_url: String,
pub timestamp_format: String,
pub between_format: String,
pub throttle: u32,
}
impl Default for Config {
fn default() -> Config {
Config {
api_key: "E3GrOiQAnY61BP623XXzt9Fo87A1IQrS1FFzD57P".to_owned(),
tags_url: "https://platform.yepzon.com/tags".to_owned(),
states_url: "https://platform.yepzon.com/tags/{tag}/states".to_owned(),
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(),
throttle: 110,
}
}
}

56
src/main.rs Normal file
View File

@ -0,0 +1,56 @@
mod api;
mod config;
use api::API;
use chrono::{NaiveDateTime, ParseError};
use config::Config;
use std::fs::File;
use std::io::prelude::*;
fn main() {
let config = Config::default();
let mut file = File::create("config.toml").unwrap();
file.write_all(&toml::to_vec(&config).unwrap()).ok();
}
fn run(config: &Config, from: Option<String>, to: Option<String>) -> Result<(), ParseError> {
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 first_tag = tags[0].id.clone().unwrap();
let state_list = api.get_states(&first_tag).unwrap();
let states = API::get_between(state_list.clone(), from, to, true, &config);
let len = states.len();
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();
locations.append(&mut location_list);
}
dbg!(API::get_between(locations, from, to, false, &config));
Ok(())
}
fn get_opt<A, B>(option: Option<Result<A, B>>) -> Result<Option<A>, B> {
if let Some(res) = option {
match res {
Ok(a) => Ok(Some(a)),
Err(b) => Err(b),
}
} else {
Ok(None)
}
}
fn exp_time(api: &API, reqs_left: u32) -> f32 {
(reqs_left * api.last_response_ping) as f32 / 1000.
}