From fc19a1430bc71276c74e9228bd41f7749b4fd104 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 26 Sep 2021 20:29:57 -0400 Subject: [PATCH] listen command --- Cargo.lock | 1 + Cargo.toml | 1 + src/twitch/websocket_client.rs | 36 ++++++++++++++++++++++++++++++++-- src/util/mod.rs | 4 +++- src/util/random_nonce.rs | 24 +++++++++++++++++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/util/random_nonce.rs diff --git a/Cargo.lock b/Cargo.lock index 1f0d4e5015..3c3628861a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1300,6 +1300,7 @@ dependencies = [ "easyenv", "futures-util", "log", + "rand", "reqwest", "rustls 0.20.0-beta2", "serde", diff --git a/Cargo.toml b/Cargo.toml index 0a57ac5219..af96cc2d8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ twitch_oauth2 = "0.6.0-rc.2" anyhow = "1.0.44" easyenv = "0.0.6" log = "0.4.14" +rand = "0.8.4" #[build-dependencies] diff --git a/src/twitch/websocket_client.rs b/src/twitch/websocket_client.rs index b8ece637eb..4c060a21b9 100644 --- a/src/twitch/websocket_client.rs +++ b/src/twitch/websocket_client.rs @@ -11,8 +11,9 @@ use tokio::net::TcpStream; use tokio; use tokio_tungstenite::tungstenite::Message; use tokio_tungstenite::{connect_async, WebSocketStream, MaybeTlsStream}; -use twitch_api2::pubsub::{Response, TopicData}; +use twitch_api2::pubsub::{Response, TopicData, Topic, Topics}; use twitch_api2::pubsub; +use crate::util::random_nonce::random_nonce; // Reference javascript Twitch Websocket client: // https://github.com/twitchdev/pubsub-javascript-sample/blob/main/main.js @@ -179,6 +180,37 @@ impl TwitchWebsocketClient { Ok(()) } + pub async fn listen<'t>(&mut self, auth_token: &str, topics: &'t [Topics]) -> AnyhowResult<()> { + //// We want to subscribe to moderator actions on channel with id 1234 + //// as if we were a user with id 4321 that is moderator on the channel. + //let chat_mod_actions = pubsub::moderation::ChatModeratorActions { + // user_id: 4321, + // channel_id: 1234, + //}.into_topic(); + + //// Listen to follows as well + //let follows = pubsub::following::Following { channel_id: 1234 }.into_topic(); + + let mut socket = match self.socket { + None => return Err(anyhow!("not connected")), + Some(ref mut socket) => socket, + }; + + let nonce = random_nonce(128); + + let command = pubsub::listen_command( + topics, + auth_token, + nonce.as_ref(), + )?; + + debug!("Sending LISTEN"); + let message = Message::Text(command); + socket.send(message).await?; + + Ok(()) + } + pub fn is_connected(&self) -> bool { // TODO: This probably isn't accurate self.socket.is_some() @@ -190,7 +222,7 @@ impl TwitchWebsocketClient { Some(ref mut socket) => socket, }; - debug!("Sending ping"); + debug!("Sending PING"); let message = Message::Text(PING_COMMAND.to_string()); socket.send(message).await?; diff --git a/src/util/mod.rs b/src/util/mod.rs index 0bb75d1b62..145df6fe0c 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1 +1,3 @@ -pub mod anyhow_result; \ No newline at end of file +pub mod anyhow_result; +pub mod random_nonce; + diff --git a/src/util/random_nonce.rs b/src/util/random_nonce.rs new file mode 100644 index 0000000000..5f9034d3aa --- /dev/null +++ b/src/util/random_nonce.rs @@ -0,0 +1,24 @@ +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; + +/// Returns a random nonce for Twitch +pub fn random_nonce(length: usize) -> String { + thread_rng() + .sample_iter(&Alphanumeric) + .take(length) + .map(char::from) + .collect() +} + +#[cfg(test)] +mod tests { + use crate::util::random_nonce::random_nonce; + + #[test] + fn random_nonce_length() { + assert_eq(1, random_nonce(1).len()); + assert_eq(10, random_nonce(10).len()); + assert_eq(15, random_nonce(15).len()); + assert_eq(64, random_nonce(64).len()); + } +} \ No newline at end of file