graph-http 0.0.2

Http client and utilities for the graph-rs project
Documentation
use crate::types::{Content, Delta};
use crate::url::GraphUrl;
use crate::GraphResponse;
use graph_error::{GraphFailure, GraphResult};
use reqwest::header::CONTENT_TYPE;
use std::convert::TryFrom;
use std::sync::mpsc::{channel, Receiver};
use std::thread;

pub trait DownloadLink<RHS = Self> {
    fn download_link(&self) -> Option<String>;
}

pub trait MetadataLink<RHS = Self> {
    fn metadata_link(&self) -> Option<String>;

    fn metadata(&self) -> Option<GraphResult<GraphResponse<Content>>> {
        let link = self.metadata_link()?;
        let client = reqwest::blocking::Client::new();
        let response = client.get(link.as_str()).send();

        if let Err(e) = response {
            Some(Err(GraphFailure::from(e)))
        } else if let Ok(res) = response {
            Some(GraphResponse::try_from(res))
        } else {
            None
        }
    }
}

pub trait NextLink<RHS = Self> {
    fn next_link(&self) -> Option<String>;
}

pub trait DeltaLink<RHS = Self> {
    fn delta_link(&self) -> Option<String>;

    #[allow(unused_assignments)]
    fn delta<T: 'static + Send + NextLink>(&self, access_token: &str) -> Option<Receiver<Delta<T>>>
    where
        for<'de> T: serde::Deserialize<'de>,
    {
        let link = self.delta_link()?;
        let token = access_token.to_string();
        let (sender, receiver) = channel();
        let client = reqwest::blocking::Client::new();
        let response = client
            .get(link.as_str())
            .bearer_auth(token.as_str())
            .send()
            .map_err(GraphFailure::from);

        if let Err(err) = response {
            sender.send(Delta::Done(Some(err))).unwrap();
            return Some(receiver);
        }

        let res = response.unwrap();
        if let Some(err) = GraphFailure::from_response(&res) {
            sender.send(Delta::Done(Some(err))).unwrap();
            return Some(receiver);
        }

        let url = GraphUrl::from(res.url());
        let headers = res.headers().clone();
        let status = res.status().as_u16();
        let next: GraphResult<T> = res.json().map_err(GraphFailure::from);
        if let Err(err) = next {
            sender.send(Delta::Done(Some(err))).unwrap();
            return Some(receiver);
        }

        let value: T = next.unwrap();
        let mut next_link = value.next_link();
        sender
            .send(Delta::Next(GraphResponse::new(url, value, status, headers)))
            .unwrap();

        thread::spawn(move || {
            while let Some(next) = next_link {
                let res = client
                    .get(next.as_str())
                    .header(CONTENT_TYPE, "application/json")
                    .bearer_auth(token.as_str())
                    .send()
                    .map_err(GraphFailure::from);

                if let Err(err) = res {
                    next_link = None;
                    sender.send(Delta::Done(Some(err))).unwrap();
                } else {
                    let response = res.unwrap();
                    let url = GraphUrl::from(response.url());
                    let headers = response.headers().clone();
                    let status = response.status().as_u16();
                    if let Some(err) = GraphFailure::from_response(&response) {
                        next_link = None;
                        sender.send(Delta::Done(Some(err))).unwrap();
                    }

                    let value_res: GraphResult<T> = response.json().map_err(GraphFailure::from);
                    if let Err(err) = value_res {
                        next_link = None;
                        sender.send(Delta::Done(Some(err))).unwrap();
                    } else {
                        let value = value_res.unwrap();
                        next_link = value.next_link();
                        sender
                            .send(Delta::Next(GraphResponse::new(url, value, status, headers)))
                            .unwrap();
                    }
                }
            }
            sender.send(Delta::Done(None)).unwrap();
        });

        Some(receiver)
    }
}

impl DownloadLink for serde_json::Value {
    fn download_link(&self) -> Option<String> {
        self["@microsoft.graph.downloadUrl"]
            .as_str()
            .map(|s| s.to_string())
    }
}

impl NextLink for serde_json::Value {
    fn next_link(&self) -> Option<String> {
        self["@odata.nextLink"].as_str().map(|s| s.to_string())
    }
}

impl DeltaLink for serde_json::Value {
    fn delta_link(&self) -> Option<String> {
        self["@odata.deltaLink"].as_str().map(|s| s.to_string())
    }
}

impl MetadataLink for serde_json::Value {
    fn metadata_link(&self) -> Option<String> {
        self["@odata.context"].as_str().map(|s| s.to_string())
    }
}