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 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
#![warn(missing_docs)] //! Connect to Twitch chat from a Rust application. //! //! This library supports the modern stdlib futures and runs using the `tokio` runtime. //! //! # Getting started //! //! The central feature of this library is the `TwitchIRCClient` which connects to Twitch IRC //! for you using a pool of connections and handles all the important bits. Here is a minimal //! example to get you started: //! //! ```no_run //! use futures::prelude::*; //! use twitch_irc::login::StaticLoginCredentials; //! use twitch_irc::ClientConfig; //! use twitch_irc::TCPTransport; //! use twitch_irc::TwitchIRCClient; //! //! #[tokio::main] //! pub async fn main() { //! // default configuration is to join chat as anonymous. //! let config = ClientConfig::default(); //! let (mut incoming_messages, client) = //! TwitchIRCClient::<TCPTransport, StaticLoginCredentials>::new(config); //! //! // first thing you should do: start consuming incoming messages, //! // otherwise they will back up. //! let join_handle = tokio::spawn(async move { //! while let Some(message) = incoming_messages.next().await { //! println!("Received message: {:?}", message); //! } //! }); //! //! // join a channel //! client.join("sodapoppin".to_owned()); //! //! // keep the tokio executor alive. //! // If you return instead of waiting the background task will exit. //! join_handle.await.unwrap(); //! } //! ``` //! //! The above example connects to chat anonymously and listens to messages coming to the channel `sodapoppin`. //! //! # Features //! //! * Simple API //! * Integrated connection pool, new connections will be made based on your application's demand //! (based on amount of channels joined as well as number of outgoing messages) //! * Automatic reconnect of failed connections, automatically re-joins channels //! * Rate limiting of new connections //! * Support for refreshing login tokens, see below //! * Fully parses all message types (see [`ServerMessage`](message/enum.ServerMessage.html) //! for all supported types) //! * Can connect using both plain TLS-secured socket as well as secure websocket //! * No unsafe code //! * Feature flags to reduce compile time and binary size //! //! # Send messages //! //! To send messages, use the `TwitchIRCClient` handle you get from `TwitchIRCClient::new`. //! //! ```no_run //! # use futures::prelude::*; //! # use twitch_irc::login::StaticLoginCredentials; //! # use twitch_irc::ClientConfig; //! # use twitch_irc::TCPTransport; //! # use twitch_irc::TwitchIRCClient; //! # //! # #[tokio::main] //! # async fn main() { //! # let config = ClientConfig::default(); //! # let (mut incoming_messages, client) = TwitchIRCClient::<TCPTransport, StaticLoginCredentials>::new(config); //! client.say("a_channel".to_owned(), "Hello world!".to_owned()).await.unwrap(); //! # } //! ``` //! //! The `TwitchIRCClient` handle can also be cloned and then used from multiple threads. //! //! See the documentation on [`TwitchIRCClient`](struct.TwitchIRCClient.html) //! for the possible methods. //! //! # Receive and handle messages //! //! Incoming messages are [`ServerMessage`](message/enum.ServerMessage.html)s. You can use a match //! block to differentiate between the possible server messages: //! //! ```no_run //! # use twitch_irc::message::ServerMessage; //! # use tokio::sync::mpsc; //! # use futures::prelude::*; //! # //! # #[tokio::main] //! # async fn main() { //! # let mut incoming_messages: mpsc::UnboundedReceiver<ServerMessage> = unimplemented!(); //! while let Some(message) = incoming_messages.next().await { //! match message { //! ServerMessage::Privmsg(msg) => { //! println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); //! }, //! ServerMessage::Whisper(msg) => { //! println!("(w) {}: {}", msg.sender.name, msg.message_text); //! }, //! _ => {} //! } //! } //! # } //! ``` //! //! # Logging in //! //! `twitch_irc` ships with [`StaticLoginCredentials`](login/struct.StaticLoginCredentials.html) //! and [`RefreshingLoginCredentials`](login/struct.RefreshingLoginCredentials.html). //! //! For simple cases, `StaticLoginCredentials` fulfills all needs: //! //! ``` //! use twitch_irc::login::StaticLoginCredentials; //! use twitch_irc::ClientConfig; //! //! let login_name = "your_bot_name".to_owned(); //! let oauth_token = "u0i05p6kbswa1w72wu1h1skio3o20t".to_owned(); //! //! let config = ClientConfig::new_simple( //! StaticLoginCredentials::new(login_name, Some(oauth_token)) //! ); //! ``` //! //! However for most applications it is strongly recommended to have your login token automatically //! refreshed when it expires. For this, enable the `refreshing-token` feature flag, and use //! [`RefreshingLoginCredentials`](login/struct.RefreshingLoginCredentials.html), for example //! like this: //! //! ```no_run //! use async_trait::async_trait; //! use twitch_irc::login::{RefreshingLoginCredentials, TokenStorage, UserAccessToken}; //! use twitch_irc::ClientConfig; //! use std::path::Path; //! //! #[derive(Debug)] //! struct CustomTokenStorage { //! // fields... //! } //! //! #[async_trait] //! impl TokenStorage for CustomTokenStorage { //! type LoadError = std::io::Error; // or some other error //! type UpdateError = std::io::Error; //! //! async fn load_token(&mut self) -> Result<UserAccessToken, Self::LoadError> { //! // Load the currently stored token from the storage. //! todo!() //! } //! //! async fn update_token(&mut self, token: &UserAccessToken) -> Result<(), Self::UpdateError> { //! // Called after the token was updated successfully, to save the new token. //! // After `update_token()` completes, the `load_token()` method should then return //! // that token for future invocations //! todo!() //! } //! } //! //! let login_name = "your_bot_name".to_owned(); //! // these credentials can be generated for your app at https://dev.twitch.tv/console/apps //! let client_id = "rrbau1x7hl2ssz78nd2l32ns9jrx2w".to_owned(); //! let client_secret = "m6nuam2b2zgn2fw8actt8hwdummz1g".to_owned(); //! let storage = CustomTokenStorage { /* ... */ }; //! //! let config = ClientConfig::new_simple( //! RefreshingLoginCredentials::new(login_name, client_id, client_secret, storage) //! ); //! // then create your client and use it //! ``` //! //! `RefreshingLoginCredentials` just needs an implementation of `TokenStorage` that depends //! on your application, to retrieve the token or update it. For example, you might put the token //! in a config file you overwrite, some extra file for secrets, or a database. //! //! # Close the client //! //! To close the client, drop all clones of the `TwitchIRCClient` handle. The client will shut down //! and end the stream of incoming messages once all processing is done. //! //! # Feature flags //! //! This library has these optional feature toggles: //! * **`transport-tcp`** enables `TCPTransport`, to connect using a plain TLS socket using the //! normal IRC protocol. //! * **`transport-wss`** enables `WSSTransport` to connect using the Twitch-specific websocket //! method. //! * **`refreshing-token`** enables //! [`RefreshingLoginCredentials`](login/struct.RefreshingLoginCredentials.html) (see above). //! * **`metrics-collection`** enables a set of metrics to be exported from the client. See the //! documentation on `ClientConfig` for details. //! //! By default, only `transport-tcp` is enabled. mod client; mod config; mod connection; mod error; pub mod login; pub mod message; mod transport; pub use client::TwitchIRCClient; pub use config::ClientConfig; pub use error::Error; #[cfg(feature = "transport-tcp")] pub use transport::tcp::TCPTransport; #[cfg(feature = "transport-wss")] pub use transport::websocket::WSSTransport; pub use transport::Transport;