diff options
| author | Jokler <jokler.contact@gmail.com> | 2020-01-06 00:07:57 +0100 |
|---|---|---|
| committer | Jokler <jokler.contact@gmail.com> | 2020-01-06 00:07:57 +0100 |
| commit | 31fab217a2221d76c79bd0b7b0f2e97fbc23d06b (patch) | |
| tree | 399388eab5fecfd485b1f85fbb5770dca424f2ed /src/main.rs | |
| download | pokebot-31fab217a2221d76c79bd0b7b0f2e97fbc23d06b.tar.gz pokebot-31fab217a2221d76c79bd0b7b0f2e97fbc23d06b.zip | |
Initial commit
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e00ae9f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,193 @@ +use std::str::FromStr; +use std::io::Read; +use std::path::PathBuf; + +use futures::{ + compat::Future01CompatExt, + future::{FutureExt, TryFutureExt}, +}; + +use futures01::{future::Future, stream::Stream, sync::mpsc}; +use structopt::clap::AppSettings; +use structopt::StructOpt; + +use tsclientlib::{ + events::Event, ChannelId, ConnectOptions, Connection, ConnectionLock, DisconnectOptions, + Event::ConEvents, Identity, MessageTarget, +}; + +use log::error; + +mod state; +use state::State; + +#[derive(StructOpt, Debug)] +#[structopt(raw(global_settings = "&[AppSettings::ColoredHelp]"))] +struct Args { + #[structopt( + short = "a", + long = "address", + default_value = "localhost", + help = "The address of the server to connect to" + )] + address: String, + #[structopt( + short = "i", + long = "id", + help = "Identity file - good luck creating one", + parse(from_os_str) + )] + id_path: Option<PathBuf>, + #[structopt( + short = "v", + long = "verbose", + help = "Print the content of all packets", + parse(from_occurrences) + )] + verbose: u8, + // 0. Print nothing + // 1. Print command string + // 2. Print packets + // 3. Print udp packets +} + +fn main() { + tokio::run(async_main().unit_error().boxed().compat()); +} + +async fn async_main() { + // Parse command line options + let args = Args::from_args(); + + let id = if let Some(path) = args.id_path { + let mut file = std::fs::File::open(path).expect("Failed to open id file"); + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("Failed to read id file"); + + toml::from_str(&content).expect("Failed to parse id file") + } else { + Identity::create().expect("Failed to create id") + }; + + let con_config = ConnectOptions::new(args.address) + .version(tsclientlib::Version::Linux_3_3_2) + .name(String::from("PokeBot")) + .identity(id) + .log_commands(args.verbose >= 1) + .log_packets(args.verbose >= 2) + .log_udp_packets(args.verbose >= 3); + + //let (disconnect_send, disconnect_recv) = mpsc::unbounded(); + let con = Connection::new(con_config).compat().await.unwrap(); + + let mut state = State::new(con.clone()); + { + let packet = con.lock().server.set_subscribed(true); + con.send_packet(packet).compat().await; + } + //con.add_on_disconnect(Box::new( || { + //disconnect_send.unbounded_send(()).unwrap() + //})); + let inner_state = state.clone(); + con.add_event_listener( + String::from("listener"), + Box::new(move |e| { + if let ConEvents(con, events) = e { + for event in *events { + handle_event(&inner_state, &con, event); + } + } + }), + ); + + loop { + state.poll().await; + } + let ctrl_c = tokio_signal::ctrl_c().flatten_stream(); + + //let dc_fut = disconnect_recv.into_future().compat().fuse(); + //let ctrlc_fut = ctrl_c.into_future().compat().fuse(); + //ctrlc_fut.await.map_err(|(e, _)| e).unwrap(); + + con.disconnect(DisconnectOptions::new()) + .compat() + .await + .unwrap(); + + // TODO Should not be required + std::process::exit(0); +} + +fn handle_event<'a>(state: &State, con: &ConnectionLock<'a>, event: &Event) { + match event { + Event::Message { + from: target, + invoker: sender, + message: msg, + } => { + if let MessageTarget::Poke(who) = target { + let channel = con.clients.get(&who).expect("can find poke sender").channel; + tokio::spawn( + con.to_mut() + .get_client(&con.own_client) + .expect("can get myself") + .set_channel(channel) + .map_err(|e| error!("Failed to switch channel: {}", e)), + ); + } else if sender.id != con.own_client { + if msg.starts_with("!") { + let tokens = msg[1..].split_whitespace().collect::<Vec<_>>(); + match tokens.get(0).map(|t| *t) { + Some("test") => { + tokio::spawn( + con.to_mut() + .send_message(*target, "works :)") + .map_err(|_| ()), + ); + } + Some("add") => { + let mut invalid = false; + if let Some(url) = &tokens.get(1) { + if url.len() > 11 { + let trimmed = url[5..url.len() - 6].to_owned(); + state.add_audio(trimmed); + } else { + invalid = true; + } + } else { + invalid = true; + } + if invalid { + tokio::spawn( + con.to_mut() + .send_message(MessageTarget::Channel, "Invalid Url") + .map_err(|_| ()), + ); + } + } + Some("volume") => { + if let Ok(volume) = f64::from_str(tokens[1]) { + state.volume(volume / 100.0); + } + } + Some("play") => { + state.play(); + } + Some("pause") => { + state.pause(); + } + Some("stop") => { + state.stop(); + } + Some("quit") => { + //tokio::spawn(state.disconnect().unit_error().boxed().compat()); + } + _ => (), + }; + } + } + } + _ => (), + } +} |
