summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Blajda <blajda@hotmail.com>2018-12-20 23:42:45 +0000
committerDavid Blajda <blajda@hotmail.com>2018-12-20 23:42:45 +0000
commit298806448db4a4e74306ec648bfc0e43a76c6bc3 (patch)
tree1cdd90df0d65a513ad94588dae7621b03a906b3e
parent2bae9a4e8d8b77f8a99df6829547a60f883632a3 (diff)
Split auth and unauth client and created ClientTrait
-rw-r--r--src/bin/main.rs17
-rw-r--r--src/helix/mod.rs394
-rw-r--r--src/helix/namespaces/auth.rs14
-rw-r--r--src/helix/namespaces/clips.rs10
-rw-r--r--src/helix/namespaces/mod.rs17
-rw-r--r--src/helix/namespaces/users.rs14
-rw-r--r--src/helix/namespaces/videos.rs2
-rw-r--r--src/lib.rs22
-rw-r--r--src/namespace.rs0
9 files changed, 324 insertions, 166 deletions
diff --git a/src/bin/main.rs b/src/bin/main.rs
index c5b7ea2..81f07ff 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -6,17 +6,16 @@ extern crate twitch_api;
use futures::future::Future;
use std::env;
-use twitch_api::Client;
use twitch_api::HelixClient;
fn main() {
dotenv::dotenv().unwrap();
let client_id = &env::var("TWITCH_API").unwrap();
- let client = Client::new(client_id);
+ let client = HelixClient::new(client_id);
let authed_client =
- client.helix.clone()
+ client
.authenticate(&env::var("TWITCH_SECRET").unwrap())
.build();
@@ -50,13 +49,21 @@ fn main() {
* to become idle but it will never becomes idle since we keep a reference
* to a reqwest client which maintains a connection pool.
*/
- std::mem::drop(authed_client);
- std::mem::drop(client);
+ //std::mem::drop(authed_client);
tokio::run(
clip.join(clip2)
.and_then(|(c1, c2)| {
println!("{:?} {:?}", c1, c2);
Ok((c1, c2))
+ }).and_then(move |_| {
+ authed_client
+ .clips()
+ .clip(&"EnergeticApatheticTarsierThisIsSparta")
+ .map(|_| ())
+ .map_err(|err| {
+ println!("{:?}", err);
+ ()
+ })
})
.map(|_| ())
.map_err(|_| ())
diff --git a/src/helix/mod.rs b/src/helix/mod.rs
index 3ed4494..c6eb1f5 100644
--- a/src/helix/mod.rs
+++ b/src/helix/mod.rs
@@ -2,14 +2,14 @@ use futures::future::Future;
use std::sync::{Arc, Mutex};
use reqwest::r#async::Client as ReqwestClient;
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
use super::error::Error;
-use std::marker::PhantomData;
use futures::future::Shared;
use futures::Poll;
use serde::de::DeserializeOwned;
use futures::Async;
use futures::try_ready;
+use std::iter::FromIterator;
use crate::error::ConditionError;
@@ -19,19 +19,13 @@ pub use super::types;
pub mod models;
pub mod namespaces;
-pub struct Namespace<T> {
- client: Client,
- _type: PhantomData<T>
-}
+const API_DOMAIN: &'static str = "api.twitch.tv";
-impl<T> Namespace<T> {
- pub fn new(client: &Client) -> Self {
- Namespace {
- client: client.clone(),
- _type: PhantomData,
- }
- }
+#[derive(PartialEq, Eq, Hash, Clone)]
+pub enum RatelimitKey {
+ Default,
}
+type RatelimitMap = HashMap<RatelimitKey, Ratelimit>;
#[derive(PartialEq, Hash, Eq, Clone)]
pub enum Scope {
@@ -47,7 +41,152 @@ pub enum Scope {
#[derive(Clone)]
pub struct Client {
- inner: Arc<ClientRef>,
+ inner: Arc<ClientType>,
+}
+
+enum ClientType {
+ Unauth(UnauthClient),
+ Auth(AuthClient),
+}
+
+/*TODO: Try to remove this boilerplate too*/
+impl ClientTrait for Client {
+
+ fn id<'a>(&'a self) -> &'a str {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.id(),
+ Auth(inner) => inner.id(),
+ }
+ }
+
+ fn domain<'a>(&'a self) -> &'a str {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.domain(),
+ Auth(inner) => inner.domain(),
+ }
+ }
+
+ fn ratelimit<'a>(&self, key: RatelimitKey) -> Option<&'a Ratelimit> {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.ratelimit(key),
+ Auth(inner) => inner.ratelimit(key),
+ }
+ }
+
+ fn authenticated(&self) -> bool {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.authenticated(),
+ Auth(inner) => inner.authenticated(),
+ }
+ }
+
+ fn scopes(&self) -> Vec<Scope> {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.scopes(),
+ Auth(inner) => inner.scopes(),
+ }
+ }
+}
+
+pub struct UnauthClient {
+ id: String,
+ reqwest: ReqwestClient,
+ domain: String,
+ ratelimits: RatelimitMap,
+}
+
+impl Client {
+
+ pub fn authenticate(self, secret: &str) -> AuthClientBuilder {
+ AuthClientBuilder::new(self, secret)
+ }
+
+ pub fn deauthenticate(self) -> Client {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(_inner) => self,
+ Auth(inner) => inner.previous.clone(),
+ }
+ }
+}
+
+
+pub trait ClientTrait {
+
+ fn id<'a>(&'a self) -> &'a str;
+ fn domain<'a>(&'a self) -> &'a str;
+ fn ratelimit<'a>(&self, key: RatelimitKey) -> Option<&'a Ratelimit>;
+
+ fn authenticated(&self) -> bool;
+ fn scopes(&self) -> Vec<Scope>;
+}
+
+impl ClientTrait for UnauthClient {
+ fn id<'a>(&'a self) -> &'a str {
+ &self.id
+ }
+
+ fn domain<'a>(&'a self) -> &'a str {
+ &self.domain
+ }
+
+ fn ratelimit<'a>(&self, key: RatelimitKey) -> Option<&'a Ratelimit> {
+ None
+ }
+
+ fn authenticated(&self) -> bool {
+ false
+ }
+
+ fn scopes(&self) -> Vec<Scope> {
+ Vec::with_capacity(0)
+ }
+}
+
+pub struct AuthClient {
+ secret: String,
+ auth_state: Mutex<AuthStateRef>,
+ auth_barrier: Barrier,
+ previous: Client,
+}
+
+/*TODO I'd be nice to remove this boiler plate */
+impl ClientTrait for AuthClient {
+ fn id<'a>(&'a self) -> &'a str {
+ match self.previous.inner.as_ref() {
+ ClientType::Auth(auth) => auth.id(),
+ ClientType::Unauth(unauth) => unauth.id(),
+ }
+ }
+
+ fn domain<'a>(&'a self) -> &'a str {
+ match self.previous.inner.as_ref() {
+ ClientType::Auth(auth) => auth.domain(),
+ ClientType::Unauth(unauth) => unauth.domain(),
+ }
+ }
+
+ fn ratelimit<'a>(&self, key: RatelimitKey) -> Option<&'a Ratelimit> {
+ match self.previous.inner.as_ref() {
+ ClientType::Auth(auth) => auth.ratelimit(key),
+ ClientType::Unauth(unauth) => unauth.ratelimit(key),
+ }
+ }
+
+ fn authenticated(&self) -> bool {
+ let auth = self.auth_state.lock().expect("Auth Lock is poisoned");
+ auth.state == AuthState::Auth
+ }
+
+ fn scopes(&self) -> Vec<Scope> {
+ let auth = self.auth_state.lock().expect("Auth Lock is poisoned");
+ Vec::with_capacity(0)
+ }
}
#[derive(Clone, PartialEq)]
@@ -56,22 +195,21 @@ enum AuthState {
Auth,
}
-
-struct MutClientRef {
+struct AuthStateRef {
token: Option<String>,
scopes: Vec<Scope>,
- previous: Option<Client>,
- auth_state: AuthState,
- auth_future: Option<Shared<Box<Future<Item=(), Error=ConditionError> + Send>>>
+ state: AuthState,
}
struct ClientRef {
id: String,
secret: Option<String>,
- client: ReqwestClient,
+ reqwest: ReqwestClient,
+ domain: &'static str,
+ ratelimits: RatelimitMap,
+ auth_state: Mutex<AuthStateRef>,
auth_barrier: Barrier,
- ratelimit_default: Ratelimit,
- inner: Mutex<MutClientRef>,
+ previous: Option<Client>,
}
impl Client {
@@ -80,50 +218,41 @@ impl Client {
Client::new_with_client(id, client)
}
- pub fn default_ratelimit(&self) -> Ratelimit {
- self.inner.ratelimit_default.clone()
+ fn default_ratelimits() -> RatelimitMap {
+ let mut limits = RatelimitMap::new();
+ limits.insert(RatelimitKey::Default, Ratelimit::new(30, "Ratelimit-Limit", "Ratelimit-Remaining", "Ratelimit-Reset"));
+
+ limits
}
- pub fn new_with_client(id: &str, client: ReqwestClient) -> Client {
+ pub fn new_with_client(id: &str, reqwest: ReqwestClient) -> Client {
Client {
- inner: Arc::new(ClientRef {
- id: id.to_owned(),
- client: client,
- secret: None,
- auth_barrier: Barrier::new(),
- ratelimit_default: Ratelimit::new(30, "Ratelimit-Limit", "Ratelimit-Remaining", "Ratelimit-Reset"),
- inner: Mutex::new(
- MutClientRef {
- token: None,
- scopes: Vec::new(),
- previous: None,
- auth_state: AuthState::Auth,
- auth_future: None,
- })
- })
+ inner: Arc::new(
+ ClientType::Unauth(UnauthClient {
+ id: id.to_owned(),
+ reqwest: reqwest,
+ domain: API_DOMAIN.to_owned(),
+ ratelimits: Self::default_ratelimits(),
+ }))
}
}
- pub fn id(&self) -> &str {
- &self.inner.id
- }
-
- pub fn client(&self) -> &ReqwestClient {
- &self.inner.client
- }
-
- pub fn authenticated(&self) -> bool {
- let mut_data = self.inner.inner.lock().unwrap();
- mut_data.token.is_some()
+ fn secret<'a>(&'a self) -> Option<&'a str> {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(_) => None,
+ Auth(inner) => Some(&inner.secret),
+ }
}
- /*
- pub fn scopes(&self) -> Vec<Scope> {
- let mut_data = self.inner.inner.lock().unwrap();
- (&mut_data.scopes).into_iter().to_owned().collect()
+ fn reqwest(&self) -> ReqwestClient {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.reqwest.clone(),
+ Auth(inner) => inner.previous.reqwest(),
+ }
}
- */
/* The 'bottom' client must always be a client that is not authorized.
* This which allows for calls to Auth endpoints using the same control flow
@@ -133,38 +262,28 @@ impl Client {
* to authenticate stack a authed client on top
*/
fn get_bottom_client(&self) -> Client {
- let mut_client = self.inner.inner.lock().unwrap();
- match &mut_client.previous {
- Some(client) => {
- client.get_bottom_client()
- },
- None => {
- self.clone()
- }
- }
- }
-
- pub fn authenticate(self, secret: &str) -> AuthClientBuilder {
- AuthClientBuilder::new(self, secret)
- }
-
- pub fn deauthenticate(self) -> Client {
- let mut_data = self.inner.inner.lock().unwrap();
- match &mut_data.previous {
- Some(old_client) => old_client.clone(),
- None => self.clone()
+ match self.inner.as_ref() {
+ ClientType::Auth(inner) => inner.previous.get_bottom_client(),
+ ClientType::Unauth(_) => self.clone(),
}
}
- pub fn apply_standard_headers(&self, request: RequestBuilder)
+ fn apply_standard_headers(&self, request: RequestBuilder)
-> RequestBuilder
{
- let mut_client = self.inner.inner.lock().unwrap();
+ let token = match self.inner.as_ref() {
+ ClientType::Auth(inner) => {
+ let auth = inner.auth_state.lock().expect("Authlock is poisoned");
+ auth.token.as_ref().map(|s| s.to_owned())
+ }
+ ClientType::Unauth(_) => None,
+ };
+
let client_header = header::HeaderValue::from_str(self.id()).unwrap();
let request =
- if let Some(token) = &mut_client.token {
- let value = "Bearer ".to_owned() + token;
+ if let Some(token) = token {
+ let value = "Bearer ".to_owned() + &token;
let token_header = header::HeaderValue::from_str(&value).unwrap();
request.header("Authorization", token_header)
} else { request };
@@ -202,22 +321,18 @@ impl AuthClientBuilder {
let auth_state = if self.token.is_some() { AuthState::Auth } else { AuthState::Unauth };
let old_client = self.client;
Client {
- inner: Arc::new(ClientRef {
- id: old_client.inner.id.clone(),
- client: old_client.inner.client.clone(),
- secret: Some(self.secret),
+ inner: Arc::new(ClientType::Auth(
+ AuthClient {
+ secret: self.secret,
auth_barrier: Barrier::new(),
- ratelimit_default: old_client.default_ratelimit(),
- inner: Mutex::new (
- MutClientRef {
+ auth_state: Mutex::new (
+ AuthStateRef {
token: self.token,
scopes: Vec::new(),
- previous: Some(old_client),
- auth_state: auth_state,
- auth_future: None,
- })
-
- })
+ state: auth_state,
+ }),
+ previous: old_client,
+ }))
}
}
@@ -252,13 +367,14 @@ struct RequestRef {
url: String,
params: BTreeMap<String, String>,
client: Client,
- ratelimit: Option<Ratelimit>,
+ ratelimit: Option<RatelimitKey>,
method: Method,
}
enum RequestState<T> {
Uninitalized,
WaitAuth(WaiterState<AuthWaiter>),
+ SetupRatelimit,
WaitLimit(WaiterState<RatelimitWaiter>),
WaitRequest,
PollParse(Box<dyn Future<Item=T, Error=reqwest::Error> + Send>),
@@ -272,16 +388,21 @@ pub struct ApiRequest<T> {
impl<T: DeserializeOwned + 'static + Send> ApiRequest<T> {
pub fn new(url: String,
- params: BTreeMap<String, String>,
+ params: BTreeMap<&str, &str>,
client: Client,
method: Method,
- ratelimit: Option<Ratelimit>,
+ ratelimit: Option<RatelimitKey>,
) -> ApiRequest<T>
{
+ let mut owned_params = BTreeMap::new();
+ for (key, value) in params {
+ owned_params.insert(key.to_owned(), value.to_owned());
+ }
+
ApiRequest {
inner: Arc::new( RequestRef {
url: url,
- params: params,
+ params: owned_params,
client: client,
method: method,
ratelimit: ratelimit,
@@ -393,14 +514,21 @@ impl Waiter for AuthWaiter {
type Error = ConditionError;
fn blocked(&self) -> bool {
- let mut_client = self.waiter.inner.inner.lock().unwrap();
- mut_client.auth_state == AuthState::Unauth
+ match self.waiter.inner.as_ref() {
+ ClientType::Unauth(_) => false,
+ ClientType::Auth(inner) => {
+ let auth = inner.auth_state.lock()
+ .expect("unable to lock auth state");
+ auth.state == AuthState::Unauth
+ }
+ }
}
fn condition(&self) ->
Shared<Box<Future<Item=(), Error=ConditionError> + Send>> {
+ /* If a secret is not provided than just immediately return */
+ let secret = self.waiter.secret().unwrap();
let bottom_client = self.waiter.get_bottom_client();
- let secret = self.waiter.inner.secret.as_ref().unwrap();
let client = self.waiter.clone();
let auth_future =
@@ -409,9 +537,11 @@ impl Waiter for AuthWaiter {
.client_credentials(secret)
.map(move |credentials| {
println!("{:?}", credentials);
- let mut mut_client = client.inner.inner.lock().unwrap();
- mut_client.auth_state = AuthState::Auth;
- mut_client.token = Some(credentials.access_token.clone());
+ if let ClientType::Auth(inner) = client.inner.as_ref() {
+ let mut auth = inner.auth_state.lock().unwrap();
+ auth.state = AuthState::Auth;
+ auth.token = Some(credentials.access_token.clone());
+ }
()
})
.map_err(|_| ConditionError{});
@@ -454,23 +584,35 @@ impl<T: DeserializeOwned + 'static + Send> Future for ApiRequest<T> {
loop {
match &mut self.state {
RequestState::Uninitalized => {
- let mut_client = self.inner.client.inner.inner.lock().unwrap();
-
- let waiter = AuthWaiter {
- waiter: self.inner.client.clone(),
- };
+ match self.inner.client.inner.as_ref() {
+ ClientType::Auth(inner) => {
+ let waiter = AuthWaiter {
+ waiter: self.inner.client.clone(),
+ };
- let f = WaiterState::new(waiter,
- &self.inner.client.inner.auth_barrier);
- self.state = RequestState::WaitAuth(f);
+ let f = WaiterState::new(waiter,
+ &inner.auth_barrier);
+ self.state = RequestState::WaitAuth(f);
+ },
+ ClientType::Unauth(_) => {
+ self.state = RequestState::SetupRatelimit;
+ }
+ }
},
RequestState::WaitAuth(auth) => {
let _waiter = try_ready!(auth.poll());
- match self.inner.ratelimit {
- Some(ref limit) => {
- let barrier = limit.barrier.clone();
+ self.state = RequestState::SetupRatelimit;
+ },
+ RequestState::SetupRatelimit => {
+ let limits =
+ self.inner.ratelimit.as_ref().and_then(|key| {
+ self.inner.client.ratelimit(key.clone())
+ });
+ match limits {
+ Some(ratelimit) => {
+ let barrier = ratelimit.barrier.clone();
let waiter = RatelimitWaiter {
- limit: limit.clone(),
+ limit: ratelimit.clone(),
};
let f = WaiterState::new(waiter,
&barrier);
@@ -487,9 +629,14 @@ impl<T: DeserializeOwned + 'static + Send> Future for ApiRequest<T> {
},
RequestState::WaitRequest => {
let client = &self.inner.client;
- let reqwest = client.client();
+ let reqwest = client.reqwest();
+
+ let limits =
+ self.inner.ratelimit.as_ref().and_then(|key| {
+ client.ratelimit(key.clone())
+ });
- if let Some(limits) = &self.inner.ratelimit {
+ if let Some(limits) = limits {
let mut mut_limits = limits.inner.lock().unwrap();
mut_limits.inflight = mut_limits.inflight + 1;
}
@@ -497,24 +644,23 @@ impl<T: DeserializeOwned + 'static + Send> Future for ApiRequest<T> {
let builder = reqwest.request(self.inner.method.clone(), &self.inner.url);
let builder = client.apply_standard_headers(builder);
let r = builder.query(&self.inner.params);
- /*TODO add 1 to inflight*/
- let ratelimit_err = self.inner.ratelimit.clone();
- let ratelimit_ok = self.inner.ratelimit.clone();
+ let limits_err = limits.clone();
+ let limits_ok = limits.clone();
let f = r.send()
- .map_err(|err| {
+ .map_err(move |err| {
- if let Some(limits) = ratelimit_err {
+ if let Some(limits) = limits_err {
let mut mut_limits = limits.inner.lock().unwrap();
mut_limits.inflight = mut_limits.inflight - 1;
}
err
})
- .map(|mut response| {
+ .map(move |mut response| {
println!("{:?}", response);
- if let Some(limits) = ratelimit_ok {
+ if let Some(limits) = limits_ok {
let mut mut_limits = limits.inner.lock().unwrap();
mut_limits.inflight = mut_limits.inflight - 1;
diff --git a/src/helix/namespaces/auth.rs b/src/helix/namespaces/auth.rs
index 5efc0fe..478c1af 100644
--- a/src/helix/namespaces/auth.rs
+++ b/src/helix/namespaces/auth.rs
@@ -1,9 +1,9 @@
-use futures::future::Future;
use std::collections::BTreeMap;
use super::super::models::Credentials;
use super::super::Client;
const ID_DOMAIN: &'static str = "id.twitch.tv";
-use super::super::Namespace;
+use super::Namespace;
+use super::super::ClientTrait;
pub struct Auth {}
type AuthNamespace = Namespace<Auth>;
@@ -34,10 +34,10 @@ pub fn client_credentials(client: Client, secret: &str)
ID_DOMAIN + "/oauth2/token";
let mut params = BTreeMap::new();
- params.insert("client_id".to_owned(), client.id().to_owned());
- params.insert("client_secret".to_owned(), secret.to_owned());
- params.insert("grant_type".to_owned(), "client_credentials".to_owned());
- params.insert("scope".to_owned(), "".to_owned());
+ params.insert("client_id", client.id());
+ params.insert("client_secret", secret);
+ params.insert("grant_type", "client_credentials");
+ params.insert("scope", "");
- ApiRequest::new(url, params, client, Method::POST, None)
+ ApiRequest::new(url, params, client.clone(), Method::POST, None)
}
diff --git a/src/helix/namespaces/clips.rs b/src/helix/namespaces/clips.rs
index 083e5c4..19293cc 100644
--- a/src/helix/namespaces/clips.rs
+++ b/src/helix/namespaces/clips.rs
@@ -1,9 +1,10 @@
-use futures::future::Future;
use std::collections::BTreeMap;
use super::super::models::{DataContainer, PaginationContainer, User, Video, Clip};
use super::super::Client;
+use super::super::ClientTrait;
+use super::super::RatelimitKey;
const API_DOMAIN: &'static str = "api.twitch.tv";
-use super::super::Namespace;
+use super::Namespace;
pub struct Clips {}
type ClipsNamespace = Namespace<Clips>;
@@ -30,10 +31,9 @@ pub fn clip(client: Client, id: &str)
{
let url =
String::from("https://") +
- API_DOMAIN + "/helix/clips" + "?id=" + id;
+ client.domain() + "/helix/clips" + "?id=" + id;
let params = BTreeMap::new();
- let limit = client.default_ratelimit();
- ApiRequest::new(url, params, client, Method::GET, Some(limit))
+ ApiRequest::new(url, params, client, Method::GET, Some(RatelimitKey::Default))
}
diff --git a/src/helix/namespaces/mod.rs b/src/helix/namespaces/mod.rs
index d1c44bd..1c0d08e 100644
--- a/src/helix/namespaces/mod.rs
+++ b/src/helix/namespaces/mod.rs
@@ -1,4 +1,21 @@
+use std::marker::PhantomData;
+use super::Client;
+
pub mod clips;
pub mod users;
pub mod videos;
pub mod auth;
+
+pub struct Namespace<T> {
+ client: Client,
+ _type: PhantomData<T>
+}
+
+impl<T> Namespace<T> {
+ pub fn new(client: &Client) -> Self {
+ Namespace {
+ client: client.clone(),
+ _type: PhantomData,
+ }
+ }
+}
diff --git a/src/helix/namespaces/users.rs b/src/helix/namespaces/users.rs
index c809b95..3e4f1dd 100644
--- a/src/helix/namespaces/users.rs
+++ b/src/helix/namespaces/users.rs
@@ -3,25 +3,28 @@ use super::super::models::{DataContainer, PaginationContainer, User, Video, Clip
use super::super::Client;
use std::collections::BTreeMap;
const API_DOMAIN: &'static str = "api.twitch.tv";
-use super::super::Namespace;
+use super::Namespace;
pub struct Users {}
type UsersNamespace = Namespace<Users>;
impl UsersNamespace {
+ /*
pub fn users(self, id: Vec<&str>, login: Vec<&str>) -> impl Future<Item=DataContainer<User>, Error=reqwest::Error> {
- use self::users;
- users(self.client, id, login)
+ //use self::users;
+ //users(self.client, id, login)
}
+ */
}
-
+/*
impl Client {
pub fn users(&self) -> UsersNamespace {
UsersNamespace::new(self)
}
}
-
+*/
+/*
pub fn users(
client: Client,
id: Vec<&str>,
@@ -50,3 +53,4 @@ pub fn users(
})
.and_then(|json| json)
}
+*/
diff --git a/src/helix/namespaces/videos.rs b/src/helix/namespaces/videos.rs
index ad5ca28..7b8839b 100644
--- a/src/helix/namespaces/videos.rs
+++ b/src/helix/namespaces/videos.rs
@@ -3,7 +3,7 @@ use super::super::models::{DataContainer, PaginationContainer, User, Video, Clip
use super::super::Client;
use std::collections::BTreeMap;
const API_DOMAIN: &'static str = "api.twitch.tv";
-use super::super::Namespace;
+use super::Namespace;
pub struct Videos {}
type VideosNamespace = Namespace<Videos>;
diff --git a/src/lib.rs b/src/lib.rs
index 70f03dd..e18f243 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,35 +1,19 @@
#![recursion_limit="128"]
#![feature(option_replace)]
-#![feature(associated_type_defaults)]
extern crate futures;
extern crate reqwest;
extern crate serde;
extern crate chrono;
#[macro_use] extern crate serde_derive;
+use reqwest::r#async::Client as ReqwestClient;
+
pub mod helix;
pub mod kraken;
pub mod types;
pub mod error;
pub mod sync;
-
+pub mod namespace;
pub use self::helix::Client as HelixClient;
pub use self::kraken::Client as KrakenClient;
-
-use reqwest::r#async::Client as ReqwestClient;
-
-pub struct Client {
- pub helix: HelixClient,
- pub kraken: KrakenClient,
-}
-
-impl Client {
- pub fn new(client_id: &str) -> Client {
- let client = ReqwestClient::new();
- Client {
- helix: HelixClient::new_with_client(client_id, client.clone()),
- kraken: KrakenClient::new_with_client(client_id, client.clone()),
- }
- }
-}
diff --git a/src/namespace.rs b/src/namespace.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/namespace.rs