sm64pc/gamebridge/src/twitch.rs

132 lines
4.2 KiB
Rust

use crate::{
controller::{HiButtons, LoButtons},
MTState,
};
use tokio::stream::StreamExt as _;
use twitchchat::{events, Control, Dispatcher, Runner, Status};
pub(crate) fn run(st: MTState) {
use tokio::runtime::Runtime;
Runtime::new()
.expect("Failed to create Tokio runtime")
.block_on(handle(st));
}
async fn handle(st: MTState) {
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 channels = &[std::env::var("TWITCH_CHANNEL").unwrap()];
let dispatcher = Dispatcher::new();
let (runner, control) = Runner::new(dispatcher.clone(), twitchchat::RateLimit::default());
let fut = run_loop(control.clone(), dispatcher, channels, st);
let conn = twitchchat::connect_easy_tls(&nick, &pass).await.unwrap();
tokio::select! {
_ = fut => { control.stop() }
status = runner.run(conn) => {
match status {
Ok(Status::Eof) => {}
Ok(Status::Canceled) => {}
Ok(Status::Timeout) => {}
Err(err) => panic!(err),
}
}
}
}
async fn run_loop(
mut control: Control,
mut dispatcher: Dispatcher,
channels: &[String],
st: MTState,
) {
let mut join = dispatcher.subscribe::<events::Join>();
let mut part = dispatcher.subscribe::<events::Part>();
let mut pmsg = dispatcher.subscribe::<events::Privmsg>();
async fn wait_and_join(
control: &mut Control,
dispatcher: &mut Dispatcher,
channels: &[String],
) {
let ready = dispatcher.wait_for::<events::IrcReady>().await.unwrap();
eprintln!("our name: {}", ready.nickname);
let w = control.writer();
for channel in channels {
eprintln!("joining: {}", channel);
let _ = w.join(channel).await;
eprintln!("joined");
}
eprintln!("joined all channels")
}
wait_and_join(&mut control, &mut dispatcher, channels).await;
let mut stickx: i8 = 0;
let mut sticky: i8 = 0;
loop {
tokio::select! {
Some(msg) = join.next() => {
eprintln!("{} joined {}", msg.name, msg.channel);
}
Some(msg) = part.next() => {
eprintln!("{} left {}", msg.name, msg.channel);
}
Some(msg) = pmsg.next() => {
let mut hi = HiButtons::NONE;
let mut lo = LoButtons::NONE;
let mut data = msg.data.to_string();
let data = data.to_ascii_lowercase();
match data.as_str() {
"a" => hi = hi | HiButtons::A_BUTTON,
"b" => hi = hi | HiButtons::B_BUTTON,
"z" => hi = hi | HiButtons::Z_BUTTON,
"r" => lo = lo | LoButtons::R_BUTTON,
"cup" => lo = lo | LoButtons::C_UP,
"cdown" => lo = lo | LoButtons::C_DOWN,
"cleft" => lo = lo | LoButtons::C_LEFT,
"cright" => lo = lo | LoButtons::C_RIGHT,
"start" => hi = hi | HiButtons::START,
"up" => sticky = 127,
"down" => sticky = -128,
"left" => stickx = -128,
"right" => stickx = 127,
"stop" => {stickx = 0; sticky = 0;},
_ => {},
}
{
let mut data = st.write().unwrap();
data.controller[0] = hi.bits() as u8;
data.controller[1] = lo.bits() as u8;
data.controller[2] = stickx as u8;
data.controller[3] = sticky as u8;
}
eprintln!("[{}] {}: {}", msg.channel, msg.name, msg.data);
match msg.data.split(" ").next() {
Some("!quit") => {
// causes the runner to shutdown
control.stop();
}
_ => {}
}
}
else => { break }
}
}
}