Skip to content

Commit

Permalink
Merge pull request #459 from twitch-rs/feat/conduits
Browse files Browse the repository at this point in the history
Complete Conduits and use `twitch_types`
  • Loading branch information
Nerixyz authored Dec 1, 2024
2 parents 941bf8a + e668e54 commit 0c7edfc
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 82 deletions.
12 changes: 6 additions & 6 deletions src/eventsub/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ pub struct EventSubSubscription {
#[cfg_attr(nightly, doc(cfg(feature = "eventsub")))]
pub struct Conduit {
/// Conduit ID
pub id: String,
pub id: types::ConduitId,
/// Number of shards associated with this conduit
pub shard_count: usize,
}
Expand All @@ -990,17 +990,17 @@ pub struct Conduit {
#[cfg_attr(nightly, doc(cfg(feature = "eventsub")))]
pub struct Shard {
/// Shard ID.
pub id: String,
pub id: types::ConduitShardId,

/// The transport details that you want Twitch to use when sending you notifications.
pub transport: Transport,
}

impl Shard {
/// Create a shard with a transport set
pub fn new(id: impl std::string::ToString, transport: Transport) -> Self {
pub fn new(id: impl Into<types::ConduitShardId>, transport: Transport) -> Self {
Self {
id: id.to_string(),
id: id.into(),

transport,
}
Expand Down Expand Up @@ -1051,7 +1051,7 @@ pub enum ShardStatus {
#[non_exhaustive]
pub struct ShardError {
/// Shard ID.
pub id: String,
pub id: types::ConduitShardId,

/// The error that occurred while updating the shard.
pub message: String,
Expand All @@ -1065,7 +1065,7 @@ pub struct ShardError {
#[non_exhaustive]
pub struct ShardResponse {
/// Shard ID.
pub id: String,
pub id: types::ConduitShardId,

/// The shard status. The subscriber receives events only for enabled shards.
pub status: ShardStatus,
Expand Down
104 changes: 96 additions & 8 deletions src/helix/client/client_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1713,7 +1713,7 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> {
///
/// # Ok(()) }
/// ```
pub async fn create_conduit<'b: 'client, T>(
pub async fn create_conduit<T>(
&'client self,
shard_count: usize,
token: &'client T,
Expand Down Expand Up @@ -1781,7 +1781,7 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> {
/// ```
pub fn get_conduit_shards<'b: 'client, T>(
&'client self,
conduit_id: impl Into<Cow<'b, str>>,
conduit_id: impl types::IntoCow<'b, types::ConduitIdRef> + 'b,
status: impl Into<Option<crate::eventsub::ShardStatus>>,
token: &'client T,
) -> impl futures::Stream<Item = Result<crate::eventsub::ShardResponse, ClientError<C>>>
Expand All @@ -1792,14 +1792,102 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> {
T: TwitchToken + Send + Sync + ?Sized,
{
let req = helix::eventsub::GetConduitShardsRequest {
conduit_id: conduit_id.into(),
conduit_id: conduit_id.into_cow(),
status: status.into(),
after: None,
};

make_stream(req, token, self, std::collections::VecDeque::from)
}

#[cfg(feature = "eventsub")]
/// Updates a [conduit](crate::eventsub::Conduit)’s shard count..
///
/// # Notes
///
/// To delete shards, update the count to a lower number, and the shards above the count will be deleted.
/// For example, if the existing shard count is 100, by resetting shard count to 50, shards 50-99 are disabled.
///
/// The token must be an App Access Token.
///
/// # Examples
///
/// ```rust, no_run
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
/// # let client: helix::HelixClient<'static, twitch_api::client::DummyHttpClient> = helix::HelixClient::default();
/// # let client_id = twitch_oauth2::types::ClientId::from_static("your_client_id");
/// # let client_secret = twitch_oauth2::types::ClientSecret::from_static("your_client_id");
/// # let token = twitch_oauth2::AppAccessToken::get_app_access_token(&client, client_id, client_secret, vec![]).await?;
/// use twitch_api::{helix, eventsub};
///
/// // The conduit ID of a previously created Conduit
/// let conduit_id = "bb7a1803-eb03-41ef-a1ab-e9242e72053e";
/// let shard_count = 5;
/// let updated: eventsub::Conduit = client
/// .update_conduit(conduit_id, shard_count, &token)
/// .await?;
///
/// # Ok(()) }
/// ```
pub async fn update_conduit<'b: 'client, T>(
&'client self,
conduit_id: impl types::IntoCow<'b, types::ConduitIdRef> + 'b + Send,
shard_count: usize,
token: &'client T,
) -> Result<crate::eventsub::Conduit, ClientError<C>>
where
T: TwitchToken + Send + Sync + ?Sized,
{
let req = helix::eventsub::UpdateConduitRequest::default();
let body = helix::eventsub::UpdateConduitBody::new(conduit_id, shard_count);

self.req_patch(req, body, token)
.await
.map(|response| response.data)
}

#[cfg(feature = "eventsub")]
/// Deletes a specified [conduit](crate::eventsub::Conduit).
///
/// # Notes
///
/// Note that it may take some time for Eventsub subscriptions on a deleted conduit to show as disabled when calling [Get Eventsub Subscriptions][Self::get_eventsub_subscriptions].
///
/// The token must be an App Access Token.
///
/// # Examples
///
/// ```rust, no_run
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
/// # let client: helix::HelixClient<'static, twitch_api::client::DummyHttpClient> = helix::HelixClient::default();
/// # let client_id = twitch_oauth2::types::ClientId::from_static("your_client_id");
/// # let client_secret = twitch_oauth2::types::ClientSecret::from_static("your_client_id");
/// # let token = twitch_oauth2::AppAccessToken::get_app_access_token(&client, client_id, client_secret, vec![]).await?;
/// use twitch_api::{helix, eventsub};
///
/// // The conduit ID of a previously created Conduit
/// let conduit_id = "bb7a1803-eb03-41ef-a1ab-e9242e72053e";
/// client
/// .delete_conduit(conduit_id, &token)
/// .await?;
///
/// # Ok(()) }
/// ```
pub async fn delete_conduit<'b: 'client, T>(
&'client self,
conduit_id: impl types::IntoCow<'b, types::ConduitIdRef> + 'b + Send,
token: &'client T,
) -> Result<(), ClientError<C>>
where
T: TwitchToken + Send + Sync + ?Sized,
{
let req = helix::eventsub::DeleteConduitRequest::new(conduit_id);

self.req_delete(req, token).await.map(|_| ())
}

#[cfg(feature = "eventsub")]
/// Updates the [Shard](crate::eventsub) for the given [Conduit](crate::eventsub).
///
Expand Down Expand Up @@ -1833,22 +1921,22 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> {
/// );
///
/// let response = client
/// .update_conduit_shards(conduit_id, vec![shard], &token)
/// .update_conduit_shards(conduit_id, &[shard], &token)
/// .await;
///
/// # Ok(()) }
/// ```
pub async fn update_conduit_shards<'b: 'client, T>(
&'client self,
conduit_id: impl Into<String> + Send,
shards: Vec<crate::eventsub::Shard>,
conduit_id: impl types::IntoCow<'b, types::ConduitIdRef> + 'b + Send,
shards: impl Into<Cow<'b, [crate::eventsub::Shard]>> + Send,
token: &'client T,
) -> Result<helix::eventsub::UpdateConduitShardsResponse, ClientError<C>>
where
T: TwitchToken + Send + Sync + ?Sized,
{
let req = helix::eventsub::UpdateConduitShardsRequest {};
let body = helix::eventsub::UpdateConduitShardsBody::new(conduit_id.into(), shards);
let req = helix::eventsub::UpdateConduitShardsRequest::default();
let body = helix::eventsub::UpdateConduitShardsBody::new(conduit_id, shards);

self.req_patch(req, body, token)
.await
Expand Down
2 changes: 1 addition & 1 deletion src/helix/endpoints/eventsub/create_conduit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ fn test_successful_response() {
assert_eq!(
response.data,
crate::eventsub::Conduit {
id: "bfcfc993-26b1-b876-44d9-afe75a379dac".to_string(),
id: "bfcfc993-26b1-b876-44d9-afe75a379dac".into(),
shard_count: 5,
},
);
Expand Down
98 changes: 98 additions & 0 deletions src/helix/endpoints/eventsub/delete_conduit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! Deletes a specified conduit.
//! [`delete-conduit`](https://dev.twitch.tv/docs/api/reference/#delete-conduit)
//!
//! Note that it may take some time for Eventsub subscriptions on a deleted conduit to show as disabled when calling [Get Eventsub Subscriptions](super::get_eventsub_subscriptions).
use super::*;
use helix::RequestDelete;

/// Query Parameters for [Delete Conduit](super::delete_conduit)
///
/// [`delete-conduit`](https://dev.twitch.tv/docs/api/reference/#delete-conduit)
#[derive(PartialEq, Eq, Serialize, Clone, Debug)]
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
#[must_use]
#[non_exhaustive]
pub struct DeleteConduitRequest<'a> {
/// Conduit ID.
#[cfg_attr(feature = "typed-builder", builder(setter(into)))]
#[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))]
pub id: Cow<'a, types::ConduitIdRef>,
}

impl<'a> DeleteConduitRequest<'a> {
/// Delete a specific conduit
pub fn new(id: impl types::IntoCow<'a, types::ConduitIdRef> + 'a) -> Self {
Self { id: id.into_cow() }
}
}

/// Return Values for [Delete Conduit](super::delete_conduit)
///
/// [`delete-conduit`](https://dev.twitch.tv/docs/api/reference/#delete-conduit)
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
#[non_exhaustive]
pub enum DeleteConduitResponse {
/// 204 - Conduit deleted
Success,
}

impl Request for DeleteConduitRequest<'_> {
type Response = DeleteConduitResponse;

const PATH: &'static str = "eventsub/conduits";
#[cfg(feature = "twitch_oauth2")]
const SCOPE: twitch_oauth2::Validator = twitch_oauth2::validator![];
}

impl RequestDelete for DeleteConduitRequest<'_> {
fn parse_inner_response(
request: Option<Self>,
uri: &http::Uri,
response: &str,
status: http::StatusCode,
) -> Result<helix::Response<Self, Self::Response>, helix::HelixRequestDeleteError>
where
Self: Sized,
{
match status {
http::StatusCode::NO_CONTENT | http::StatusCode::OK => Ok(helix::Response::with_data(
DeleteConduitResponse::Success,
request,
)),
_ => Err(helix::HelixRequestDeleteError::InvalidResponse {
reason: "unexpected status",
response: response.to_string(),
status,
uri: uri.clone(),
}),
}
}
}

#[cfg(test)]
#[test]
fn test_uri() {
use helix::*;
let req = DeleteConduitRequest::new("bfcfc993-26b1-b876-44d9-afe75a379dac");

let uri = req.get_uri().unwrap();
assert_eq!(
uri.to_string(),
"https://api.twitch.tv/helix/eventsub/conduits?id=bfcfc993-26b1-b876-44d9-afe75a379dac"
);
}

#[cfg(test)]
#[test]
fn test_successful_response() {
use helix::*;
let req = DeleteConduitRequest::new("bfcfc993-26b1-b876-44d9-afe75a379dac");

let http_response = http::Response::builder().status(204).body(vec![]).unwrap();

let uri = req.get_uri().unwrap();
let response = DeleteConduitRequest::parse_response(Some(req), &uri, http_response).unwrap();

assert_eq!(response.data, DeleteConduitResponse::Success);
}
Loading

0 comments on commit 0c7edfc

Please sign in to comment.