twitch_highway 0.0.4

Twitch Api reqest Http
Documentation
use std::{collections::HashMap, sync::Arc};

use asknothingx2_util::{
    api::{APIRequest, HeaderBuilder, HeaderMap, Method},
    oauth::{AccessToken, ClientId},
};
use serde::{Deserialize, Serialize};
use url::Url;

#[derive(Debug, thiserror::Error)]
pub enum EventSubCreateError {
    #[error("empty value: {0}")]
    EmptyValue(String),
}

#[derive(Debug, Serialize)]
pub struct CreateEventSub<'a> {
    #[serde(skip)]
    pub access_token: Arc<AccessToken>,
    #[serde(skip)]
    pub client_id: Arc<ClientId>,
    #[serde(skip)]
    pub url: Url,
    #[serde(rename = "type")]
    pub kind: &'a str,
    pub version: &'a str,
    pub condition: HashMap<&'a str, &'a str>,
    pub transport: Transport,
}
impl<'a> CreateEventSub<'a> {
    pub fn new(
        access_token: Arc<AccessToken>,
        client_id: Arc<ClientId>,
        url: Url,
        kind: &'a str,
        version: &'a str,
        condition: HashMap<&'a str, &'a str>,
        transport_method: TransportMethod,
    ) -> CreateEventSub<'a> {
        Self {
            access_token,
            client_id,
            url,
            kind,
            version,
            condition,
            transport: Transport {
                method: transport_method,
                callback: None,
                secret: None,
                session_id: None,
                conduit_id: None,
            },
        }
    }

    pub fn set_type(mut self, kind: &'a str) -> Self {
        self.kind = kind;
        self
    }
    pub fn set_version(mut self, version: &'a str) -> Self {
        self.version = version;
        self
    }
    pub fn set_condition(mut self, condition: HashMap<&'a str, &'a str>) -> Self {
        self.condition = condition;
        self
    }
    pub fn set_transport(mut self, transport: Transport) -> Self {
        self.transport = transport;
        self
    }
}

impl APIRequest for CreateEventSub<'_> {
    fn json(&self) -> Option<String> {
        Some(Self::json_to_string(self).unwrap())
    }

    fn headers(&self) -> HeaderMap {
        HeaderBuilder::new()
            .content_type_json()
            .authorization("Bearer", self.access_token.secret().as_str())
            .client_id(self.client_id.as_str())
            .build()
    }

    fn method(&self) -> Method {
        Method::POST
    }

    fn url(&self) -> Url {
        self.url.clone()
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EventSubCreateResponse {
    data: EventSubCreateResponseData,
    total: u64,
    total_cost: u64,
    max_total_cost: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EventSubCreateResponseData {
    id: String,
    status: String,
    #[serde(rename = "type")]
    kind: String,
    version: String,
    condition: HashMap<String, String>,
    created_at: String,
    transport: Transport,
    cost: u64,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Transport {
    pub method: TransportMethod,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub callback: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub secret: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub session_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conduit_id: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TransportMethod {
    Webhook,
    Websocket,
    Conduit,
    Unknown,
}

#[cfg(test)]
mod tests {
    use std::{collections::HashMap, sync::Arc};

    use asknothingx2_util::{
        api::{APIRequest, HeaderBuilder, Method},
        oauth::{AccessToken, ClientId},
    };
    use pretty_assertions::assert_eq;
    use url::Url;

    use super::CreateEventSub;
    use crate::{expect_APIRequest, expect_headers, TransportMethod};

    #[test]
    fn create_eventsub() {
        let mut condition = HashMap::new();
        condition.insert("user_id", "1234");

        let create_eventsub = CreateEventSub::new(
            Arc::new(AccessToken::new(
                "cfabdegwdoklmawdzdo98xt2fo512y".to_string(),
            )),
            Arc::new(ClientId::new("uo6dggojyb8d6soh92zknwmi5ej1q2".to_string())),
            Url::parse("https://api.twitch.tv/helix/eventsub/subscriptions").unwrap(),
            "user.update",
            "1",
            HashMap::new(),
            TransportMethod::Websocket,
        )
        .set_condition(condition);

        let expected_headers = expect_headers!(json);
        let expected_json ="{\"type\":\"user.update\",\"version\":\"1\",\"condition\":{\"user_id\":\"1234\"},\"transport\":{\"method\":\"websocket\"}}".to_string();

        expect_APIRequest!(
            POST,
            expected_headers,
            "https://api.twitch.tv/helix/eventsub/subscriptions",
            create_eventsub
        );
        expect_APIRequest!(json = Some(expected_json), create_eventsub);
    }
}