From 8615cc2f030240ba2982dba893fe63f11a0c8a88 Mon Sep 17 00:00:00 2001 From: David Blajda Date: Thu, 13 Dec 2018 20:56:55 +0000 Subject: Restructure project and included kraken endpoint --- src/bin/main.rs | 20 ++++++-- src/helix/endpoints.rs | 121 +++++++++++++++++++++++++++++++++++++++++++++++ src/helix/mod.rs | 2 + src/helix/models.rs | 76 ++++++++++++++++++++++++++++++ src/kraken/endpoints.rs | 20 ++++++++ src/kraken/mod.rs | 33 +++++++++++++ src/kraken/models.rs | 44 +++++++++++++++++ src/lib.rs | 122 ++++-------------------------------------------- src/models.rs | 76 ------------------------------ 9 files changed, 322 insertions(+), 192 deletions(-) create mode 100644 src/helix/endpoints.rs create mode 100644 src/helix/mod.rs create mode 100644 src/helix/models.rs create mode 100644 src/kraken/endpoints.rs create mode 100644 src/kraken/mod.rs create mode 100644 src/kraken/models.rs delete mode 100644 src/models.rs (limited to 'src') diff --git a/src/bin/main.rs b/src/bin/main.rs index 61e16ef..1aa55ed 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -6,11 +6,13 @@ extern crate twitch_api; use futures::future::Future; use std::env; +use twitch_api::HelixClient; use twitch_api::Client; fn main() { dotenv::dotenv().unwrap(); - let twitch_api = Client::new(&env::var("TWITCH_API").unwrap()); + let client_id = &env::var("TWITCH_API").unwrap(); + let client = Client::new(client_id); /* let users = twitch_api @@ -40,7 +42,7 @@ fn main() { */ - let clip = twitch_api + let clip = client.helix .clip(&"EnergeticApatheticTarsierThisIsSparta") .and_then(|json| { println!("{:?}", json); @@ -52,5 +54,17 @@ fn main() { () }); - tokio::run(clip); + let clip2 = client.kraken + .clip(&"EnergeticApatheticTarsierThisIsSparta") + .and_then(|json| { + print!("{:?}", json); + Ok(json) + }) + .map(|_| ()) + .map_err(|err| { + println!("{:?}", err); + () + }); + + tokio::run(clip.join(clip2).map(|_| ()).map_err(|_| ())); } diff --git a/src/helix/endpoints.rs b/src/helix/endpoints.rs new file mode 100644 index 0000000..5c3aa05 --- /dev/null +++ b/src/helix/endpoints.rs @@ -0,0 +1,121 @@ +use futures::future::Future; +use reqwest::header; +use reqwest::r#async::{Chunk, Decoder, Request, Response}; +use reqwest::r#async::Client as ReqwestClient; + +use super::models::{DataContainer, PaginationContainer, User, Video, Clip}; + +const API_DOMAIN: &'static str = "api.twitch.tv"; + +/* When Client owns a ReqwestClient, any futures spawned do not immediately + * terminate but 'hang'. When creating a new client for each request this problem + * does not occur. This would need to be resolved so we can benefit from keep alive + * connections. + * + */ + +pub struct Client { + id: String, +} + +impl Client { + pub fn new(client_id: &str) -> Client { + Client { + id: client_id.to_owned(), + } + } + + fn create_client(&self) -> ReqwestClient { + let mut headers = header::HeaderMap::new(); + let auth_key = &self.id; + let header_value = header::HeaderValue::from_str(auth_key).unwrap(); + headers.insert("Client-ID", header_value); + + let client = ReqwestClient::builder().default_headers(headers).build().unwrap(); + client + } + + pub fn users( + &self, + id: Vec<&str>, + login: Vec<&str>, + ) -> impl Future, Error = reqwest::Error> { + let mut url = + String::from("https://") + &String::from(API_DOMAIN) + &String::from("/helix/users"); + + if id.len() > 0 || login.len() > 0 { + url.push_str("?"); + } + + if id.len() > 0 { + for index in 0..id.len() { + url.push_str("id="); + url.push_str(id[index]); + url.push('&'); + } + } + + if login.len() > 0 { + for index in 0..login.len() { + url.push_str("login="); + url.push_str(login[index]); + url.push('&'); + } + } + + + let f = self.create_client() + .get(&url) + .send() + .map(|mut res| res.json::>()) + .and_then(|json| json); + + return f; + } + + pub fn videos( + &self, + video_id: Option>, + user_id: Option<&str>, + game_id: Option<&str>, + ) -> impl Future, Error = reqwest::Error> { + let mut url = + String::from("https://") + &String::from(API_DOMAIN) + &String::from("/helix/videos"); + + url.push_str("?"); + if let Some(user_id) = user_id { + url.push_str("user_id="); + url.push_str(user_id); + url.push('&'); + } + + let f = self.create_client() + .get(&url) + .send() + .map(|mut res| { + res.json::>() + }) + .and_then(|json| json); + + return f; + } + + pub fn clip(&self, id: &str) + -> impl Future, Error=reqwest::Error> + { + let url = + String::from("https://") + + API_DOMAIN + "/helix/clips" + "?id=" + id; + + let f = self.create_client() + .get(&url) + .send() + .map(|mut res| { + println!("{:?}", res); + res.json::>() + }) + .and_then(|json| json); + + return f; + } +} diff --git a/src/helix/mod.rs b/src/helix/mod.rs new file mode 100644 index 0000000..ce4a7a2 --- /dev/null +++ b/src/helix/mod.rs @@ -0,0 +1,2 @@ +pub mod endpoints; +pub mod models; diff --git a/src/helix/models.rs b/src/helix/models.rs new file mode 100644 index 0000000..2b01e7c --- /dev/null +++ b/src/helix/models.rs @@ -0,0 +1,76 @@ +extern crate serde_json; +extern crate chrono; + +use chrono::{Duration, DateTime, Utc}; + + +#[derive(Debug, Deserialize)] +pub struct DataContainer { + pub data: Vec +} + +#[derive(Debug, Deserialize)] +pub struct Cursor { + cursor: String +} + +#[derive(Debug, Deserialize)] +pub struct PaginationContainer { + pub data: Vec, + pub pagination: Option +} + +#[derive(Debug, Deserialize)] +pub struct Video { + pub id: String, + pub user_id: String, + pub user_name: String, + pub title: String, + pub description: String, + //Should be converted to a DateTime + pub created_at: String, + pub published_at: String, + //Should be converted to a URL + pub url: String, + pub thumbnail_url: String, + pub viewable: String, + pub view_count: i32, + pub language: String, + #[serde(rename = "type")] + pub video_type: String, + //Should be converted to a Duration + pub duration: String, +} + +#[derive(Debug, Deserialize)] +pub struct User { + pub id: String, + pub login: String, + pub display_name: String, + #[serde(rename = "type")] + pub user_type: String, + pub broadcaster_type: String, + pub description: String, + pub profile_image_url: String, + pub offline_image_url: String, + pub view_count: u32, + pub email: Option, +} + +#[derive(Debug, Deserialize)] +pub struct Clip { + pub id: String, + pub url: String, + pub embed_url: String, + pub broadcaster_id: String, + pub broadcaster_name: String, + pub creator_id: String, + pub creator_name: String, + pub video_id: String, + pub game_id: String, + pub language: String, + pub title: String, + pub created_at: String, + pub thumbnail_url: String, + pub view_count: i32, +} diff --git a/src/kraken/endpoints.rs b/src/kraken/endpoints.rs new file mode 100644 index 0000000..2dbc8d1 --- /dev/null +++ b/src/kraken/endpoints.rs @@ -0,0 +1,20 @@ +use futures::Future; +use super::models::Clip; +use super::Client; + +use super::API_DOMAIN; + +impl Client { + pub fn clip(&self, id: &str) + -> impl Future + { + let url = String::from("https://") + API_DOMAIN + "/kraken/clips/" + id; + let client = self.create_reqwest_client(); + + client + .get(&url) + .send() + .map(|mut res| res.json::()) + .and_then(|json| json) + } +} diff --git a/src/kraken/mod.rs b/src/kraken/mod.rs new file mode 100644 index 0000000..2015781 --- /dev/null +++ b/src/kraken/mod.rs @@ -0,0 +1,33 @@ +use reqwest::header; +use reqwest::r#async::{Chunk, Decoder, Request, Response}; +use reqwest::r#async::Client as ReqwestClient; + +mod endpoints; +mod models; + +const ACCEPT: &str = "application/vnd.twitchtv.v5+json"; +pub const API_DOMAIN: &str = "api.twitch.tv"; + +pub struct Client { + id: String, +} + +impl Client { + pub fn new(id: &str) -> Client { + Client { + id: id.to_owned(), + } + } + + fn create_reqwest_client(&self) -> ReqwestClient { + let mut headers = header::HeaderMap::new(); + let auth_key = &self.id; + let client_header = header::HeaderValue::from_str(auth_key).unwrap(); + let accept_header = header::HeaderValue::from_str(ACCEPT).unwrap(); + headers.insert("Client-ID", client_header); + headers.insert("Accept", accept_header); + + let client = ReqwestClient::builder().default_headers(headers).build().unwrap(); + client + } +} diff --git a/src/kraken/models.rs b/src/kraken/models.rs new file mode 100644 index 0000000..13c524c --- /dev/null +++ b/src/kraken/models.rs @@ -0,0 +1,44 @@ +extern crate serde_json; +extern crate chrono; + +#[derive(Debug, Deserialize)] +pub struct Clip { + pub slug: String, + pub tracking_id: String, + pub url: String, + pub embed_url: String, + pub embed_html: String, + pub broadcaster: UserData, + pub curator: UserData, + pub vod: Vod, + pub game: String, + pub language: String, + pub title: String, + pub views: i32, + pub duration: f32, + pub created_at: String, + pub thumbnails: Thumbnails, +} + + +#[derive(Debug, Deserialize)] +pub struct Thumbnails { + pub medium: String, + pub small: String, + pub tiny: String, +} + +#[derive(Debug, Deserialize)] +pub struct UserData { + pub id: String, + pub name: String, + pub display_name: String, + pub channel_url: String, + pub logo: String, +} + +#[derive(Debug, Deserialize)] +pub struct Vod { + pub id: String, + pub url: String, +} diff --git a/src/lib.rs b/src/lib.rs index 450ffde..06239b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,126 +6,22 @@ extern crate chrono; #[macro_use] extern crate serde_derive; -pub mod models; +mod helix; +mod kraken; -use futures::future::Future; -use reqwest::header; -use reqwest::r#async::{Chunk, Decoder, Request, Response}; -use reqwest::r#async::Client as ReqwestClient; - -use self::models::{DataContainer, PaginationContainer, User, Video, Clip}; - -const API_DOMAIN: &'static str = "api.twitch.tv"; - -/* When Client owns a ReqwestClient, any futures spawned do not immediately - * terminate but 'hang'. When creating a new client for each request this problem - * does not occur. This would need to be resolved so we can benefit from keep alive - * connections. - * - */ +pub use self::helix::endpoints::Client as HelixClient; +pub use self::kraken::Client as KrakenClient; pub struct Client { - id: String, + pub helix: HelixClient, + pub kraken: KrakenClient, } impl Client { pub fn new(client_id: &str) -> Client { - Client { - id: client_id.to_owned(), - } - } - - fn create_client(&self) -> ReqwestClient { - let mut headers = header::HeaderMap::new(); - let auth_key = &self.id; - let header_value = header::HeaderValue::from_str(auth_key).unwrap(); - headers.insert("Client-ID", header_value); - - let client = ReqwestClient::builder().default_headers(headers).build().unwrap(); - client - } - - pub fn users( - &self, - id: Vec<&str>, - login: Vec<&str>, - ) -> impl Future, Error = reqwest::Error> { - let mut url = - String::from("https://") + &String::from(API_DOMAIN) + &String::from("/helix/users"); - - if id.len() > 0 || login.len() > 0 { - url.push_str("?"); - } - - if id.len() > 0 { - for index in 0..id.len() { - url.push_str("id="); - url.push_str(id[index]); - url.push('&'); - } - } - - if login.len() > 0 { - for index in 0..login.len() { - url.push_str("login="); - url.push_str(login[index]); - url.push('&'); - } + Client { + helix: HelixClient::new(client_id), + kraken: KrakenClient::new(client_id), } - - - let f = self.create_client() - .get(&url) - .send() - .map(|mut res| res.json::>()) - .and_then(|json| json); - - return f; - } - - pub fn videos( - &self, - video_id: Option>, - user_id: Option<&str>, - game_id: Option<&str>, - ) -> impl Future, Error = reqwest::Error> { - let mut url = - String::from("https://") + &String::from(API_DOMAIN) + &String::from("/helix/videos"); - - url.push_str("?"); - if let Some(user_id) = user_id { - url.push_str("user_id="); - url.push_str(user_id); - url.push('&'); - } - - let f = self.create_client() - .get(&url) - .send() - .map(|mut res| { - res.json::>() - }) - .and_then(|json| json); - - return f; - } - - pub fn clip(&self, id: &str) - -> impl Future, Error=reqwest::Error> - { - let url = - String::from("https://") + - API_DOMAIN + "/helix/clips" + "?id=" + id; - - let f = self.create_client() - .get(&url) - .send() - .map(|mut res| { - println!("{:?}", res); - res.json::>() - }) - .and_then(|json| json); - - return f; } } diff --git a/src/models.rs b/src/models.rs deleted file mode 100644 index 2b01e7c..0000000 --- a/src/models.rs +++ /dev/null @@ -1,76 +0,0 @@ -extern crate serde_json; -extern crate chrono; - -use chrono::{Duration, DateTime, Utc}; - - -#[derive(Debug, Deserialize)] -pub struct DataContainer { - pub data: Vec -} - -#[derive(Debug, Deserialize)] -pub struct Cursor { - cursor: String -} - -#[derive(Debug, Deserialize)] -pub struct PaginationContainer { - pub data: Vec, - pub pagination: Option -} - -#[derive(Debug, Deserialize)] -pub struct Video { - pub id: String, - pub user_id: String, - pub user_name: String, - pub title: String, - pub description: String, - //Should be converted to a DateTime - pub created_at: String, - pub published_at: String, - //Should be converted to a URL - pub url: String, - pub thumbnail_url: String, - pub viewable: String, - pub view_count: i32, - pub language: String, - #[serde(rename = "type")] - pub video_type: String, - //Should be converted to a Duration - pub duration: String, -} - -#[derive(Debug, Deserialize)] -pub struct User { - pub id: String, - pub login: String, - pub display_name: String, - #[serde(rename = "type")] - pub user_type: String, - pub broadcaster_type: String, - pub description: String, - pub profile_image_url: String, - pub offline_image_url: String, - pub view_count: u32, - pub email: Option, -} - -#[derive(Debug, Deserialize)] -pub struct Clip { - pub id: String, - pub url: String, - pub embed_url: String, - pub broadcaster_id: String, - pub broadcaster_name: String, - pub creator_id: String, - pub creator_name: String, - pub video_id: String, - pub game_id: String, - pub language: String, - pub title: String, - pub created_at: String, - pub thumbnail_url: String, - pub view_count: i32, -} -- cgit v1.2.3