diff --git a/Cargo.lock b/Cargo.lock index 65bf328..d4a756d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "arrayvec" version = "0.7.4" @@ -300,9 +306,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "camino" @@ -733,6 +739,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -787,7 +799,7 @@ dependencies = [ [[package]] name = "fren" -version = "0.7.0" +version = "0.8.0" dependencies = [ "axum", "axum-macros", @@ -800,6 +812,8 @@ dependencies = [ "log", "magick_rust", "ndm", + "prost", + "raas_types", "rand", "regex", "reqwest", @@ -1577,6 +1591,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "nanorand" version = "0.7.0" @@ -1891,6 +1911,16 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "phf" version = "0.11.2" @@ -2072,6 +2102,59 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.48", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + [[package]] name = "pulldown-cmark" version = "0.9.3" @@ -2092,6 +2175,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "raas_types" +version = "0.0.2" +source = "registry+https://git.jojodev.com/joeyahines/_cargo-index.git" +checksum = "6104c0c441473bc9c0817f9958a1c1e0db9ea7c72a7fee826b84a1d9d1baea62" +dependencies = [ + "bytes", + "prost", + "prost-build", +] + [[package]] name = "rand" version = "0.8.5" diff --git a/Cargo.toml b/Cargo.toml index 15d357d..74ff9a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "0.7.0" +version = "0.8.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -27,6 +27,8 @@ chrono = { version = "0.4.31", features = ["serde"] } chrono-tz = "0.8.5" log = "0.4.20" serde_json = "1.0.113" +raas_types = { version = "0.0.2", registry = "jojo-dev"} +prost = "0.12.6" [dependencies.serenity] version = "0.12.0" diff --git a/src/config.rs b/src/config.rs index 85ecbe1..5b6ad1c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use crate::album_manager::AlbumManager; use crate::error::Error; use crate::migrations::do_migration; +use crate::rass::RaaSHandler; use config::{Config, File}; use j_db::database::Database; use reqwest::Url; @@ -60,6 +61,7 @@ pub struct BotState { pub accepted_nsfw: Option, pub bad_apple_running: bool, pub speak_lock: Mutex<()>, + pub raas_handler: Option, } impl BotState { @@ -68,6 +70,7 @@ impl BotState { accepted_nsfw: None, bad_apple_running: false, speak_lock: Mutex::new(()), + raas_handler: None, }) } } diff --git a/src/discord/joke.rs b/src/discord/joke.rs index d7a3d1c..7839d86 100644 --- a/src/discord/joke.rs +++ b/src/discord/joke.rs @@ -2,9 +2,11 @@ use crate::album_manager::{Album, AlbumQuery, ImageQuery, ImageSort}; use crate::error::Error; use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType}; use crate::models::random::{Random, RandomConfig}; +use crate::rass::RaaSCmd; use crate::{command, group, GlobalData, BAD_APPLE}; use reqwest::Client; use serde::{Deserialize, Serialize}; +use serenity::all::{CreateAttachment, CreateMessage}; use serenity::builder::EditMessage; use serenity::client::Context; use serenity::constants::MESSAGE_CODE_LIMIT; @@ -15,7 +17,7 @@ use std::collections::HashMap; use std::time::Duration; #[group] -#[commands(dad_joke, roll, bad_apple, insult, add_random, list_random)] +#[commands(dad_joke, roll, real_roll, bad_apple, insult, add_random, list_random)] pub struct Joke; #[derive(Clone, Serialize, Deserialize)] @@ -238,6 +240,41 @@ async fn roll(ctx: &Context, msg: &Message, args: Args) -> CommandResult { Ok(()) } +#[command] +#[aliases("real_roll")] +#[description("Roll a real die!")] +async fn real_roll(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { + let mut data = ctx.data.write().await; + let global = data.get_mut::().unwrap(); + + if let Some(raas_handler) = &mut global.bot_state.raas_handler { + raas_handler.send_msg_queue.send(RaaSCmd::Roll(3)).await?; + msg.reply(&ctx.http, "Sent request to Roll Bot...").await?; + if let Some(img) = raas_handler.recv_msg_queue.recv().await { + match img { + RaaSCmd::Roll(_) => {} + RaaSCmd::Img(img_data) => { + msg.channel_id + .send_message( + &ctx.http, + CreateMessage::new() + .content("Your roll my friend, hope its good I can't read!") + .add_file(CreateAttachment::bytes(img_data, "roll.jpg")), + ) + .await?; + } + } + } else { + msg.reply(&ctx.http, "Roll Bot is gone... oh god!").await?; + } + } else { + msg.reply(&ctx.http, "Looks like I can't reach my real flesh") + .await?; + } + + Ok(()) +} + #[command] #[bucket = "bad_apple"] async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult { diff --git a/src/discord/mod.rs b/src/discord/mod.rs index 1f2d751..122d9df 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -17,6 +17,7 @@ use crate::discord::fren_coin::give_coin; use crate::discord::joke::random; use crate::models::lil_fren::lil_fren_task; use crate::models::task::Task; +use crate::rass::{RaaS, RaaSCmd, RaaSHandler}; use crate::{help, hook, GlobalData}; use rand::prelude::IteratorRandom; use rand::thread_rng; @@ -48,6 +49,29 @@ impl EventHandler for Handler { lil_fren_task(&ctx1).await; } }); + let ctx2 = ctx.clone(); + tokio::spawn(async move { + let (tx_client, rx_server) = tokio::sync::mpsc::channel::(10); + let (tx_server, rx_client) = tokio::sync::mpsc::channel::(10); + + let handler = RaaSHandler { + recv_msg_queue: rx_client, + send_msg_queue: tx_client, + }; + + let mut raas = RaaS { + recv_msg_queue: rx_server, + send_msg_queue: tx_server, + }; + + { + let mut data = ctx2.data.write().await; + let global_data = data.get_mut::().unwrap(); + global_data.bot_state.raas_handler = Some(handler); + } + + raas.worker("0.0.0.0:50000").await.unwrap(); + }); tokio::spawn(async move { Task::create_reoccurring_tasks(&ctx).await.unwrap(); diff --git a/src/main.rs b/src/main.rs index 501a5fe..fbe3e5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod error; mod inventory; mod migrations; mod models; +mod rass; mod user; use crate::config::{Args, BotConfig, Channel, GlobalData}; diff --git a/src/rass.rs b/src/rass.rs new file mode 100644 index 0000000..99fb358 --- /dev/null +++ b/src/rass.rs @@ -0,0 +1,128 @@ +use prost::Message; +use raas_types::raas; +use raas_types::raas::bot::roll::Roll; +use raas_types::raas::cmd::Command; +use raas_types::raas::register::{Register, RegisterResponse}; +use raas_types::raas::resp::response::Resp; +use raas_types::raas::resp::Response; +use raas_types::raas::RaasMessage; +use std::time::{SystemTime, UNIX_EPOCH}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; + +#[derive(Debug, Clone)] +pub enum RaaSCmd { + Roll(u32), + Img(Vec), +} + +#[derive(Debug)] +pub struct RaaSHandler { + pub recv_msg_queue: tokio::sync::mpsc::Receiver, + pub send_msg_queue: tokio::sync::mpsc::Sender, +} + +#[derive(Debug)] +pub struct RaaS { + pub recv_msg_queue: tokio::sync::mpsc::Receiver, + pub send_msg_queue: tokio::sync::mpsc::Sender, +} + +impl RaaS { + async fn receive_packet(socket: &mut TcpStream) -> Result { + let mut message_len_bytes = [0u8; 4]; + socket.read_exact(&mut message_len_bytes).await?; + + let len = u32::from_be_bytes(message_len_bytes); + + let mut message = vec![0u8; len as usize]; + + socket.read_exact(&mut message).await?; + + Ok(RaasMessage { len, msg: message }) + } + + async fn send_packet(socket: &mut TcpStream, data: Vec) -> Result<(), std::io::Error> { + let msg = RaasMessage::new(data); + + socket.write_all(&msg.into_bytes()).await?; + Ok(()) + } + + async fn handle_register( + &self, + tcp_listener: TcpListener, + ) -> Result { + let (mut socket, _) = tcp_listener.accept().await?; + + let register_msg = Self::receive_packet(&mut socket).await?; + + let register = Register::decode(&*register_msg.msg).unwrap(); + + let register_resp = RegisterResponse { + name: register.name.to_string(), + r#type: register.bot_type, + id: 0, + }; + + let mut msg = Vec::new(); + + register_resp.encode(&mut msg).unwrap(); + + Self::send_packet(&mut socket, msg).await?; + + Ok(socket) + } + + pub async fn worker(&mut self, addr: &str) -> Result<(), std::io::Error> { + let tcp_listener = TcpListener::bind(addr).await.unwrap(); + println!("Waiting for Rollbot to connect to {}...", addr); + let mut stream = self.handle_register(tcp_listener).await?; + println!("Rollbot has entered the chat!"); + + loop { + if self.recv_msg_queue.recv().await.is_none() { + return Ok(()); + } + + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let roll = Roll { rotations: 3 }; + + let cmd = Command { + id: 0, + timestamp, + cmd: Some(raas::cmd::command::Cmd::RollCmd(raas::bot::roll::RollCmd { + cmd: Some(raas::bot::roll::roll_cmd::Cmd::Roll(roll)), + })), + }; + + let mut msg = Vec::new(); + + cmd.encode(&mut msg).unwrap(); + Self::send_packet(&mut stream, msg).await?; + + let recv = Self::receive_packet(&mut stream).await?; + + let resp = Response::decode(&*recv.msg).unwrap(); + + println!("Got {} {}", resp.id, resp.timestamp); + + match resp.resp.unwrap() { + Resp::RollResp(roll) => match roll.response.unwrap() { + raas::bot::roll::roll_response::Response::Pong(_) => {} + raas::bot::roll::roll_response::Response::RollImage(img) => { + println!("Got img!"); + self.send_msg_queue + .send(RaaSCmd::Img(img.img)) + .await + .unwrap(); + } + }, + } + } + } +}