twitchchat

This crate provides a way to interace with [Twitch]'s chat.

Along with the messages as Rust types, it provides methods for sending messages.

Simple example

```rust

[tokio::main]

async fn main() { use futures::prelude::*;

let (nick, pass) = (
    // twitch name
    std::env::var("TWITCH_NICK").unwrap(),
    // oauth token for twitch name
    std::env::var("TWITCH_PASS").unwrap(),
);

// putting this in the env so people don't join my channel when running this
let channel = std::env::var("TWITCH_CHANNEL").unwrap();

// connect via tls over tcp with this nick and password
let (read, write) = twitchchat::connect_easy(&nick, &pass, twitchchat::Secure::Nope)
    .await
    .unwrap();

// make a client. the client is clonable
let client = twitchchat::Client::new();

// get a future that resolves when the client is done reading, fails to read/write or is stopped
let done = client.run(read, write);

// get an event dispatcher
let mut dispatcher = client.dispatcher().await;

// subscribe to an event stream

// for privmsg (what users send to channels)
let mut privmsg = dispatcher.subscribe::<twitchchat::events::Privmsg>();
// spawn a task to consume the stream
tokio::task::spawn(async move {
    while let Some(msg) = privmsg.next().await {
        eprintln!("[{}] {}: {}", msg.channel, msg.user, msg.data);
    }
});

// for join (when a user joins a channel)
let mut join = dispatcher.subscribe::<twitchchat::events::Join>();
tokio::task::spawn(async move {
    while let Some(msg) = join.next().await {
        // we've joined a channel
        if msg.user == nick {
            eprintln!("you joined {}", msg.channel);
            break; // returning/dropping the stream un-subscribes it
        }
    }
});

// for privmsg again
let mut bot = dispatcher.subscribe::<twitchchat::events::Privmsg>();
// we can move the client to another task by cloning it
let bot_client = client.clone();
tokio::task::spawn(async move {
    let mut writer = bot_client.writer();
    while let Some(msg) = bot.next().await {
        match msg.data.split(" ").next() {
            Some("!quit") => {
                // causes the client to shutdown
                bot_client.stop().await.unwrap();
            }
            Some("!hello") => {
                let response = format!("hello {}!", msg.user);
                // send a message in response
                let still_connected = writer.privmsg(&msg.channel, &response).await;
                if !still_connected {
                    break;
                }
            }
            _ => {}
        }
    }
});

// dispatcher has an RAII guard, so keep it scoped
// dropping it here so everything can proceed while keeping example brief
drop(dispatcher);

// get a clonable writer from the client
// join a channel, methods on writer return false if the client is connected
if !client.writer().join(&channel).await {
    panic!("not connected!?")
}

// you can clear subscriptions with
// client.dispatcher().await.clear_subscriptions::<event::Join>()
// or all subscriptions
// client.dispatcher().await.clear_subscriptions_all()

// you can get the number of active subscriptions with
// client.dispatcher().await.count_subscribers::<event::Join>()
// or all subscriptions
// client.dispatcher().await.count_subscribers_all()

// await for the client to be done
match done.await {
    Ok(twitchchat::client::Status::Eof) => {
        eprintln!("done!");
    }
    Ok(twitchchat::client::Status::Canceled) => {
        eprintln!("client was stopped by user");
    }
    Err(err) => {
        eprintln!("error: {}", err);
    }
}

// note you should wait for all of your tasks to join before exiting
// but we detached them to make this shorter

// another way would be to clear all subscriptions
// clearing the subscriptions would close each event stream
client.dispatcher().await.count_subscribers_all();

} ```

License: 0BSD