1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#![doc(alias = "bits")]
#![doc(alias = "channel-bits-events-v2")]
use crate::{pubsub, types};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[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: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::BitsRead];
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "allow_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(not(feature = "allow_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(not(feature = "allow_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);
}
}