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::(); let mut part = dispatcher.subscribe::(); let mut pmsg = dispatcher.subscribe::(); async fn wait_and_join( control: &mut Control, dispatcher: &mut Dispatcher, channels: &[String], ) { let ready = dispatcher.wait_for::().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 } } } }