extern crate reqwest;
use crate::samplic::{
Curve, DeviceDescription, Icon, LoadableDevice, MeasurementMetadata,
MeasurementResults, ProfileDescription, SampleMetadata, Sampling,
Translation, UnitDescription,
};
use crate::{error, Result};
use indexmap::IndexSet;
use serde;
use snafu::ResultExt;
use std::io::Read;
use uuid::Uuid;
#[derive(Clone)]
pub struct Device {
api_url: String,
}
impl Device {
pub fn units_url(&self) -> String {
format!("{}/unit", self.api_url)
}
pub fn unit_url(&self, unit_id: &str) -> String {
format!("{}/{}", self.units_url(), unit_id)
}
pub fn translations_url(&self) -> String {
format!("{}/translation", self.api_url)
}
pub fn translation_url(&self, translation_id: &str) -> String {
format!("{}/{}", self.translations_url(), translation_id)
}
pub fn samples_url(&self) -> String {
format!("{}/sample", self.api_url)
}
pub fn sample_url(&self, sample_id: Uuid) -> String {
format!("{}/{}", self.samples_url(), sample_id.to_hyphenated_ref())
}
pub fn sample_metadata_url(&self, sample_id: Uuid) -> String {
format!("{}/{}", self.sample_url(sample_id), "metadata")
}
pub fn measurements_url(&self, sample_id: Uuid) -> String {
format!("{}/measurement", self.sample_url(sample_id))
}
pub fn measurement_url(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> String {
format!(
"{}/{}",
self.measurements_url(sample_id),
measurement_index
)
}
pub fn measurement_metadata_url(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> String {
format!(
"{}/metadata",
self.measurement_url(sample_id, measurement_index),
)
}
pub fn curves_url(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> String {
format!(
"{}/curve",
self.measurement_url(sample_id, measurement_index),
)
}
pub fn curve_url(
&self,
sample_id: Uuid,
measurement_index: usize,
curve_id: &str,
) -> String {
format!(
"{}/{}",
self.curves_url(sample_id, measurement_index),
curve_id
)
}
pub fn results_url(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> String {
format!(
"{}/results",
self.measurement_url(sample_id, measurement_index)
)
}
pub fn description_url(&self) -> String {
format!("{}/description", self.api_url)
}
pub fn samplings_url(&self) -> String {
format!("{}/sampling", self.description_url())
}
pub fn sampling_url(&self, sampling_id: &str) -> String {
format!("{}/{}", self.samplings_url(), sampling_id)
}
pub fn device_description_url(&self) -> String {
format!("{}/device", self.description_url())
}
pub fn system_profiles_url(&self) -> String {
format!("{}/system_profile", self.description_url())
}
pub fn system_profile_url(&self, profile_id: Uuid) -> String {
format!(
"{}/{}",
self.system_profiles_url(),
profile_id.to_hyphenated_ref()
)
}
pub fn user_profiles_url(&self) -> String {
format!("{}/user_profile", self.description_url())
}
pub fn user_profile_url(&self, profile_id: Uuid) -> String {
format!(
"{}/{}",
self.user_profiles_url(),
profile_id.to_hyphenated_ref()
)
}
pub fn images_url(&self) -> String {
format!("{}/image", self.api_url)
}
pub fn icons_url(&self) -> String {
format!("{}/icon", self.images_url())
}
pub fn icon_url(&self, icon_id: &str) -> String {
format!("{}/{}", self.icons_url(), icon_id)
}
pub fn icon_svg_url(&self, icon_id: &str) -> String {
format!("{}/svg", self.icon_url(icon_id))
}
}
fn load_json<T, S: AsRef<str>>(url: S) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let url = url.as_ref();
debug!("Getting url {}", url);
reqwest::get(url)
.context(error::Reqwest {})?
.json()
.context(error::Reqwest {})
}
fn load_index<
T: std::str::FromStr + std::hash::Hash + std::cmp::Eq,
S: AsRef<str>,
>(
url: S,
) -> Result<IndexSet<T>> {
let listing: crate::samplic::DirectoryListing = load_json(url)?;
Ok(listing
.into_iter()
.filter_map(|(k, _v)| T::from_str(&k).ok())
.collect())
}
fn load_string<S: AsRef<str>>(url: S) -> Result<String> {
debug!("Getting url {}", url.as_ref());
let mut response =
reqwest::get(url.as_ref()).context(error::Reqwest {})?;
let mut content = String::new();
response.read_to_string(&mut content).context(
error::ReadResponse {
url: url.as_ref().to_string(),
},
)?;
Ok(content)
}
impl LoadableDevice for Device {
fn load_unit_index(&self) -> Result<IndexSet<String>> {
load_json(self.units_url())
}
fn load_unit(&self, unit_id: &str) -> Result<UnitDescription> {
load_json(self.unit_url(unit_id))
}
fn load_translation_index(&self) -> Result<IndexSet<String>> {
load_json(self.translations_url())
}
fn load_translation(
&self,
translation_id: &str,
) -> Result<Translation> {
load_json(self.translation_url(translation_id))
}
fn load_sample_metadata(
&self,
sample_id: Uuid,
) -> Result<SampleMetadata> {
load_json(self.sample_metadata_url(sample_id))
}
fn load_measurement_metadata(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> Result<MeasurementMetadata> {
load_json(
self.measurement_metadata_url(sample_id, measurement_index),
)
}
fn load_curve(
&self,
sample_id: Uuid,
measurement_index: usize,
curve_id: &str,
) -> Result<Curve> {
load_json(self.curve_url(sample_id, measurement_index, curve_id))
}
fn load_curve_index(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> Result<IndexSet<String>> {
load_index(self.curves_url(sample_id, measurement_index))
}
fn load_results(
&self,
sample_id: Uuid,
measurement_index: usize,
) -> Result<MeasurementResults> {
load_json(self.results_url(sample_id, measurement_index))
}
fn load_sampling_index(&self) -> Result<IndexSet<String>> {
load_index(self.samplings_url())
}
fn load_measurement_index(
&self,
sample_id: Uuid,
) -> Result<IndexSet<usize>> {
let mut index = load_index(self.measurements_url(sample_id))?;
index.sort();
Ok(index)
}
fn load_sample_index(&self) -> Result<IndexSet<Uuid>> {
load_index(self.samples_url())
}
fn load_device_description(&self) -> Result<DeviceDescription> {
load_json(self.device_description_url())
}
fn load_system_profile(
&self,
profile_id: Uuid,
) -> Result<ProfileDescription> {
load_json(self.system_profile_url(profile_id))
}
fn load_system_profile_index(&self) -> Result<IndexSet<Uuid>> {
load_index(self.system_profiles_url())
}
fn load_user_profile(
&self,
profile_id: Uuid,
) -> Result<ProfileDescription> {
load_json(self.user_profile_url(profile_id))
}
fn load_user_profile_index(&self) -> Result<IndexSet<Uuid>> {
load_index(self.user_profiles_url())
}
fn load_sampling(&self, sampling_id: &str) -> Result<Sampling> {
load_json(self.sampling_url(sampling_id))
}
fn load_icon(&self, icon_id: &str) -> Result<Icon> {
load_string(self.icon_svg_url(icon_id))
}
fn load_icon_index(&self) -> Result<IndexSet<String>> {
load_index(self.icons_url())
}
}
impl Device {
pub fn new(api_url: &str) -> Self {
Device {
api_url: api_url.to_string(),
}
}
}