twitchchat
interface to the irc portion of twitch's chat
you provide implementations of ReadAdapter
and WriteAdapter
or, wrap an std::io::Read
and std::io::Write
with
ReadAdapter
and WriteAdapter
...and this provides all of the types for Twitch chat message.
see the docs for more info
if you want serde support, then include features = ["serde_derive"]
in your Cargo.toml
a demo of it:
fn main() {
use std::net::TcpStream;
use twitchchat::commands::PrivMsg;
use twitchchat::{Client, Writer, UserConfig, sync_adapters};
// create a userconfig
let userconfig = UserConfig::builder()
.nick(env!("MY_TWITCH_NAME"))
.token(env!("MY_TWITCH_PASS"))
// enable these capabilities
.tags()
.membership()
.commands()
// build the config
.build()
.expect("semi-valid config");
// connect to twitch
let read = TcpStream::connect(twitchchat::TWITCH_IRC_ADDRESS).expect("connect");
// clone the tcpstream
let write = read.try_clone().expect("must be able to clone");
// create the adapters adapter
let (read, write) = sync_adapters(read, write);
// create a new client from the read, write pairs
let mut client = Client::new(read, write);
// when we receive a PrivMsg run this function
// tok allows us to remove this later, if we want
let _tok = client.on(move |msg: PrivMsg, w: Writer| {
const KAPPA: usize = 25;
// print out `user: message`
println!("{}: {}", msg.display_name().unwrap(), msg.message());
let kappas = msg
.emotes()
.iter()
// filter Kappas
.filter(|e| e.id == KAPPA)
// count how many times it appears
.map(|d| d.ranges.len())
.sum::<usize>();
// if someone sent more than 3 Kappas, send a Kappa back
if kappas >= 3 {
// using the provided Writer
w.send(msg.channel(), "Kappa").unwrap();
}
});
// log if the broadcaster, a sub or a mod talks
client.on(move |msg: PrivMsg, _: Writer| {
use twitchchat::BadgeKind::{Broadcaster, Subscriber};
let name = msg.display_name().unwrap_or_else(|| msg.irc_name());
let badges = msg
.badges()
.iter()
// filter to just the "BadgeKind"
.map(|badge| badge.kind.clone())
.collect::<Vec<_>>();
match (
badges.contains(&Broadcaster),
badges.contains(&Subscriber),
msg.moderator(), // or badges.contains(&Moderator)
) {
(true, _, _) => println!("{} is the broadcaster", name),
(_, true, _) => println!("{} is a subscriber", name),
(_, _, true) => println!("{} is a mod", name),
(_, _, _) => {
// just a normal viewer
}
};
});
// 'register' (sends out creds.) with the server
client.register(userconfig).expect("register with twitch");
// blocks the thread until the server tells us who we were
match client.wait_for_ready() {
// and print it out
Ok(user) => {
// id: 23196011, name: Some("museun"), color: Some(OrangeRed)
println!(
"id: {}, name: {:?}, color: {:?}",
user.user_id, user.display_name, user.color
)
}
Err(twitchchat::Error::InvalidRegistration) => {
eprintln!("invalid nick/pass");
std::process::exit(1);
}
Err(err) => panic!(err),
};
// get a clone of the writer, this allows you to write to the connection
let w = client.writer();
// join a channel
w.join("museun").unwrap();
{
// not needed here, but the writer is clonable
// you can also get another one from the `client`
let w = w.clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(3));
w.send("museun", "VoHiYo").unwrap();
});
}
// block this thread until the connection ends
// this will call the filters when it receives the appropirate message
if let Err(err) = client.run() {
eprintln!("error while running: {}", err);
std::process::exit(1);
}
}