#![doc(alias = "bits")]
#![doc(alias = "channel-bits-events-v2")]
use crate::{pubsub, types};
use serde_derive::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(into = "String", try_from = "String")]
pub struct ChannelBitsEventsV2 {
pub channel_id: u32,
}
impl_de_ser!(ChannelBitsEventsV2, "channel-bits-events-v2", channel_id);
impl pubsub::Topic for ChannelBitsEventsV2 {
#[cfg(feature = "twitch_oauth2")]
const SCOPE: twitch_oauth2::Validator =
twitch_oauth2::validator![twitch_oauth2::Scope::BitsRead];
fn into_topic(self) -> pubsub::Topics { super::Topics::ChannelBitsEventsV2(self) }
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
#[serde(tag = "message_type")]
#[non_exhaustive]
pub enum ChannelBitsEventsV2Reply {
#[serde(rename = "bits_event")]
BitsEvent {
data: BitsEventData,
message_id: String,
version: String,
#[doc(hidden)]
#[serde(default)] is_anonymous: bool,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct BitsEventData {
pub badge_entitlement: Option<BadgeEntitlement>,
pub bits_used: i64,
pub channel_id: types::UserId,
pub channel_name: types::UserName,
pub chat_message: String,
pub context: BitsContext,
#[serde(default)] pub is_anonymous: bool,
pub time: types::Timestamp,
pub total_bits_used: i64,
pub user_id: types::UserId,
pub user_name: types::UserName,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct BadgeEntitlement {
new_version: u64,
previous_version: u64,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BitsContext {
#[serde(rename = "cheer")]
Cheer,
}
#[cfg(test)]
mod tests {
use super::super::{Response, TopicData};
use super::*;
#[test]
fn bits_event() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "channel-bits-events-v2.1234",
"message": "{\"data\":{\"user_name\":\"justintv\",\"channel_name\":\"tmi\",\"user_id\":\"12345\",\"channel_id\":\"1234\",\"time\":\"2020-10-19T17:50:24.807841596Z\",\"chat_message\":\"Corgo1 Corgo1 Corgo1 Corgo1 Corgo1\",\"bits_used\":5,\"total_bits_used\":29,\"is_anonymous\":false,\"context\":\"cheer\",\"badge_entitlement\":null},\"version\":\"1.0\",\"message_type\":\"bits_event\",\"message_id\":\"d1831817-95f2-5dfa-8864-f36f16eeb5d8\"}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChannelBitsEventsV2 { .. },
}
));
}
#[test]
fn bits_event_documented() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "channel-bits-events-v2.46024993",
"message": "{\"data\":{\"user_name\":\"jwp\",\"channel_name\":\"bontakun\",\"user_id\":\"95546976\",\"channel_id\":\"46024993\",\"time\":\"2017-02-09T13:23:58.168Z\",\"chat_message\":\"cheer10000 New badge hype!\",\"bits_used\":10000,\"total_bits_used\":25000,\"context\":\"cheer\",\"badge_entitlement\":{\"new_version\":25000,\"previous_version\":10000}},\"version\":\"1.0\",\"message_type\":\"bits_event\",\"message_id\":\"8145728a4-35f0-4cf7-9dc0-f2ef24de1eb6\",\"is_anonymous\":true}"
}
}
"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChannelBitsEventsV2 { .. },
}
));
}
#[test]
fn check_deser() {
use std::convert::TryInto as _;
let s = "channel-bits-events-v2.1234";
assert_eq!(
ChannelBitsEventsV2 { channel_id: 1234 },
s.to_string().try_into().unwrap()
);
}
#[test]
fn check_ser() {
let s = "channel-bits-events-v2.1234";
let right: String = ChannelBitsEventsV2 { channel_id: 1234 }.into();
assert_eq!(s.to_string(), right);
}
}