reorg workspaces

This commit is contained in:
modulatingforce 2025-02-02 08:17:38 -05:00
parent 2a6b512ce1
commit 46cff68bc1
27 changed files with 519 additions and 180 deletions

120
Cargo.lock generated
View file

@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.85" version = "0.1.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -63,9 +63,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.10" version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@ -142,7 +142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]] [[package]]
name = "forcebot-rs-v2" name = "forcebot_core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dotenv", "dotenv",
@ -200,13 +200,14 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi", "wasi 0.13.3+wasi-0.2.2",
"windows-targets",
] ]
[[package]] [[package]]
@ -271,15 +272,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "moderator_reactor"
version = "0.1.0"
dependencies = [
"dotenv",
"forcebot_core",
"lazy_static",
"tokio",
"twitch-irc",
]
[[package]] [[package]]
name = "native-tls" name = "native-tls"
version = "0.2.12" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@ -292,6 +304,17 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "new_empty_bot"
version = "0.1.0"
dependencies = [
"dotenv",
"forcebot_core",
"lazy_static",
"tokio",
"twitch-irc",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@ -318,9 +341,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.68" version = "0.10.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -344,9 +367,9 @@ dependencies = [
[[package]] [[package]]
name = "openssl-probe" name = "openssl-probe"
version = "0.1.5" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
@ -436,9 +459,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.43" version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -500,6 +523,39 @@ dependencies = [
"libc", "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]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -527,9 +583,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.96" version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -538,9 +594,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.15.0" version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -687,9 +743,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.14" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
@ -703,6 +759,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
@ -784,3 +849,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 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",
]

View file

@ -1,24 +1,7 @@
[package] [workspace]
name = "forcebot-rs-v2" members = [
version = "0.1.0" "forcebot_core",
edition = "2021" "simple_module_example",
default-run = "forcebot-rs-v2" "new_empty_bot",
"simple_debug_listener",
[dependencies] "moderator_reactor", "simple_command_bot"]
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"

11
forcebot_core/Cargo.toml Normal file
View file

@ -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"

View file

@ -1,9 +1,9 @@
//! WIP Fun forcebot with catered customizations #todo //! WIP Fun forcebot with catered customizations #todo
//! //!
//! Custom modules that can be managed in chat through `disable` and `enable` commands //! Custom modules that can be managed in chat through `disable` and `enable` commands
//! - funbot //! - `besty`
//! - guests //! - `guests`
//! - pyramid //! - `pyramid`
//! //!
//! //!
//! Be sure the followig is defined in `.env` //! Be sure the followig is defined in `.env`
@ -17,7 +17,10 @@
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - 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] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -41,16 +44,17 @@ pub async fn main() {
pub mod funbot_objs { pub mod funbot_objs {
use std::sync::Arc; 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; use twitch_irc::message::ServerMessage;
/// Create a Module with a loaded Command object /// Create a Module with a loaded Command object
pub fn create_module() -> Module { pub fn create_module() -> Module {
let mut custom_mod = Module::new( let mut custom_mod = Module::new(
vec!["funbot".to_string()], vec!["besty".to_string()],
"".to_string()); "Now Aware of besty xdd666 ".to_string());
custom_mod.load_command(create_cmd_test()); custom_mod.load_command(create_cmd_test());
custom_mod.set_status_by_default(Status::Disabled);
custom_mod custom_mod
} }
@ -73,6 +77,7 @@ pub mod funbot_objs {
cmd.set_admin_only(false); cmd.set_admin_only(false);
cmd.set_min_badge(Badge::Vip); cmd.set_min_badge(Badge::Vip);
cmd cmd
} }

View file

@ -10,7 +10,7 @@
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {

View file

@ -17,7 +17,7 @@
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -37,7 +37,7 @@ pub async fn main() {
pub mod custom_mod { pub mod custom_mod {
use std::sync::Arc; 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; use twitch_irc::message::ServerMessage;

View file

@ -5,10 +5,16 @@ use twitch_irc::{login::StaticLoginCredentials, message::{PrivmsgMessage, Server
use dotenv::dotenv; use dotenv::dotenv;
use std::{env, sync::Arc, time::{Duration, Instant}}; 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 /// Twitch chat bot
pub struct Bot pub struct Bot
@ -73,7 +79,7 @@ impl Bot
/// Creates a new `Bot` using bot information /// 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 { pub fn new_from(bot_login_name:String,oauth_token:String,prefix:String,botchannels:Vec<String>) -> Bot {
dotenv().ok(); dotenv().ok();
@ -90,10 +96,6 @@ impl Bot
let mut botchannels_all = Vec::new(); let mut botchannels_all = Vec::new();
botchannels_all.extend(botchannels); botchannels_all.extend(botchannels);
for chnl in env::var("bot_channels").unwrap().split(',') {
botchannels_all.push(chnl.to_owned());
}
let mut admins = Vec::new(); let mut admins = Vec::new();

View file

@ -105,8 +105,16 @@ pub mod built_in_objects {
use std::{sync::Arc, time::{Duration, Instant}}; use std::{sync::Arc, time::{Duration, Instant}};
use twitch_irc::message::ServerMessage; 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 /// 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()) 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)); cmd.set_exec_fn(execution_async(execbody));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */
cmd.set_admin_only(false); cmd.set_admin_only(false);
/* 5. optionally, set min badge*/ /* 5. optionally, set min badge*/
cmd.set_min_badge(Badge::Moderator); cmd.set_min_badge(Badge::Moderator /* ::Moderator */);
cmd cmd
} }
@ -201,7 +209,7 @@ pub mod built_in_objects {
Result::Err("Not Valid message type".to_string()) 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)); cmd.set_exec_fn(execution_async(execbody));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */
@ -304,7 +312,7 @@ pub mod built_in_objects {
Result::Err("Not Valid message type".to_string()) 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)); cmd.set_exec_fn(execution_async(execbody));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */

View file

@ -2,7 +2,9 @@ use std::sync::Arc;
use twitch_irc::message::{PrivmsgMessage, ServerMessage}; 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}; use super::{CommandTrigger, ExecBody};
@ -80,7 +82,7 @@ impl Command
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// 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)); /// cmd.set_custom_cond_async(condition_async(condition01));
/// ``` /// ```
/// ///

View file

@ -2,13 +2,22 @@ use std::sync::Arc;
use twitch_irc::message::ServerMessage; 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}; 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)] #[derive(Clone)]
pub struct Listener pub struct Listener
{ {
@ -23,14 +32,22 @@ pub struct Listener
impl Listener impl Listener
{ {
/// Creates a new empty `Listener` . /// Creates a new empty `Listener`
/// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks ///
/// 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 { pub fn new() -> Listener {
async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true }
Listener { Listener {
trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| false, trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| true,
trigger_cond_async : Arc::new(listener_condition_async(condition01)), trigger_cond_async : Arc::new(listener_condition_async(condition01)),
exec_fn : Arc::new(execution_async(execbody)), exec_fn : Arc::new(execution_async(execbody)),
} }
@ -45,7 +62,7 @@ impl Listener
/// ///
/// Same as `set_trigger_cond_fn()` , but async define /// 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 - /// Example -
/// ```rust /// ```rust
@ -55,7 +72,7 @@ impl Listener
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } /// 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)); /// 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 /// 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 - /// Example -
/// ```rust /// ```rust
@ -76,8 +93,8 @@ impl Listener
/// /* 2. define an async function */ /// /* 2. define an async function */
/// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) }
/// ///
/// /* 3. Set and Store the execution body using `async_box()` */ /// /* 3. Set and Store the execution body using `execution_async()` */
/// listener.set_exec_fn(asyncfn_box(execbody)); /// listener.set_exec_fn(execution_async(execbody));
/// ``` /// ```
/// ///
pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) {

View file

@ -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)] #[derive(PartialEq, Eq,Debug,Clone)]
pub enum Status { pub enum Status {
@ -33,7 +34,7 @@ impl Module
bot_read_description, bot_read_description,
listeners: vec![], listeners: vec![],
commands: vec![], commands: vec![],
default_status_per_channel: Status::Disabled, default_status_per_channel: Status::Enabled,
} }
} }

View file

@ -4,7 +4,14 @@ use std::sync::{Arc, Mutex};
use twitch_irc::message::{PrivmsgMessage, ServerMessage}; 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 /// pyramid module
/// ///
@ -58,15 +65,15 @@ fn create_pyramid_detector() -> Listener {
/* 4. Define an async fn callback execution */ /* 4. Define an async fn callback execution */
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
if let ServerMessage::Privmsg(msg) = message { 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 ; let _ = bot.client.say_in_reply_to(&msg, "Clap".to_string()).await ;
return Result::Ok("Success".to_string()) ; return Result::Ok("Success".to_string()) ;
} // }
} }
Result::Err("Not Valid message type".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.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b))));
listener 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 msgtext = msg.message_text.replace("\u{e0000}","").trim().to_string();
let msgchannel = msg.channel_login; let msgchannel = msg.channel_login;
let msgchatter = msg.sender.login;
// 1. Check if Pyramid started in chat > and recognize pyramid started // 1. Check if Pyramid started in chat > and recognize pyramid started
if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) { if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) {
set_pyramid_started(msgchannel.clone(),true); 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()) { 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 // 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!{ lazy_static!{
/// Message Compare stack per channel (channel:String,msgstack:Vec<String>) /// 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>>)>> = Mutex::new(vec![]); pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>> = Mutex::new(vec![]);
#[derive(Debug)] #[derive(Debug)]
/// Pyramid Started per channel (channel:String,started:bool) /// Pyramid Started per channel (channel:String,started:bool)
pub static ref PYRAMID_STARTED_PER_CHNL: Mutex<Vec<(String,Mutex<bool>)>> = Mutex::new(vec![]); 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(); 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(); let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
for rec in comp_perchnl.iter() { for rec in comp_perchnl.iter() {
@ -218,7 +226,7 @@ fn get_start_pattern(channel:String) -> String {
/// pushes message to compare stack /// 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 comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap();
let mut found = false; let mut found = false;
@ -226,12 +234,12 @@ fn push_to_compare(channel:String,message:String) {
if rec.0 == channel { if rec.0 == channel {
found = true; found = true;
let mut msg_stack = rec.1.lock().unwrap(); 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()); // dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last());
} }
} }
if !found { 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 { fn symmetry_ok(channel:String) -> bool {
let mut temp_stack = TEMP_MSG_STACK.lock().unwrap(); let mut temp_stack = TEMP_MSG_STACK.lock().unwrap();
let mut checking_started = false; 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; return false;
} }
loop { 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; 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() { 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())); 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(); 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(); temp_stack.pop();
continue; continue;
@ -272,7 +280,7 @@ fn symmetry_ok(channel:String) -> bool {
} }
} else { /* dbg!("failed catchall"); */ return false; } } 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(); temp_stack.clear();
return true; 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 /// 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()) 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)))); cmd.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b))));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */
@ -324,5 +334,47 @@ fn create_interruptor_cmd() -> Command {
cmd 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
}

View file

@ -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 //! Customize by adding additional bot objects
//! //!
@ -7,7 +7,7 @@
//! Uses Env defined variables to create and run the bot //! Uses Env defined variables to create and run the bot
//! //!
//! ```rust //! ```rust
//! use forcebot_rs_v2::Bot; //! use forcebot_core::Bot;
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn 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 //! 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 //! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
//! //!
//! ```rust //! ```rust
//! use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; //! use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot};
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn main() { //! pub async fn main() {
@ -60,7 +59,7 @@
//! //!
//! //!
//! ```rust //! ```rust
//! use forcebot_rs_v2::Bot; //! use forcebot_core::Bot;
//! //!
//! #[tokio::main] //! #[tokio::main]
//! pub async fn main() { //! pub async fn main() {
@ -79,7 +78,7 @@
//! pub mod custom_mod { //! pub mod custom_mod {
//! use std::sync::Arc; //! 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; //! use twitch_irc::message::ServerMessage;
//! //!
//! //!
@ -129,7 +128,7 @@
//! ```rust //! ```rust
//! use std::sync::Arc; //! use std::sync::Arc;
//! //!
//! use forcebot_rs_v2::{execution_async, Bot, Listener}; //! use forcebot_core::{execution_async, Bot, Listener};
//! use twitch_irc::message::ServerMessage; //! use twitch_irc::message::ServerMessage;
//! //!
//! #[tokio::main] //! #[tokio::main]
@ -152,7 +151,7 @@
//! Result::Ok("Success".to_string()) //! 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)); //! listener.set_exec_fn(execution_async(execbody));
//! //!
//! /* 3. Load the listener into the bot */ //! /* 3. Load the listener into the bot */
@ -171,9 +170,9 @@
//! //!
//! use std::sync::Arc; //! use std::sync::Arc;
//! //!
//! use forcebot_rs_v2::Bot; //! use forcebot_core::Bot;
//! use forcebot_rs_v2::execution_async; //! use forcebot_core::execution_async;
//! use forcebot_rs_v2::Listener; //! use forcebot_core::Listener;
//! use twitch_irc::message::ServerMessage; //! use twitch_irc::message::ServerMessage;
//! //!
//! //!
@ -211,7 +210,7 @@
//! Result::Err("Not Valid message type".to_string()) //! 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)); //! listener.set_exec_fn(execution_async(execbody));
//! //!
//! /* 5. Load the listener into the bot */ //! /* 5. Load the listener into the bot */
@ -226,12 +225,13 @@
pub mod botcore; pub mod botcore;
pub mod custom_mods; pub mod custom_mods;
pub use crate::botcore::bot::Bot; pub use botcore::bot::Bot;
pub use crate::botcore::bot_objects::execution_async; pub use botcore::bot_objects::execution_async;
pub use crate::botcore::bot_objects::command_condition_async; pub use botcore::bot_objects::command_condition_async;
pub use crate::botcore::bot_objects::listener_condition_async; pub use botcore::bot_objects::listener_condition_async;
pub use crate::botcore::bot_objects::listener::Listener; pub use botcore::bot_objects::listener::Listener;
pub use crate::botcore::bot_objects::command::Command; // pub use crate::botcore::bot_objects::command::Command;
pub use crate::botcore::modules::Module; pub use botcore::bot_objects::command::Command;
pub use crate::botcore::bot_objects::Badge; pub use botcore::modules::Module;
pub use crate::botcore::modules; pub use botcore::bot_objects::Badge;
pub use botcore::modules;

View file

@ -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"

View file

@ -13,9 +13,9 @@
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
use forcebot_rs_v2::execution_async; use forcebot_core::execution_async;
use forcebot_rs_v2::Listener; use forcebot_core::Listener;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
@ -53,7 +53,7 @@ pub async fn main() {
Result::Err("Not Valid message type".to_string()) 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)); listener.set_exec_fn(execution_async(execbody));
/* 5. Load the listener into the bot */ /* 5. Load the listener into the bot */

11
new_empty_bot/Cargo.toml Normal file
View file

@ -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"

View file

@ -10,8 +10,7 @@
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
//! - More Info - <https://dev.twitch.tv/docs/authentication> //! - More Info - <https://dev.twitch.tv/docs/authentication>
use forcebot_rs_v2::botcore::bot::Bot; use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {

129
readme.md
View file

@ -1,4 +1,4 @@
Twitch chat bot written in rust Customizable Twitch chat bot written in rust
# Quick Start # Quick Start
@ -22,28 +22,47 @@ bot_admins=ADMIN
3. Build & run 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 # 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 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 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 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 ## 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 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 ## Moderator Reactor
Run a bot that listens for messages with the `moderator` badge, and replies to that mod with an emote 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 ## 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 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 Uses Env defined variables to create and run the bot
```rust ```rust
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -95,7 +155,6 @@ pub async fn main() {
bot.run().await; bot.run().await;
} }
``` ```
## Customize by Loading Custom Modules ## 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 Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot
```rust ```rust
use forcebot_rs_v2::{custom_mods::{guest_badge, pyramid}, Bot}; use forcebot_core::{custom_mods::{guest_badge, pyramid}, Bot};
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -134,7 +194,7 @@ Create a custom `Module` by :
```rust ```rust
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -153,7 +213,7 @@ pub async fn main() {
pub mod custom_mod { pub mod custom_mod {
use std::sync::Arc; 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; use twitch_irc::message::ServerMessage;
@ -193,7 +253,6 @@ pub mod custom_mod {
cmd cmd
} }
} }
``` ```
## Simple Debug Listener ## Simple Debug Listener
@ -202,7 +261,7 @@ Bot with a simple listener that listens for all messages and prints in output
```rust ```rust
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::{execution_async, Bot, Listener}; use forcebot_core::{execution_async, Bot, Listener};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
@ -225,7 +284,7 @@ pub async fn main() {
Result::Ok("Success".to_string()) 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)); listener.set_exec_fn(execution_async(execbody));
/* 3. Load the listener into the bot */ /* 3. Load the listener into the bot */
@ -235,7 +294,6 @@ pub async fn main() {
bot.run().await; bot.run().await;
} }
``` ```
## Moderator Reactor ## Moderator Reactor
@ -243,12 +301,11 @@ pub async fn main() {
Example listener listens for a moderator badge and reply in chat Example listener listens for a moderator badge and reply in chat
```rust ```rust
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
use forcebot_rs_v2::execution_async; use forcebot_core::execution_async;
use forcebot_rs_v2::Listener; use forcebot_core::Listener;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
@ -286,7 +343,7 @@ pub async fn main() {
Result::Err("Not Valid message type".to_string()) 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)); listener.set_exec_fn(execution_async(execbody));
/* 5. Load the listener into the bot */ /* 5. Load the listener into the bot */
@ -296,9 +353,6 @@ pub async fn main() {
bot.run().await; bot.run().await;
} }
``` ```
## Simple Test Command ## Simple Test Command
@ -306,13 +360,12 @@ pub async fn main() {
```rust ```rust
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::Badge; use forcebot_core::Badge;
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
use forcebot_rs_v2::execution_async; use forcebot_core::execution_async;
use forcebot_rs_v2::Command; use forcebot_core::Command;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
pub async fn main() { pub async fn main() {
@ -331,7 +384,7 @@ pub async fn main() {
Result::Err("Not Valid message type".to_string()) 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)); cmd.set_exec_fn(execution_async(execbody));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */
@ -347,11 +400,9 @@ pub async fn main() {
bot.run().await; bot.run().await;
} }
``` ```
# Crate Rust Documentation # Crate Rust API Documentation
Create `forcebot_rs_v2` Rust Crate documentation Create `forcebot_rs_v2` Rust Crate documentation

View file

@ -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"

View file

@ -15,10 +15,10 @@
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::Badge; use forcebot_core::Badge;
use forcebot_rs_v2::Bot; use forcebot_core::Bot;
use forcebot_rs_v2::execution_async; use forcebot_core::execution_async;
use forcebot_rs_v2::Command; use forcebot_core::Command;
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
@ -40,7 +40,7 @@ pub async fn main() {
Result::Err("Not Valid message type".to_string()) 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)); cmd.set_exec_fn(execution_async(execbody));
/* 4. optionally, remove admin only default flag */ /* 4. optionally, remove admin only default flag */

View file

@ -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"

View file

@ -12,7 +12,7 @@
use std::sync::Arc; use std::sync::Arc;
use forcebot_rs_v2::{execution_async, Bot, Listener}; use forcebot_core::{execution_async, Bot, Listener};
use twitch_irc::message::ServerMessage; use twitch_irc::message::ServerMessage;
#[tokio::main] #[tokio::main]
@ -35,7 +35,7 @@ pub async fn main() {
Result::Ok("Success".to_string()) 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)); listener.set_exec_fn(execution_async(execbody));
/* 3. Load the listener into the bot */ /* 3. Load the listener into the bot */

View file

@ -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"

View file

@ -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
}
}