summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Blajda <blajda@hotmail.com>2018-12-27 22:03:23 +0000
committerDavid Blajda <blajda@hotmail.com>2018-12-27 22:03:23 +0000
commit678e3d3f28cb8594204dc5e2b7597ae66a4582c7 (patch)
tree55b563cfdc09dab8f18c1f4d688ebf0c2187985c
parentcb1b144e48ee357a76f551433d4886f092d259c8 (diff)
Use Id types for endpoints and implement kraken headers
-rw-r--r--src/bin/main.rs42
-rw-r--r--src/client.rs49
-rw-r--r--src/helix/models.rs7
-rw-r--r--src/helix/namespaces/auth.rs31
-rw-r--r--src/helix/namespaces/clips.rs17
-rw-r--r--src/helix/namespaces/mod.rs7
-rw-r--r--src/helix/namespaces/users.rs55
-rw-r--r--src/helix/namespaces/videos.rs28
-rw-r--r--src/kraken/endpoints.rs20
-rw-r--r--src/kraken/mod.rs46
-rw-r--r--src/kraken/models.rs5
-rw-r--r--src/kraken/namespaces/clips.rs33
-rw-r--r--src/kraken/namespaces/mod.rs19
-rw-r--r--src/lib.rs4
-rw-r--r--src/namespace/auth.rs3
-rw-r--r--src/types.rs10
16 files changed, 199 insertions, 177 deletions
diff --git a/src/bin/main.rs b/src/bin/main.rs
index ba1482a..15b7753 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -8,26 +8,32 @@ use futures::future::Future;
use futures::Stream;
use std::env;
use twitch_api::HelixClient;
+use twitch_api::KrakenClient;
+use std::str::FromStr;
+
+use twitch_api::types::UserId;
+use twitch_api::types::ClipId;
+
fn main() {
dotenv::dotenv().unwrap();
let client_id = &env::var("TWITCH_API").unwrap();
- let client = HelixClient::new(client_id);
-
+ let helix_client = HelixClient::new(client_id);
+ let kraken_client = KrakenClient::new(client_id);
- let authed_client = client;
/*
.authenticate(&env::var("TWITCH_SECRET").unwrap())
.build();
*/
- let clip = authed_client
+ let clip = helix_client
.clips()
- .clip(&"EnergeticApatheticTarsierThisIsSparta")
+ .clip(&ClipId::new("EnergeticApatheticTarsierThisIsSparta"))
.map_err(|err| {
println!("{:?}", err);
()
});
+ /*
let clip2 = authed_client
.clips()
@@ -36,27 +42,31 @@ fn main() {
println!("{:?}", err);
()
});
+ */
+
+ //use twitch_api::types::VideoId;
+ /*
let videos = authed_client
.videos()
- .by_user("67955580")
- .take(10)
+ .by_user(&UserId::from_str("19571641").unwrap())
+ .take(1)
.for_each(|collection| {
println!("{:?}", collection);
Ok(())
})
.map(|_| ())
.map_err(|err| {println!("{:?}", err); ()});
+ */
- /*
- let clip2 = client.kraken
+ let clip2 = kraken_client
+ .clips()
.clip(&"EnergeticApatheticTarsierThisIsSparta")
.map_err(|err| {
println!("{:?}", err);
()
});
- */
/* Prevents tokio from **hanging**
* since tokio::run blocks the current thread and waits for the entire runtime
@@ -65,15 +75,16 @@ fn main() {
*/
//std::mem::drop(authed_client);
tokio::run(
- /*
clip.join(clip2)
.and_then(|(c1, c2)| {
- println!("{:?} {:?}", c1, c2);
+ println!("{:?}", c1);
+ println!("__");
+ println!("{:?}", c2);
Ok((c1, c2))
}).and_then(move |_| {
- authed_client
+ helix_client
.clips()
- .clip(&"EnergeticApatheticTarsierThisIsSparta")
+ .clip(&ClipId::new("EnergeticApatheticTarsierThisIsSparta"))
.map(|_| ())
.map_err(|err| {
println!("{:?}", err);
@@ -82,7 +93,6 @@ fn main() {
})
.map(|_| ())
.map_err(|_| ())
- */
- videos
+ /*videos*/
);
}
diff --git a/src/client.rs b/src/client.rs
index fd3af32..8f93e1e 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -21,6 +21,8 @@ pub enum RatelimitKey {
type RatelimitMap = HashMap<RatelimitKey, Ratelimit>;
const API_DOMAIN: &'static str = "api.twitch.tv";
+const AUTH_DOMAIN: &'static str = "id.twitch.tv";
+const KRAKEN_ACCEPT: &'static str = "application/vnd.twitchtv.v5+json";
pub trait PaginationTrait {
fn cursor<'a>(&'a self) -> Option<&'a str>;
@@ -68,6 +70,7 @@ pub struct UnauthClient {
id: String,
reqwest: ReqwestClient,
domain: String,
+ auth_domain: String,
ratelimits: RatelimitMap,
version: Version,
}
@@ -83,6 +86,7 @@ pub trait ClientTrait {
fn id<'a>(&'a self) -> &'a str;
fn domain<'a>(&'a self) -> &'a str;
+ fn auth_domain<'a>(&'a self) -> &'a str;
fn ratelimit<'a>(&'a self, key: RatelimitKey) -> Option<&'a Ratelimit>;
fn authenticated(&self) -> bool;
@@ -98,6 +102,10 @@ impl ClientTrait for UnauthClient {
&self.domain
}
+ fn auth_domain<'a>(&'a self) -> &'a str {
+ &self.auth_domain
+ }
+
fn ratelimit<'a>(&'a self, key: RatelimitKey) -> Option<&'a Ratelimit> {
self.ratelimits.get(&key)
}
@@ -129,6 +137,14 @@ impl ClientTrait for Client {
}
}
+ fn auth_domain<'a>(&'a self) -> &'a str {
+ use self::ClientType::*;
+ match self.inner.as_ref() {
+ Unauth(inner) => inner.auth_domain(),
+ Auth(inner) => inner.auth_domain(),
+ }
+ }
+
fn ratelimit<'a>(&'a self, key: RatelimitKey) -> Option<&'a Ratelimit> {
use self::ClientType::*;
match self.inner.as_ref() {
@@ -170,6 +186,13 @@ impl ClientTrait for AuthClient {
}
}
+ fn auth_domain<'a>(&'a self) -> &'a str {
+ match self.previous.inner.as_ref() {
+ ClientType::Auth(auth) => auth.auth_domain(),
+ ClientType::Unauth(unauth) => unauth.auth_domain(),
+ }
+ }
+
fn ratelimit<'a>(&'a self, key: RatelimitKey) -> Option<&'a Ratelimit> {
match self.previous.inner.as_ref() {
ClientType::Auth(auth) => auth.ratelimit(key),
@@ -221,6 +244,7 @@ impl Client {
id: id.to_owned(),
reqwest: reqwest,
domain: API_DOMAIN.to_owned(),
+ auth_domain: AUTH_DOMAIN.to_owned(),
ratelimits: Self::default_ratelimits(),
version: version,
}))
@@ -268,15 +292,15 @@ impl Client {
fn apply_standard_headers(&self, request: RequestBuilder)
-> RequestBuilder
{
+ 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,
+ };
match self.version() {
Version::Helix => {
- 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();
@@ -290,6 +314,17 @@ impl Client {
request.header("Client-ID", client_header)
},
Version::Kraken => {
+ let client_header = header::HeaderValue::from_str(self.id()).unwrap();
+ let accept_header = header::HeaderValue::from_str(KRAKEN_ACCEPT).unwrap();
+
+ let request = request.header("Client-ID", client_header);
+ let request = request.header("Accept", accept_header);
+ let request = if let Some(token) = token {
+ let value = "OAuth ".to_owned() + &token;
+ let token_header = header::HeaderValue::from_str(&value).unwrap();
+ request.header("Authorization", token_header)
+ } else {request};
+
request
}
}
diff --git a/src/helix/models.rs b/src/helix/models.rs
index 47a1288..4c1566c 100644
--- a/src/helix/models.rs
+++ b/src/helix/models.rs
@@ -56,8 +56,11 @@ pub struct Video {
pub published_at: DateTime<Utc>,
#[serde(with = "url_serde")]
pub url: Url,
- #[serde(with = "url_serde")]
- pub thumbnail_url: Url,
+ /*FIXME: Serde will attempt to parse an empty string.
+ * In this case this should be None when thumbnail_url is an empty string
+ */
+ //#[serde(with = "url_serde")]
+ pub thumbnail_url: String, //Option<Url>,
pub viewable: String,
pub view_count: i32,
pub language: String,
diff --git a/src/helix/namespaces/auth.rs b/src/helix/namespaces/auth.rs
index 1ad5c57..1900fbf 100644
--- a/src/helix/namespaces/auth.rs
+++ b/src/helix/namespaces/auth.rs
@@ -1,10 +1,6 @@
-use std::collections::BTreeMap;
-use crate::helix::models::Credentials;
-use super::super::Client;
-const ID_DOMAIN: &'static str = "id.twitch.tv";
-use super::Namespace;
-use crate::client::{ClientTrait, ApiRequest};
-use reqwest::Method;
+use super::*;
+use crate::models::Credentials;
+use crate::namespace::auth;
pub struct Auth {}
type AuthNamespace = Namespace<Auth>;
@@ -12,8 +8,7 @@ type AuthNamespace = Namespace<Auth>;
impl AuthNamespace {
pub fn client_credentials(self, secret: &str)
-> ApiRequest<Credentials> {
- use self::client_credentials;
- client_credentials(self.client, secret)
+ auth::client_credentials(self.client.inner, secret)
}
}
@@ -22,21 +17,3 @@ impl Client {
AuthNamespace::new(self)
}
}
-
-//TODO: Implement scopes
-pub fn client_credentials(client: Client, secret: &str)
- -> ApiRequest<Credentials> {
-
- let client = client.inner;
- let url =
- String::from("https://") +
- ID_DOMAIN + "/oauth2/token";
-
- let mut params = BTreeMap::new();
- 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.clone(), Method::POST, None)
-}
diff --git a/src/helix/namespaces/clips.rs b/src/helix/namespaces/clips.rs
index 28b66f7..1de2e33 100644
--- a/src/helix/namespaces/clips.rs
+++ b/src/helix/namespaces/clips.rs
@@ -1,36 +1,31 @@
-use std::collections::BTreeMap;
-use super::super::models::{DataContainer, Clip};
-use super::super::Client;
-use super::Namespace;
-
-use crate::client::{RatelimitKey, ClientTrait, ApiRequest};
+use super::*;
+use super::models::{DataContainer, Clip};
+use crate::types::ClipId;
pub struct Clips {}
type ClipsNamespace = Namespace<Clips>;
impl ClipsNamespace {
- pub fn clip(self, id: &str) -> ApiRequest<DataContainer<Clip>> {
+ pub fn clip(self, id: &ClipId) -> ApiRequest<DataContainer<Clip>> {
use self::clip;
clip(self.client, id)
}
}
impl Client {
-
pub fn clips(&self) -> ClipsNamespace {
ClipsNamespace::new(self)
}
}
-use reqwest::Method;
-pub fn clip(client: Client, id: &str)
+pub fn clip(client: Client, id: &ClipId)
-> ApiRequest<DataContainer<Clip>>
{
let client = client.inner;
let url =
String::from("https://") +
- client.domain() + "/helix/clips" + "?id=" + id;
+ client.domain() + "/helix/clips" + "?id=" + id.as_ref();
let params = BTreeMap::new();
diff --git a/src/helix/namespaces/mod.rs b/src/helix/namespaces/mod.rs
index 1c0d08e..8adc1e3 100644
--- a/src/helix/namespaces/mod.rs
+++ b/src/helix/namespaces/mod.rs
@@ -1,5 +1,10 @@
use std::marker::PhantomData;
-use super::Client;
+
+pub use super::Client;
+pub use crate::client::{RatelimitKey, ClientTrait, ApiRequest, IterableApiRequest};
+pub use std::collections::BTreeMap;
+pub use reqwest::Method;
+pub use super::models;
pub mod clips;
pub mod users;
diff --git a/src/helix/namespaces/users.rs b/src/helix/namespaces/users.rs
index 3e4f1dd..20f2914 100644
--- a/src/helix/namespaces/users.rs
+++ b/src/helix/namespaces/users.rs
@@ -1,56 +1,45 @@
-use futures::future::Future;
-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::Namespace;
+use super::*;
+use super::models::{DataContainer, User};
+use crate::types::UserId;
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)
+ pub fn users(self, ids: Vec<&UserId>, logins: Vec<&str>)
+ -> ApiRequest<DataContainer<User>> {
+ use self::users;
+ users(self.client, ids, logins)
}
- */
}
-/*
-impl Client {
+impl Client {
pub fn users(&self) -> UsersNamespace {
UsersNamespace::new(self)
}
}
-*/
-/*
+
pub fn users(
client: Client,
- id: Vec<&str>,
- login: Vec<&str>,
- ) -> impl Future<Item = DataContainer<User>, Error = reqwest::Error> {
+ ids: Vec<&UserId>,
+ logins: Vec<&str>,
+ ) -> ApiRequest<DataContainer<User>> {
+ let client = client.inner;
let url =
- String::from("https://") + &String::from(API_DOMAIN) + &String::from("/helix/users");
+ String::from("https://") + client.domain() + &String::from("/helix/users");
let mut params = BTreeMap::new();
- for i in id {
- params.insert("id", i);
+ for id in ids {
+ params.insert("id", id.as_ref());
}
- for log in login {
- params.insert("login", log);
+ for login in logins {
+ params.insert("login", login);
}
- let request = client.client().get(&url);
- let request = client.apply_standard_headers(request);
- let request = request.query(&params);
+ ApiRequest::new(url, params, client, Method::GET, Some(RatelimitKey::Default))
+}
- request
- .send()
- .map(|mut res| {
- res.json::<DataContainer<User>>()
- })
- .and_then(|json| json)
+pub fn authed_as(client: Client) -> ApiRequest<DataContainer<User>> {
+ users(client, Vec::with_capacity(0), Vec::with_capacity(0))
}
-*/
diff --git a/src/helix/namespaces/videos.rs b/src/helix/namespaces/videos.rs
index a8021f3..75b702e 100644
--- a/src/helix/namespaces/videos.rs
+++ b/src/helix/namespaces/videos.rs
@@ -1,29 +1,25 @@
-use super::super::models::{PaginationContainer, Video};
-use super::super::Client;
-use super::Namespace;
-
-use crate::client::{ClientTrait, RatelimitKey, IterableApiRequest};
-use std::collections::BTreeMap;
-use reqwest::Method;
+use super::*;
+use super::models::{PaginationContainer, Video};
+use crate::types::{UserId, GameId, VideoId};
pub struct Videos {}
type VideosNamespace = Namespace<Videos>;
impl VideosNamespace {
- pub fn by_id(self, ids: Vec<&str>)
+ pub fn by_id(self, ids: Vec<&VideoId>)
-> IterableApiRequest<PaginationContainer<Video>> {
use self::by_id;
by_id(self.client, ids)
}
- pub fn by_user(self, user_id: &str)
+ pub fn by_user(self, user_id: &UserId)
-> IterableApiRequest<PaginationContainer<Video>> {
use self::by_user;
by_user(self.client, user_id)
}
- pub fn for_game(self, game_id: &str)
+ pub fn for_game(self, game_id: &GameId)
-> IterableApiRequest<PaginationContainer<Video>> {
use self::for_game;
for_game(self.client, game_id)
@@ -37,7 +33,7 @@ impl Client {
}
}
-pub fn by_id(client: Client, ids: Vec<&str>)
+pub fn by_id(client: Client, ids: Vec<&VideoId>)
-> IterableApiRequest<PaginationContainer<Video>> {
let client = client.inner;
let url =
@@ -45,34 +41,34 @@ pub fn by_id(client: Client, ids: Vec<&str>)
let mut params = BTreeMap::new();
for id in ids {
- params.insert("id", id);
+ params.insert("id", id.as_ref());
}
IterableApiRequest::new(url, params, client,
Method::GET, Some(RatelimitKey::Default))
}
-pub fn by_user(client: Client, user_id: &str)
+pub fn by_user(client: Client, user_id: &UserId)
-> IterableApiRequest<PaginationContainer<Video>> {
let client = client.inner;
let url =
String::from("https://") + client.domain() + &String::from("/helix/videos");
let mut params = BTreeMap::new();
- params.insert("user_id", user_id);
+ params.insert("user_id", user_id.as_ref());
IterableApiRequest::new(url, params, client,
Method::GET, Some(RatelimitKey::Default))
}
-pub fn for_game(client: Client, game_id: &str)
+pub fn for_game(client: Client, game_id: &GameId)
-> IterableApiRequest<PaginationContainer<Video>> {
let client = client.inner;
let url =
String::from("https://") + client.domain() + &String::from("/helix/videos");
let mut params = BTreeMap::new();
- params.insert("game_id", game_id);
+ params.insert("game_id", game_id.as_ref());
IterableApiRequest::new(url, params, client,
Method::GET, Some(RatelimitKey::Default))
diff --git a/src/kraken/endpoints.rs b/src/kraken/endpoints.rs
index 7ae273c..e69de29 100644
--- a/src/kraken/endpoints.rs
+++ b/src/kraken/endpoints.rs
@@ -1,20 +0,0 @@
-use futures::Future;
-use super::models::Clip;
-use super::Client;
-
-use super::API_DOMAIN;
-
-impl Client {
- pub fn clip(&self, id: &str)
- -> impl Future<Item=Clip, Error=reqwest::Error>
- {
- let url = String::from("https://") + API_DOMAIN + "/kraken/clips/" + id;
- let request = self.inner.client.get(&url);
- let request = self.apply_standard_headers(request);
-
- request
- .send()
- .map(|mut res| res.json::<Clip>())
- .and_then(|json| json)
- }
-}
diff --git a/src/kraken/mod.rs b/src/kraken/mod.rs
index 59d00c0..0201295 100644
--- a/src/kraken/mod.rs
+++ b/src/kraken/mod.rs
@@ -1,53 +1,19 @@
-use reqwest::header;
-use std::sync::Arc;
-use reqwest::r#async::RequestBuilder;
-use reqwest::r#async::Client as ReqwestClient;
+use crate::client::Client as GenericClient;
+use crate::client::Version;
pub use super::types;
-mod endpoints;
-mod models;
-
-
-const ACCEPT: &str = "application/vnd.twitchtv.v5+json";
-pub const API_DOMAIN: &str = "api.twitch.tv";
+mod namespaces;
+pub mod models;
#[derive(Clone)]
pub struct Client {
- inner: Arc<ClientRef>,
-}
-
-struct ClientRef {
- id: String,
- client: ReqwestClient
+ inner: GenericClient
}
impl Client {
pub fn new(id: &str) -> Client {
Client {
- inner: Arc::new(ClientRef {
- id: id.to_owned(),
- client: ReqwestClient::new(),
- })
+ inner: GenericClient::new(id, Version::Kraken)
}
}
-
- pub fn new_with_client(id: &str, client: ReqwestClient) -> Client {
- Client {
- inner: Arc::new(ClientRef {
- id: id.to_owned(),
- client: client,
- })
- }
- }
-
- fn apply_standard_headers(&self, request: RequestBuilder)
- -> RequestBuilder
- {
- let client_header = header::HeaderValue::from_str(&self.inner.id).unwrap();
- let accept_header = header::HeaderValue::from_str(ACCEPT).unwrap();
-
- request
- .header("Accept", accept_header)
- .header("Client-ID", client_header)
- }
}
diff --git a/src/kraken/models.rs b/src/kraken/models.rs
index 4863641..8b5b6d6 100644
--- a/src/kraken/models.rs
+++ b/src/kraken/models.rs
@@ -5,6 +5,7 @@ extern crate url;
use url::Url;
use chrono::{DateTime, Utc};
use super::types::{UserId, VideoId};
+use crate::client::PaginationTrait;
#[derive(Debug, Deserialize)]
pub struct Clip {
@@ -27,6 +28,10 @@ pub struct Clip {
pub thumbnails: Thumbnails,
}
+impl PaginationTrait for Clip {
+ fn cursor<'a>(&'a self) -> Option<&'a str> { None }
+}
+
#[derive(Debug, Deserialize)]
pub struct Thumbnails {
diff --git a/src/kraken/namespaces/clips.rs b/src/kraken/namespaces/clips.rs
new file mode 100644
index 0000000..edde25b
--- /dev/null
+++ b/src/kraken/namespaces/clips.rs
@@ -0,0 +1,33 @@
+use std::collections::BTreeMap;
+use super::super::models::{Clip};
+use super::super::Client;
+use crate::client::{RatelimitKey, ClientTrait, ApiRequest};
+use reqwest::Method;
+use super::Namespace;
+
+pub struct Clips {}
+type ClipsNamespace = Namespace<Clips>;
+
+impl ClipsNamespace {
+ pub fn clip(self, id: &str) -> ApiRequest<Clip> {
+ use self::clip;
+ clip(self.client, id)
+ }
+}
+
+impl Client {
+
+ pub fn clips(&self) -> ClipsNamespace {
+ ClipsNamespace::new(self)
+ }
+}
+
+pub fn clip(client: Client, id: &str)
+ -> ApiRequest<Clip>
+{
+ let client = client.inner;
+ let url = String::from("https://") + client.domain() + "/kraken/clips/" + id;
+ let params = BTreeMap::new();
+
+ ApiRequest::new(url, params, client, Method::GET, Some(RatelimitKey::Default))
+}
diff --git a/src/kraken/namespaces/mod.rs b/src/kraken/namespaces/mod.rs
new file mode 100644
index 0000000..5f4b421
--- /dev/null
+++ b/src/kraken/namespaces/mod.rs
@@ -0,0 +1,19 @@
+use std::marker::PhantomData;
+pub use super::models;
+pub use super::Client;
+
+pub mod clips;
+
+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/lib.rs b/src/lib.rs
index 5392b8e..9a90e59 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,10 +10,10 @@ pub mod helix;
pub mod kraken;
pub mod types;
pub mod error;
-pub mod sync;
+mod sync;
pub mod namespace;
pub mod client;
pub mod models;
pub use self::helix::Client as HelixClient;
-//pub use self::kraken::Client as KrakenClient;
+pub use self::kraken::Client as KrakenClient;
diff --git a/src/namespace/auth.rs b/src/namespace/auth.rs
index 577aa92..c7a0c67 100644
--- a/src/namespace/auth.rs
+++ b/src/namespace/auth.rs
@@ -1,7 +1,6 @@
use std::collections::BTreeMap;
use crate::models::Credentials;
use crate::client::Client;
-const ID_DOMAIN: &'static str = "id.twitch.tv";
use crate::client::{ClientTrait, ApiRequest};
use reqwest::Method;
use std::marker::PhantomData;
@@ -43,7 +42,7 @@ pub fn client_credentials(client: Client, secret: &str)
let url =
String::from("https://") +
- ID_DOMAIN + "/oauth2/token";
+ client.auth_domain() + "/oauth2/token";
let mut params = BTreeMap::new();
params.insert("client_id", client.id());
diff --git a/src/types.rs b/src/types.rs
index 09f2063..db8f0cb 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -11,11 +11,13 @@ use std::marker::PhantomData;
pub struct User {}
pub struct Video {}
+pub struct Game {}
pub type UserId = IntegerId<User>;
pub type ChannelId = UserId;
pub type VideoId = IntegerId<Video>;
pub type ClipId = Id;
+pub type GameId = IntegerId<Game>;
#[derive(Clone)]
pub struct IntegerId<T> {
@@ -115,6 +117,14 @@ pub struct Id {
inner: String
}
+impl Id {
+ pub fn new(id: &str) -> Id {
+ Id {
+ inner: id.to_owned(),
+ }
+ }
+}
+
impl AsRef<str> for Id {
fn as_ref(&self) -> &str {