diff --git a/Cargo.lock b/Cargo.lock index 3ee755c..e770a80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", @@ -63,9 +63,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.10" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf" dependencies = [ "shlex", ] @@ -142,7 +142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "forcebot-rs-v2" +name = "forcebot_core" version = "0.1.0" dependencies = [ "dotenv", @@ -200,13 +200,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", ] [[package]] @@ -271,15 +272,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "moderator_reactor" +version = "0.1.0" +dependencies = [ + "dotenv", + "forcebot_core", + "lazy_static", + "tokio", + "twitch-irc", +] + [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" dependencies = [ "libc", "log", @@ -292,6 +304,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_empty_bot" +version = "0.1.0" +dependencies = [ + "dotenv", + "forcebot_core", + "lazy_static", + "tokio", + "twitch-irc", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -318,9 +341,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" dependencies = [ "bitflags", "cfg-if", @@ -344,9 +367,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" @@ -436,9 +459,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", @@ -500,6 +523,39 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_command_bot" +version = "0.1.0" +dependencies = [ + "dotenv", + "forcebot_core", + "lazy_static", + "tokio", + "twitch-irc", +] + +[[package]] +name = "simple_debug_listener" +version = "0.1.0" +dependencies = [ + "dotenv", + "forcebot_core", + "lazy_static", + "tokio", + "twitch-irc", +] + +[[package]] +name = "simple_module_example" +version = "0.1.0" +dependencies = [ + "dotenv", + "forcebot_core", + "lazy_static", + "tokio", + "twitch-irc", +] + [[package]] name = "slab" version = "0.4.9" @@ -527,9 +583,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -538,9 +594,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", @@ -687,9 +743,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "vcpkg" @@ -703,6 +759,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -784,3 +849,12 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] diff --git a/Cargo.toml b/Cargo.toml index e9d2e5e..7b027e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,7 @@ -[package] -name = "forcebot-rs-v2" -version = "0.1.0" -edition = "2021" -default-run = "forcebot-rs-v2" - -[dependencies] -dotenv = "0.15.0" -lazy_static = "1.5.0" -tokio = { version = "1.33.0", features = ["full"] } -twitch-irc = "5.0.1" - - -# [[bin]] -# name = "simple_bot" -# path = "src/simple_bot.rs" - -# [[bin]] -# name = "simple_bot_listener" -# path = "src/simple_bot_listener.rs" - -# [lib] -# name = "botlib" -# path = "src/lib.rs" \ No newline at end of file +[workspace] +members = [ + "forcebot_core", + "simple_module_example", + "new_empty_bot", + "simple_debug_listener", + "moderator_reactor", "simple_command_bot"] diff --git a/forcebot_core/Cargo.toml b/forcebot_core/Cargo.toml new file mode 100644 index 0000000..082c28b --- /dev/null +++ b/forcebot_core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "forcebot_core" +version = "0.1.0" +edition = "2021" +default-run = "fun_bot" + +[dependencies] +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/src/bin/fun_bot.rs b/forcebot_core/src/bin/fun_bot.rs similarity index 82% rename from src/bin/fun_bot.rs rename to forcebot_core/src/bin/fun_bot.rs index 4f119ce..d9d8d45 100644 --- a/src/bin/fun_bot.rs +++ b/forcebot_core/src/bin/fun_bot.rs @@ -1,9 +1,9 @@ //! WIP Fun forcebot with catered customizations #todo //! //! Custom modules that can be managed in chat through `disable` and `enable` commands -//! - funbot -//! - guests -//! - pyramid +//! - `besty` +//! - `guests` +//! - `pyramid` //! //! //! Be sure the followig is defined in `.env` @@ -17,7 +17,10 @@ //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> -use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; +// use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; +use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot}; + + #[tokio::main] pub async fn main() { @@ -41,16 +44,17 @@ pub async fn main() { pub mod funbot_objs { use std::sync::Arc; - use forcebot_rs_v2::{execution_async, Badge, Bot, Command, Module}; + use forcebot_core::{execution_async, modules::Status, Badge, Bot, Command, Module}; use twitch_irc::message::ServerMessage; /// Create a Module with a loaded Command object pub fn create_module() -> Module { let mut custom_mod = Module::new( - vec!["funbot".to_string()], - "".to_string()); + vec!["besty".to_string()], + "Now Aware of besty xdd666 ".to_string()); custom_mod.load_command(create_cmd_test()); + custom_mod.set_status_by_default(Status::Disabled); custom_mod } @@ -73,6 +77,7 @@ pub mod funbot_objs { cmd.set_admin_only(false); cmd.set_min_badge(Badge::Vip); + cmd } diff --git a/src/bin/new_bot.rs b/forcebot_core/src/bin/new_bot.rs similarity index 95% rename from src/bin/new_bot.rs rename to forcebot_core/src/bin/new_bot.rs index cbe682b..4abdbc7 100644 --- a/src/bin/new_bot.rs +++ b/forcebot_core/src/bin/new_bot.rs @@ -10,7 +10,7 @@ //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> -use forcebot_rs_v2::Bot; +use forcebot_core::Bot; #[tokio::main] pub async fn main() { diff --git a/src/bin/simple_module.rs b/forcebot_core/src/bin/simple_module.rs similarity index 95% rename from src/bin/simple_module.rs rename to forcebot_core/src/bin/simple_module.rs index 77bd5da..02756d7 100644 --- a/src/bin/simple_module.rs +++ b/forcebot_core/src/bin/simple_module.rs @@ -17,7 +17,7 @@ //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> -use forcebot_rs_v2::Bot; +use forcebot_core::Bot; #[tokio::main] pub async fn main() { @@ -37,7 +37,7 @@ pub async fn main() { pub mod custom_mod { use std::sync::Arc; - use forcebot_rs_v2::{execution_async, Badge, Bot, Command, Module}; + use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use twitch_irc::message::ServerMessage; diff --git a/src/botcore.rs b/forcebot_core/src/botcore.rs similarity index 100% rename from src/botcore.rs rename to forcebot_core/src/botcore.rs diff --git a/src/botcore/bot.rs b/forcebot_core/src/botcore/bot.rs similarity index 96% rename from src/botcore/bot.rs rename to forcebot_core/src/botcore/bot.rs index f1a8798..96a66b6 100644 --- a/src/botcore/bot.rs +++ b/forcebot_core/src/botcore/bot.rs @@ -5,10 +5,16 @@ use twitch_irc::{login::StaticLoginCredentials, message::{PrivmsgMessage, Server use dotenv::dotenv; use std::{env, sync::Arc, time::{Duration, Instant}}; -use crate::{Badge, Command, Listener, Module}; +// use crate::{Badge, Command, Listener, Module}; +use super::bot_objects::command::Command; -use super::{bot_objects::built_in_objects, modules::{self, Status}}; +use crate::botcore::bot_objects::Badge; +use crate::botcore::bot_objects::listener::Listener; +use super::super::botcore::modules::Module; +// use super:: +use super:: {bot_objects::built_in_objects, modules::{self, Status}}; + /// Twitch chat bot pub struct Bot @@ -73,7 +79,7 @@ impl Bot /// Creates a new `Bot` using bot information /// - /// Bot joined channels will include channels from `.env` and `botchannels` argument + /// Bot will join `botchannels` argument pub fn new_from(bot_login_name:String,oauth_token:String,prefix:String,botchannels:Vec<String>) -> Bot { dotenv().ok(); @@ -90,10 +96,6 @@ impl Bot let mut botchannels_all = Vec::new(); botchannels_all.extend(botchannels); - for chnl in env::var("bot_channels").unwrap().split(',') { - botchannels_all.push(chnl.to_owned()); - } - let mut admins = Vec::new(); diff --git a/src/botcore/bot_objects.rs b/forcebot_core/src/botcore/bot_objects.rs similarity index 94% rename from src/botcore/bot_objects.rs rename to forcebot_core/src/botcore/bot_objects.rs index d5ae5b2..397d7fc 100644 --- a/src/botcore/bot_objects.rs +++ b/forcebot_core/src/botcore/bot_objects.rs @@ -105,8 +105,16 @@ pub mod built_in_objects { use std::{sync::Arc, time::{Duration, Instant}}; use twitch_irc::message::ServerMessage; + + use super::{execution_async,command::Command,Bot,Badge,super::modules::Status}; + + // use super::execution_async; + // use super::command::Command; + // use super::Bot; + // use super::Badge; + // use super::super::modules::Status; + // ::{execution_async, modules::Status, Badge, Bot, Command}; - use crate::{execution_async, modules::Status, Badge, Bot, Command}; /// create a vector of command build in objects @@ -146,14 +154,14 @@ pub mod built_in_objects { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(execution_async(execbody)); /* 4. optionally, remove admin only default flag */ cmd.set_admin_only(false); /* 5. optionally, set min badge*/ - cmd.set_min_badge(Badge::Moderator); + cmd.set_min_badge(Badge::Moderator /* ::Moderator */); cmd } @@ -201,7 +209,7 @@ pub mod built_in_objects { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(execution_async(execbody)); /* 4. optionally, remove admin only default flag */ @@ -304,7 +312,7 @@ pub mod built_in_objects { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(execution_async(execbody)); /* 4. optionally, remove admin only default flag */ diff --git a/src/botcore/bot_objects/command.rs b/forcebot_core/src/botcore/bot_objects/command.rs similarity index 97% rename from src/botcore/bot_objects/command.rs rename to forcebot_core/src/botcore/bot_objects/command.rs index 001ac31..54c4b85 100644 --- a/src/botcore/bot_objects/command.rs +++ b/forcebot_core/src/botcore/bot_objects/command.rs @@ -2,7 +2,9 @@ use std::sync::Arc; use twitch_irc::message::{PrivmsgMessage, ServerMessage}; -use crate::{botcore::bot::Bot, command_condition_async, execution_async, Badge}; +// use crate::{botcore::bot::Bot, command_condition_async, execution_async, Badge}; +use super::{execution_async,Bot,Badge,command_condition_async}; + use super::{CommandTrigger, ExecBody}; @@ -80,7 +82,7 @@ impl Command /// /* 2. define an async function */ /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// - /// /* 3. Set and Store the execution body using `async_box()` */ + /// /* 3. Set and Store the execution body using `execution_async()` */ /// cmd.set_custom_cond_async(condition_async(condition01)); /// ``` /// diff --git a/src/botcore/bot_objects/listener.rs b/forcebot_core/src/botcore/bot_objects/listener.rs similarity index 63% rename from src/botcore/bot_objects/listener.rs rename to forcebot_core/src/botcore/bot_objects/listener.rs index af96cf7..84bd468 100644 --- a/src/botcore/bot_objects/listener.rs +++ b/forcebot_core/src/botcore/bot_objects/listener.rs @@ -2,13 +2,22 @@ use std::sync::Arc; use twitch_irc::message::ServerMessage; -use crate::{execution_async, listener_condition_async, Bot}; - +use super::{execution_async,Bot,listener_condition_async}; + use super::{ExecBody, ListenerTrigger}; -/// Bot `Listener`` that stores trigger condition callback and a execution functon +/// Bot `Listener` that stores trigger condition callback and a execution functon /// -/// Use `asyncfn_box()` on custom async execution bodies +/// Use `Listener` functions to define the Trigger Condition & Execution callbacks. +/// When the Trigger callback is `true`, the Execution callback runs in the bot loop +/// +/// Create a new empty `Listener` with `new()` +/// +/// Use the following on the empty listener before loading it into the bot to set the callbacks +/// +/// - `set_trigger_cond_fn()` - to define the Trigger condition callback +/// +/// - `set_exec_fn()` - to define the Execution Callback #[derive(Clone)] pub struct Listener { @@ -23,14 +32,22 @@ pub struct Listener impl Listener { - /// Creates a new empty `Listener` . - /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks + /// Creates a new empty `Listener` + /// + /// Use `Listener` functions to define the Trigger Condition & Execution callbacks. + /// When the Trigger callback is `true`, the Execution callback runs in the bot loop + /// + /// Use the following on the empty listener before loading it into the bot to set the callbacks + /// + /// - `set_trigger_cond_fn()` - to define the Trigger condition callback + /// + /// - `set_exec_fn()` - to define the Execution Callback pub fn new() -> Listener { async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } Listener { - trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| false, + trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| true, trigger_cond_async : Arc::new(listener_condition_async(condition01)), exec_fn : Arc::new(execution_async(execbody)), } @@ -45,7 +62,7 @@ impl Listener /// /// Same as `set_trigger_cond_fn()` , but async define /// - /// Use`asyncfn_box()` on the async fn when storing + /// Use`condition_async()` on the async fn when storing /// /// Example - /// ```rust @@ -55,7 +72,7 @@ impl Listener /// /* 2. define an async function */ /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// - /// /* 3. Set and Store the execution body using `async_box()` */ + /// /* 3. Set and Store the execution body using `execution_async()` */ /// listener.set_trigger_cond_async(condition_async(condition01)); /// ``` /// @@ -66,7 +83,7 @@ impl Listener /// sets the execution body of the listener for when it triggers /// - /// Use`asyncfn_box()` on the async fn when storing + /// Use`execution_async()` on the async fn when storing /// /// Example - /// ```rust @@ -76,8 +93,8 @@ impl Listener /// /* 2. define an async function */ /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } /// - /// /* 3. Set and Store the execution body using `async_box()` */ - /// listener.set_exec_fn(asyncfn_box(execbody)); + /// /* 3. Set and Store the execution body using `execution_async()` */ + /// listener.set_exec_fn(execution_async(execbody)); /// ``` /// pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { diff --git a/src/botcore/modules.rs b/forcebot_core/src/botcore/modules.rs similarity index 91% rename from src/botcore/modules.rs rename to forcebot_core/src/botcore/modules.rs index 2ed44dc..9a30e41 100644 --- a/src/botcore/modules.rs +++ b/forcebot_core/src/botcore/modules.rs @@ -1,6 +1,7 @@ +use super::bot_objects::command::Command; +use super::bot_objects::listener::Listener; -use crate::{Command, Listener}; #[derive(PartialEq, Eq,Debug,Clone)] pub enum Status { @@ -33,7 +34,7 @@ impl Module bot_read_description, listeners: vec![], commands: vec![], - default_status_per_channel: Status::Disabled, + default_status_per_channel: Status::Enabled, } } diff --git a/src/custom_mods.rs b/forcebot_core/src/custom_mods.rs similarity index 100% rename from src/custom_mods.rs rename to forcebot_core/src/custom_mods.rs diff --git a/src/custom_mods/guest_badge.rs b/forcebot_core/src/custom_mods/guest_badge.rs similarity index 100% rename from src/custom_mods/guest_badge.rs rename to forcebot_core/src/custom_mods/guest_badge.rs diff --git a/src/custom_mods/pyramid.rs b/forcebot_core/src/custom_mods/pyramid.rs similarity index 73% rename from src/custom_mods/pyramid.rs rename to forcebot_core/src/custom_mods/pyramid.rs index fcc9da2..9b00db2 100644 --- a/src/custom_mods/pyramid.rs +++ b/forcebot_core/src/custom_mods/pyramid.rs @@ -4,7 +4,14 @@ use std::sync::{Arc, Mutex}; use twitch_irc::message::{PrivmsgMessage, ServerMessage}; -use crate::{listener_condition_async, Badge, Bot, Command, Listener, Module}; +// use crate::{execution_async, listener_condition_async, Badge, Bot, Command, Listener, Module}; +use super::super::botcore::bot_objects::execution_async; +use super::super::botcore::bot_objects::listener_condition_async; +use super::super::botcore::bot_objects::listener::Listener; +use super::super::botcore::modules::Module; +use super::super::botcore::bot::Bot; +use super::super::botcore::bot_objects::command::Command; +use super::super::botcore::bot_objects::Badge; /// pyramid module /// @@ -58,15 +65,15 @@ fn create_pyramid_detector() -> Listener { /* 4. Define an async fn callback execution */ async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { if let ServerMessage::Privmsg(msg) = message { - if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await { + // if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await { let _ = bot.client.say_in_reply_to(&msg, "Clap".to_string()).await ; return Result::Ok("Success".to_string()) ; - } + // } } Result::Err("Not Valid message type".to_string()) } - /* 5. Set and Store the execution body using `async_box()` */ + /* 5. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b)))); listener @@ -78,16 +85,17 @@ async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { let msgtext = msg.message_text.replace("\u{e0000}","").trim().to_string(); let msgchannel = msg.channel_login; + let msgchatter = msg.sender.login; // 1. Check if Pyramid started in chat > and recognize pyramid started if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) { set_pyramid_started(msgchannel.clone(),true); - push_to_compare(msgchannel.clone(),get_start_pattern(msgchannel.clone())); + push_to_compare(msgchannel.clone(),msgchatter.clone(),get_start_pattern(msgchannel.clone())); } if is_pyramid_started(msgchannel.clone()) { - push_to_compare(msgchannel.clone(),msgtext.clone()); + push_to_compare(msgchannel.clone(),msgchatter.clone(),msgtext.clone()); } // 2a. If Pyramid Not Started, Assume message is a potential start pattern @@ -111,8 +119,8 @@ async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { lazy_static!{ - /// Message Compare stack per channel (channel:String,msgstack:Vec<String>) - pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<String>>)>> = Mutex::new(vec![]); + /// Message Compare stack per channel (channel:String,msgstack:Vec<(chatter:String,message:String)>) + pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>> = Mutex::new(vec![]); #[derive(Debug)] /// Pyramid Started per channel (channel:String,started:bool) pub static ref PYRAMID_STARTED_PER_CHNL: Mutex<Vec<(String,Mutex<bool>)>> = Mutex::new(vec![]); @@ -126,7 +134,7 @@ lazy_static!{ } -fn read_top_of_compare(channel:String) -> Option<String> { +fn read_top_of_compare(channel:String) -> Option<(String,String)> { let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); @@ -142,7 +150,7 @@ fn read_top_of_compare(channel:String) -> Option<String> { } -fn pop_top_of_compare(channel:String) -> Option<String> { +fn pop_top_of_compare(channel:String) -> Option<(String,String)> { let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); for rec in comp_perchnl.iter() { @@ -218,7 +226,7 @@ fn get_start_pattern(channel:String) -> String { /// pushes message to compare stack -fn push_to_compare(channel:String,message:String) { +fn push_to_compare(channel:String,chatter:String,message:String) { let mut comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); let mut found = false; @@ -226,12 +234,12 @@ fn push_to_compare(channel:String,message:String) { if rec.0 == channel { found = true; let mut msg_stack = rec.1.lock().unwrap(); - msg_stack.push(message.clone()); + msg_stack.push((chatter.clone(),message.clone())); // dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last()); } } if !found { - comp_perchnl.push((channel,Mutex::new(vec![message]))); + comp_perchnl.push((channel,Mutex::new(vec![(chatter,message)]))); } } @@ -247,21 +255,21 @@ fn check_start_pyramid(channel:String,msgtext: String) -> bool { fn symmetry_ok(channel:String) -> bool { let mut temp_stack = TEMP_MSG_STACK.lock().unwrap(); let mut checking_started = false; - if !(read_top_of_compare(channel.clone()).unwrap_or("".to_string()) == get_start_pattern(channel.clone())) { + if !(read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone())) { return false; } loop { - if !checking_started && read_top_of_compare(channel.clone()).unwrap_or("".to_string()) == get_start_pattern(channel.clone()) { + if !checking_started && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone()) { checking_started = true; } - if temp_stack.last().is_none() || read_top_of_compare(channel.clone()).unwrap_or("".to_string()).len() > temp_stack.last().unwrap_or(&"".to_string()).len() { - temp_stack.push(pop_top_of_compare(channel.clone()).unwrap_or("".to_string())); + if temp_stack.last().is_none() || read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() > temp_stack.last().unwrap_or(&"".to_string()).len() { + temp_stack.push(pop_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1); - } else if temp_stack.last().is_some() && read_top_of_compare(channel.clone()).unwrap_or("".to_string()).len() < temp_stack.last().unwrap_or(&"".to_string()).len() { + } else if temp_stack.last().is_some() && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() < temp_stack.last().unwrap_or(&"".to_string()).len() { temp_stack.pop(); - if temp_stack.last().unwrap_or(&"".to_string()).clone() == read_top_of_compare(channel.clone()).unwrap_or("".to_string()) { + if temp_stack.last().unwrap_or(&"".to_string()).clone() == read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 { temp_stack.pop(); continue; @@ -272,7 +280,7 @@ fn symmetry_ok(channel:String) -> bool { } } else { /* dbg!("failed catchall"); */ return false; } - if checking_started && read_top_of_compare(channel.clone()).unwrap() == get_start_pattern(channel.clone()) { + if checking_started && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone()) { temp_stack.clear(); return true; @@ -284,7 +292,9 @@ fn symmetry_ok(channel:String) -> bool { } -/// pyramid interruptor #todo +/// #todo +/// +/// pyramid interruptor /// /// pick chatters that will be interrupted if they solo build /// @@ -311,7 +321,7 @@ fn create_interruptor_cmd() -> Command { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b)))); /* 4. optionally, remove admin only default flag */ @@ -324,5 +334,47 @@ fn create_interruptor_cmd() -> Command { cmd } +/// #todo +fn create_interruptor_module(channel:String) -> Module { + /* 1. Create a new module */ + let modname = format!("interruptor {}",channel); + let mut custom_mod = Module::new( + vec![modname], + "".to_string()); + /* 2. Load the cmd into a new module */ + custom_mod.load_listener(create_interruptor_listener()); + custom_mod + +} + +/// #todo +fn create_interruptor_listener() -> Listener { + /* 2a. Create a new blank Listener */ + let mut listener = Listener::new(); + + /* 2b. Set a trigger condition function for listener */ + listener.set_trigger_cond_fn( + |_:Arc<Bot>,_:ServerMessage| true + ); + + /* 2c. Define an async fn callback execution */ + async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + dbg!(message); + Result::Ok("Success".to_string()) + } + + /* 2d. Set and Store the execution body using `execution_async()` */ + listener.set_exec_fn(execution_async(execbody)); + + listener + +} + +/// #todo +/// +/// Returns Some(chatter) if the pyramid in progress is being built by a solo +fn solo_building(channel:String) -> Option<String> { + None +} diff --git a/src/lib.rs b/forcebot_core/src/lib.rs similarity index 85% rename from src/lib.rs rename to forcebot_core/src/lib.rs index 817caac..8ccc272 100644 --- a/src/lib.rs +++ b/forcebot_core/src/lib.rs @@ -1,4 +1,4 @@ -//! `forcebot-rs-v2` : Twitch chat bot written in rust. +//! `forcebot_core` library for `forcebot-rs-v2` Twitch chat bot //! //! Customize by adding additional bot objects //! @@ -7,7 +7,7 @@ //! Uses Env defined variables to create and run the bot //! //! ```rust -//! use forcebot_rs_v2::Bot; +//! use forcebot_core::Bot; //! //! #[tokio::main] //! pub async fn main() { @@ -27,11 +27,10 @@ //! //! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands //! -//! //! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot //! //! ```rust -//! use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; +//! use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot}; //! //! #[tokio::main] //! pub async fn main() { @@ -60,7 +59,7 @@ //! //! //! ```rust -//! use forcebot_rs_v2::Bot; +//! use forcebot_core::Bot; //! //! #[tokio::main] //! pub async fn main() { @@ -79,7 +78,7 @@ //! pub mod custom_mod { //! use std::sync::Arc; //! -//! use forcebot_rs_v2::{execution_async, Badge, Bot, Command, Module}; +//! use forcebot_core::{execution_async, Badge, Bot, Command, Module}; //! use twitch_irc::message::ServerMessage; //! //! @@ -129,7 +128,7 @@ //! ```rust //! use std::sync::Arc; //! -//! use forcebot_rs_v2::{execution_async, Bot, Listener}; +//! use forcebot_core::{execution_async, Bot, Listener}; //! use twitch_irc::message::ServerMessage; //! //! #[tokio::main] @@ -152,7 +151,7 @@ //! Result::Ok("Success".to_string()) //! } //! -//! /* 2d. Set and Store the execution body using `async_box()` */ +//! /* 2d. Set and Store the execution body using `execution_async()` */ //! listener.set_exec_fn(execution_async(execbody)); //! //! /* 3. Load the listener into the bot */ @@ -171,9 +170,9 @@ //! //! use std::sync::Arc; //! -//! use forcebot_rs_v2::Bot; -//! use forcebot_rs_v2::execution_async; -//! use forcebot_rs_v2::Listener; +//! use forcebot_core::Bot; +//! use forcebot_core::execution_async; +//! use forcebot_core::Listener; //! use twitch_irc::message::ServerMessage; //! //! @@ -211,7 +210,7 @@ //! Result::Err("Not Valid message type".to_string()) //! } //! -//! /* 4. Set and Store the execution body using `async_box()` */ +//! /* 4. Set and Store the execution body using `execution_async()` */ //! listener.set_exec_fn(execution_async(execbody)); //! //! /* 5. Load the listener into the bot */ @@ -226,12 +225,13 @@ pub mod botcore; pub mod custom_mods; -pub use crate::botcore::bot::Bot; -pub use crate::botcore::bot_objects::execution_async; -pub use crate::botcore::bot_objects::command_condition_async; -pub use crate::botcore::bot_objects::listener_condition_async; -pub use crate::botcore::bot_objects::listener::Listener; -pub use crate::botcore::bot_objects::command::Command; -pub use crate::botcore::modules::Module; -pub use crate::botcore::bot_objects::Badge; -pub use crate::botcore::modules; +pub use botcore::bot::Bot; +pub use botcore::bot_objects::execution_async; +pub use botcore::bot_objects::command_condition_async; +pub use botcore::bot_objects::listener_condition_async; +pub use botcore::bot_objects::listener::Listener; +// pub use crate::botcore::bot_objects::command::Command; +pub use botcore::bot_objects::command::Command; +pub use botcore::modules::Module; +pub use botcore::bot_objects::Badge; +pub use botcore::modules; diff --git a/moderator_reactor/Cargo.toml b/moderator_reactor/Cargo.toml new file mode 100644 index 0000000..f3431e6 --- /dev/null +++ b/moderator_reactor/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "moderator_reactor" +version = "0.1.0" +edition = "2021" + +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/src/bin/moderator_reactor.rs b/moderator_reactor/src/main.rs similarity index 91% rename from src/bin/moderator_reactor.rs rename to moderator_reactor/src/main.rs index 279d204..58c0c9f 100644 --- a/src/bin/moderator_reactor.rs +++ b/moderator_reactor/src/main.rs @@ -13,9 +13,9 @@ use std::sync::Arc; -use forcebot_rs_v2::Bot; -use forcebot_rs_v2::execution_async; -use forcebot_rs_v2::Listener; +use forcebot_core::Bot; +use forcebot_core::execution_async; +use forcebot_core::Listener; use twitch_irc::message::ServerMessage; @@ -53,7 +53,7 @@ pub async fn main() { Result::Err("Not Valid message type".to_string()) } - /* 4. Set and Store the execution body using `async_box()` */ + /* 4. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(execution_async(execbody)); /* 5. Load the listener into the bot */ diff --git a/new_empty_bot/Cargo.toml b/new_empty_bot/Cargo.toml new file mode 100644 index 0000000..96d5d3f --- /dev/null +++ b/new_empty_bot/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "new_empty_bot" +version = "0.1.0" +edition = "2021" + +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/src/main.rs b/new_empty_bot/src/main.rs similarity index 93% rename from src/main.rs rename to new_empty_bot/src/main.rs index ebbe171..4abdbc7 100644 --- a/src/main.rs +++ b/new_empty_bot/src/main.rs @@ -10,8 +10,7 @@ //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> -use forcebot_rs_v2::botcore::bot::Bot; - +use forcebot_core::Bot; #[tokio::main] pub async fn main() { diff --git a/readme.md b/readme.md index 6af83e2..d94791a 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -Twitch chat bot written in rust +Customizable Twitch chat bot written in rust # Quick Start @@ -22,28 +22,47 @@ bot_admins=ADMIN 3. Build & run ``` -cargo run +cargo run -p forcebot_core ``` +# Features + +- Quick Start to use full feature set bot +- Moderators & Broadcasters can `disable` or `enable` `Modules` of bot functionality through chat `Commands` +- Full Feature Set `forcebot_core` bot has the following modules loaded + - `guest_badge` - Temporary badges can be issued to chatters + - `besty` - Tomfoolery + - `pyramid` - for detecting & handling pyramids +- `forcebot_core` library API provides Custom package developers a way to add functionality by adding `Modules` that contain Bot Objects like `Commands` and `Listeners` +- `Listeners` and `Commands` listen for a defined callback trigger condition and run an defined execution callback +- `Commands` are similar to `Listeners` with refined trigger conditions including using bot `prefix` with the `Command` , triggers based on `Badge` , and more +- Workspace for package developers to independently code their own `Modules` +- Workspace comes with binary crates with working or example bots that use `forcebot_core` library + - `moderator_reactor` - bot kneels to all moderator messages + - `simple_module_example` - bot has a `test` `Module` with a `test` `Command` .Moderators & Broadcasters can manage the `Module` in chat with `enable` / `disable` `Commands` + - `new_empty_bot` - while empty, has `disable` and `enable` chat `Commands` . This is an example of the bot without any loaded modules + - `simple_command_bot` - bot responds to a `test` `Command`. As the command was not loaded through a `Module`, `disable` & `enable` commands don't work on the `test` command. This could be a Global `Command` + - `simple_debug_listener` - bot outputs all twitch `ServerMessages` received to terminal + + + # Example Bots -Use the following commands to build and run built-in bots. No coding required! +Use the following to build and run built-in bots. No coding required! -## New Bot +## New Empty Bot Run an empty simple bot that logs into chat and has minimum built in functions ``` -cargo run --bin new_bot +cargo run -p new_empty_bot ``` -## WIP Customized Fun Bot +## Full Featured Forcebot Run a forcebot with fun catered customizations -*ongoing work in progress* - ``` -cargo run --bin fun_bot +cargo run -p forcebot_core ``` @@ -51,28 +70,69 @@ cargo run --bin fun_bot Run a bot that listens to all messages and output to console ``` -cargo run --bin simple_debug_listener +cargo run -p simple_debug_listener ``` ## Simple Command Bot Run a bot that uses the `test` chat `Command` . `Commands` are prefixed and must be ran by a chatter with a `vip` badge or above ``` -cargo run --bin simple_command_bot +cargo run -p simple_command_bot ``` ## Moderator Reactor Run a bot that listens for messages with the `moderator` badge, and replies to that mod with an emote ``` -cargo run --bin moderator_reactor +cargo run -p moderator_reactor ``` ## Module loaded Bot Run a bot that has a `test` chat `Command`. As the command was loaded through a module, moderators or broadcastors can `enable` or `disable` the module through chat commands ``` -cargo run --bin simple_module +cargo run -p simple_module_example +``` + +# Workspace packages + +Source is a workspace of packages . In particular, `forcebot_core` is the main library crate to use + +*TIP* : if you want to start customizing you own bot, create a binary package in the workspace for your bot's binary crate + +More info about workspaces - https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html + + +## Creating a new package + +To create a new package + +1. Create a new package + +For example, to create a new binary crate in the workspace + +``` +cargo new my_new_bot +``` + +2. In the newly created directory for your package, adjust the `Cargo.toml` to the following + +``` +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" +``` + +3. Copy `main.rs` from the `new_empty_bot` package into your package + +4. Optionally, customize your `main()` to load modules before starting the bot + +5. Build and run your package +``` +cargo run -p my_new_bot ``` @@ -83,7 +143,7 @@ cargo run --bin simple_module Uses Env defined variables to create and run the bot ```rust -use forcebot_rs_v2::Bot; +use forcebot_core::Bot; #[tokio::main] pub async fn main() { @@ -95,7 +155,6 @@ pub async fn main() { bot.run().await; } - ``` ## Customize by Loading Custom Modules @@ -105,7 +164,8 @@ A `Module` is a group of bot objects (eg `Command`) that elevated users can mana Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot ```rust -use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; +use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot}; + #[tokio::main] pub async fn main() { @@ -134,7 +194,7 @@ Create a custom `Module` by : ```rust -use forcebot_rs_v2::Bot; +use forcebot_core::Bot; #[tokio::main] pub async fn main() { @@ -153,7 +213,7 @@ pub async fn main() { pub mod custom_mod { use std::sync::Arc; - use forcebot_rs_v2::{execution_async, Badge, Bot, Command, Module}; + use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use twitch_irc::message::ServerMessage; @@ -193,7 +253,6 @@ pub mod custom_mod { cmd } } - ``` ## Simple Debug Listener @@ -202,7 +261,7 @@ Bot with a simple listener that listens for all messages and prints in output ```rust use std::sync::Arc; -use forcebot_rs_v2::{execution_async, Bot, Listener}; +use forcebot_core::{execution_async, Bot, Listener}; use twitch_irc::message::ServerMessage; #[tokio::main] @@ -225,7 +284,7 @@ pub async fn main() { Result::Ok("Success".to_string()) } - /* 2d. Set and Store the execution body using `async_box()` */ + /* 2d. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(execution_async(execbody)); /* 3. Load the listener into the bot */ @@ -235,7 +294,6 @@ pub async fn main() { bot.run().await; } - ``` ## Moderator Reactor @@ -243,12 +301,11 @@ pub async fn main() { Example listener listens for a moderator badge and reply in chat ```rust - use std::sync::Arc; -use forcebot_rs_v2::Bot; -use forcebot_rs_v2::execution_async; -use forcebot_rs_v2::Listener; +use forcebot_core::Bot; +use forcebot_core::execution_async; +use forcebot_core::Listener; use twitch_irc::message::ServerMessage; @@ -286,7 +343,7 @@ pub async fn main() { Result::Err("Not Valid message type".to_string()) } - /* 4. Set and Store the execution body using `async_box()` */ + /* 4. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(execution_async(execbody)); /* 5. Load the listener into the bot */ @@ -296,9 +353,6 @@ pub async fn main() { bot.run().await; } - - - ``` ## Simple Test Command @@ -306,13 +360,12 @@ pub async fn main() { ```rust use std::sync::Arc; -use forcebot_rs_v2::Badge; -use forcebot_rs_v2::Bot; -use forcebot_rs_v2::execution_async; -use forcebot_rs_v2::Command; +use forcebot_core::Badge; +use forcebot_core::Bot; +use forcebot_core::execution_async; +use forcebot_core::Command; use twitch_irc::message::ServerMessage; - #[tokio::main] pub async fn main() { @@ -331,7 +384,7 @@ pub async fn main() { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(execution_async(execbody)); /* 4. optionally, remove admin only default flag */ @@ -347,11 +400,9 @@ pub async fn main() { bot.run().await; } - - ``` -# Crate Rust Documentation +# Crate Rust API Documentation Create `forcebot_rs_v2` Rust Crate documentation diff --git a/simple_command_bot/Cargo.toml b/simple_command_bot/Cargo.toml new file mode 100644 index 0000000..25f2f0f --- /dev/null +++ b/simple_command_bot/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "simple_command_bot" +version = "0.1.0" +edition = "2021" + +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/src/bin/simple_command_bot.rs b/simple_command_bot/src/main.rs similarity index 88% rename from src/bin/simple_command_bot.rs rename to simple_command_bot/src/main.rs index 9c2f2ff..2f29e09 100644 --- a/src/bin/simple_command_bot.rs +++ b/simple_command_bot/src/main.rs @@ -15,10 +15,10 @@ use std::sync::Arc; -use forcebot_rs_v2::Badge; -use forcebot_rs_v2::Bot; -use forcebot_rs_v2::execution_async; -use forcebot_rs_v2::Command; +use forcebot_core::Badge; +use forcebot_core::Bot; +use forcebot_core::execution_async; +use forcebot_core::Command; use twitch_irc::message::ServerMessage; @@ -40,7 +40,7 @@ pub async fn main() { Result::Err("Not Valid message type".to_string()) } - /* 3. Set and Store the execution body using `async_box()` */ + /* 3. Set and Store the execution body using `execution_async()` */ cmd.set_exec_fn(execution_async(execbody)); /* 4. optionally, remove admin only default flag */ diff --git a/simple_debug_listener/Cargo.toml b/simple_debug_listener/Cargo.toml new file mode 100644 index 0000000..fceb717 --- /dev/null +++ b/simple_debug_listener/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "simple_debug_listener" +version = "0.1.0" +edition = "2021" + +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/src/bin/simple_debug_listener.rs b/simple_debug_listener/src/main.rs similarity index 90% rename from src/bin/simple_debug_listener.rs rename to simple_debug_listener/src/main.rs index 791c5d0..3ce82fc 100644 --- a/src/bin/simple_debug_listener.rs +++ b/simple_debug_listener/src/main.rs @@ -12,7 +12,7 @@ use std::sync::Arc; -use forcebot_rs_v2::{execution_async, Bot, Listener}; +use forcebot_core::{execution_async, Bot, Listener}; use twitch_irc::message::ServerMessage; #[tokio::main] @@ -35,7 +35,7 @@ pub async fn main() { Result::Ok("Success".to_string()) } - /* 2d. Set and Store the execution body using `async_box()` */ + /* 2d. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(execution_async(execbody)); /* 3. Load the listener into the bot */ diff --git a/simple_module_example/Cargo.toml b/simple_module_example/Cargo.toml new file mode 100644 index 0000000..b00ba0b --- /dev/null +++ b/simple_module_example/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "simple_module_example" +version = "0.1.0" +edition = "2021" + +[dependencies] +forcebot_core = {path = "../forcebot_core"} +dotenv = "0.15.0" +lazy_static = "1.5.0" +tokio = { version = "1.33.0", features = ["full"] } +twitch-irc = "5.0.1" diff --git a/simple_module_example/src/main.rs b/simple_module_example/src/main.rs new file mode 100644 index 0000000..4793ed4 --- /dev/null +++ b/simple_module_example/src/main.rs @@ -0,0 +1,79 @@ +//! Simple Module with a Command +//! +//! Adding objects through packages provides controls , +//! such as moderators, and brodcasters can disable or enable mods +//! +//! Here, moderators or above can enable or disable the `test` +//! module with the command `<prefix> disable test` +//! +//! Be sure the followig is defined in `.env` +//! - login_name +//! - access_token +//! - bot_channels +//! - prefix +//! - bot_admins +//! +//! Bot access tokens be generated here - +//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> +//! - More Info - <https://dev.twitch.tv/docs/authentication> + +use forcebot_core::Bot; + +#[tokio::main] +pub async fn main() { + + /* Create the bot using env */ + let mut bot = Bot::new(); + + /* load the Module */ + bot.load_module(custom_mod::new()).await; + + /* Run the bot */ + bot.run().await; + +} + + +pub mod custom_mod { + use std::sync::Arc; + + use forcebot_core::{execution_async, Badge, Bot, Command, Module}; + use twitch_irc::message::ServerMessage; + + + /// Module definition with a loaded command + pub fn new() -> Module { + /* 1. Create a new module */ + let mut custom_mod = Module::new( + vec!["test".to_string()], + "".to_string()); + + /* 2. Load the cmd into a new module */ + custom_mod.load_command(cmd_test()); + + custom_mod + + } + + /// Command definition + pub fn cmd_test() -> Command { + /* 1. Create a new cmd */ + let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); + + /* 2. Define exec callback */ + async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + if let ServerMessage::Privmsg(msg) = message { + let _= bot.client.say_in_reply_to( + &msg, "test return".to_string()).await; + } + Result::Err("Not Valid message type".to_string()) + } + + /* 3. Set Command flags */ + cmd.set_exec_fn(execution_async(execbody)); + cmd.set_admin_only(false); + cmd.set_min_badge(Badge::Vip); + + cmd + } +} \ No newline at end of file