modules functionality
This commit is contained in:
parent
b2244a81eb
commit
92b6cd3f94
13 changed files with 700 additions and 220 deletions
171
readme.md
171
readme.md
|
@ -25,43 +25,60 @@ bot_admins=ADMIN
|
|||
cargo run
|
||||
```
|
||||
|
||||
# Binary Crates
|
||||
# Example Bots
|
||||
|
||||
## Simple Empty Bot
|
||||
Run a simple bot that logs into chat based on env
|
||||
Use the following commands to build and run built-in bots. No coding required!
|
||||
|
||||
## New Bot
|
||||
Run an empty simple bot that logs into chat and has minimum built in functions
|
||||
|
||||
```
|
||||
cargo run --bin simple_bot
|
||||
cargo run --bin new_bot
|
||||
```
|
||||
|
||||
## Fun Bot
|
||||
## WIP Customized Fun Bot
|
||||
|
||||
Run a forcebot with fun catered customizations
|
||||
|
||||
*ongoing work in progress*
|
||||
|
||||
```
|
||||
cargo run --bin fun_bot
|
||||
```
|
||||
|
||||
|
||||
## Simple Bot with Example Custom Listener
|
||||
Run a bot with some custom listeners
|
||||
## Simple Debug Listener
|
||||
Run a bot that listens to all messages and output to console
|
||||
|
||||
```
|
||||
cargo run --bin simple_bot_listener
|
||||
cargo run --bin simple_debug_listener
|
||||
```
|
||||
|
||||
## Bot with Example Custom Command
|
||||
Run a bot with some custom listeners
|
||||
## 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 bot_cmd_example
|
||||
cargo run --bin 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
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
|
||||
# Example Code
|
||||
|
||||
## Simple Bot
|
||||
## New Bot
|
||||
|
||||
Uses Env defined variables to create and run the bot
|
||||
|
||||
|
@ -81,8 +98,103 @@ pub async fn main() {
|
|||
|
||||
```
|
||||
|
||||
## Custom Bot with listener
|
||||
Bot with a simple listener
|
||||
## Module with Custom Command
|
||||
|
||||
A `Module` is a group of bot objects (eg `Command`) that elevated users can manage.
|
||||
|
||||
Bot objects are recommended to be loaded through a `Module`
|
||||
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::Bot;
|
||||
use forcebot_rs_v2::asyncfn_box;
|
||||
use forcebot_rs_v2::Command;
|
||||
use forcebot_rs_v2::Module;
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
|
||||
/* 1. Create a new module */
|
||||
let mut custom_mod = Module::new("test".to_string(), "".to_string());
|
||||
|
||||
/* 2. Create a new cmd */
|
||||
let mut cmd = Command::new("test".to_string(),"".to_string());
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
cmd.set_admin_only(false);
|
||||
cmd.set_min_badge("moderator".to_string());
|
||||
|
||||
/* 3. Load the cmd into a new module */
|
||||
custom_mod.load_command(cmd);
|
||||
|
||||
/* 4. Load the module into the bot */
|
||||
bot.load_module(custom_mod);
|
||||
|
||||
/* Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Simple Debug Listener
|
||||
Bot with a simple listener that listens for all messages and prints in output
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
|
||||
/* 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 `async_box()` */
|
||||
listener.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 3. Load the listener into the bot */
|
||||
bot.load_listener(listener);
|
||||
|
||||
/* 4. Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Moderator Reator
|
||||
|
||||
Example listener listens for a moderator badge and reply in chat
|
||||
|
||||
|
@ -104,12 +216,14 @@ pub async fn main() {
|
|||
/* 1. Create a new blank Listener */
|
||||
let mut listener = Listener::new();
|
||||
|
||||
/* 2. Set a trigger condition callback */
|
||||
/* 2. Set a trigger condition function for listener */
|
||||
listener.set_trigger_cond_fn(
|
||||
|_:Arc<Bot>,message:ServerMessage|
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
|
||||
for badge in msg.badges {
|
||||
if matches!(badge, x if x.name == "moderator") {
|
||||
// dbg!("moderator found");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -120,18 +234,16 @@ pub async fn main() {
|
|||
/* 3. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
match bot.client.say_in_reply_to(&msg, String::from("test")).await {
|
||||
Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
|
||||
return Result::Ok("Success".to_string()) ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
/* 4. Set the execution body using `async_box()` */
|
||||
/* 4. Set and Store the execution body using `async_box()` */
|
||||
listener.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 5. Load the Listener into the bot */
|
||||
/* 5. Load the listener into the bot */
|
||||
bot.load_listener(listener);
|
||||
|
||||
/* Run the bot */
|
||||
|
@ -139,9 +251,10 @@ pub async fn main() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Bot with Custom command
|
||||
## Simple Test Command
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
|
@ -159,25 +272,26 @@ pub async fn main() {
|
|||
let mut bot = Bot::new();
|
||||
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new("tester".to_string(),"".to_string());
|
||||
let mut cmd = Command::new("test".to_string(),"".to_string());
|
||||
|
||||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
match bot.client.say_in_reply_to(&msg, String::from("cmd tested")).await {
|
||||
Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
|
||||
return Result::Ok("Success".to_string()) ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
/* 3. Set and Store the execution body using `async_box()` */
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 4. optionally, remove admin only default flag */
|
||||
cmd.set_admin_only(false);
|
||||
|
||||
/* 5. optionally, set min badge*/
|
||||
cmd.set_min_badge("broadcaster".to_string());
|
||||
|
||||
//
|
||||
/* 6. Load the cmd into the bot */
|
||||
bot.load_command(cmd);
|
||||
|
||||
|
@ -185,6 +299,7 @@ pub async fn main() {
|
|||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Crate Rust Documentation
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
//! 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
|
||||
//! - funbot
|
||||
//!
|
||||
//! Be sure the followig is defined in `.env`
|
||||
//! - login_name
|
||||
|
@ -11,13 +14,7 @@
|
|||
//! - Get a Bot Chat Token here - <https://twitchtokengenerator.com>
|
||||
//! - More Info - <https://dev.twitch.tv/docs/authentication>
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::Bot;
|
||||
use forcebot_rs_v2::asyncfn_box;
|
||||
use forcebot_rs_v2::Command;
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
@ -25,28 +22,49 @@ pub async fn main() {
|
|||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new("remind besty".to_string(),"annytfYandere ".to_string());
|
||||
|
||||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
let _n= bot.client.say_in_reply_to(
|
||||
&msg, "annytfYandere he's mine".to_string()).await;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
/* 3. Set and Store the execution body using `async_box()` */
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
cmd.set_admin_only(false);
|
||||
cmd.set_min_badge("broadcaster".to_string());
|
||||
|
||||
/* 4. Load the cmd into the bot */
|
||||
bot.load_command(cmd);
|
||||
|
||||
/* Run the bot */
|
||||
/* 1. Load the module into the bot */
|
||||
bot.load_module(funbot_objs::create_module());
|
||||
|
||||
/* 2. Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub mod funbot_objs {
|
||||
use std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::{asyncfn_box, 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("funbot".to_string(), "".to_string());
|
||||
|
||||
custom_mod.load_command(create_cmd_test());
|
||||
|
||||
custom_mod
|
||||
}
|
||||
|
||||
/// Create a Command Object
|
||||
fn create_cmd_test() -> Command {
|
||||
|
||||
let mut cmd = Command::new("remind besty".to_string(),"annytfYandere ".to_string());
|
||||
|
||||
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, "annytfYandere he's mine".to_string()).await;
|
||||
return Result::Ok("Success".to_string());
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
cmd.set_admin_only(false);
|
||||
cmd.set_min_badge("vip".to_string());
|
||||
cmd
|
||||
|
||||
}
|
||||
}
|
|
@ -47,10 +47,8 @@ pub async fn main() {
|
|||
/* 3. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
match bot.client.say_in_reply_to(&msg, String::from("test")).await {
|
||||
Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
|
||||
return Result::Ok("Success".to_string()) ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
//! Bot with custom example commands that responds to caller if allowed
|
||||
//!
|
||||
//! Commands that are passed a blank prefix will use the bot prefix
|
||||
//!
|
||||
//! Be sure the followig is defined in `.env`
|
||||
//! - login_name
|
||||
//! - access_token
|
||||
|
@ -26,15 +28,13 @@ pub async fn main() {
|
|||
let mut bot = Bot::new();
|
||||
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new("tester".to_string(),"".to_string());
|
||||
let mut cmd = Command::new("test".to_string(),"".to_string());
|
||||
|
||||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
match bot.client.say_in_reply_to(&msg, String::from("cmd tested")).await {
|
||||
Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("test success")).await;
|
||||
return Result::Ok("Success".to_string()) ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
47
src/bin/simple_debug_listener.rs
Normal file
47
src/bin/simple_debug_listener.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
//! Example simple Binary crate that creates & runs bot based on `.env`
|
||||
//! 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 std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* 1. Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
|
||||
/* 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 `async_box()` */
|
||||
listener.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 3. Load the listener into the bot */
|
||||
bot.load_listener(listener);
|
||||
|
||||
/* 4. Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
62
src/bin/simple_module.rs
Normal file
62
src/bin/simple_module.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
//! 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 std::sync::Arc;
|
||||
|
||||
use forcebot_rs_v2::Bot;
|
||||
use forcebot_rs_v2::asyncfn_box;
|
||||
use forcebot_rs_v2::Command;
|
||||
use forcebot_rs_v2::Module;
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
|
||||
/* Create the bot using env */
|
||||
let mut bot = Bot::new();
|
||||
|
||||
/* 1. Create a new module */
|
||||
let mut custom_mod = Module::new("test".to_string(), "".to_string());
|
||||
|
||||
/* 2. Create a new cmd */
|
||||
let mut cmd = Command::new("test".to_string(),"".to_string());
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
cmd.set_admin_only(false);
|
||||
cmd.set_min_badge("moderator".to_string());
|
||||
|
||||
/* 3. Load the cmd into a new module */
|
||||
custom_mod.load_command(cmd);
|
||||
|
||||
/* 4. Load the module into the bot */
|
||||
bot.load_module(custom_mod);
|
||||
|
||||
/* Run the bot */
|
||||
bot.run().await;
|
||||
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod bot;
|
||||
pub mod bot_objects;
|
||||
pub mod bot_objects;
|
||||
pub mod modules;
|
|
@ -5,10 +5,9 @@ use twitch_irc::{login::StaticLoginCredentials, message::ServerMessage, SecureTC
|
|||
use dotenv::dotenv;
|
||||
use std::{env, sync::Arc};
|
||||
|
||||
use crate::Command;
|
||||
|
||||
use super::bot_objects::listener::Listener;
|
||||
use crate::{Command, Listener, Module};
|
||||
|
||||
use super::bot_objects::built_in_objects;
|
||||
|
||||
|
||||
/// Twitch chat bot
|
||||
|
@ -28,6 +27,10 @@ pub struct Bot
|
|||
listeners: Vec<Listener>,
|
||||
/// commands
|
||||
commands: Vec<Command>,
|
||||
/// modules
|
||||
modules: Vec<Module>,
|
||||
/// channel module status
|
||||
channel_module_status: Mutex<Vec<(String,String,String)>>
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,16 +52,12 @@ impl Bot
|
|||
let prefix = env::var("prefix")
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
// .chars()
|
||||
// .next()
|
||||
// .expect("ERROR : when defining prefix");
|
||||
|
||||
let mut botchannels = Vec::new();
|
||||
|
||||
for chnl in env::var("bot_channels").unwrap().split(',') {
|
||||
botchannels.push(chnl.to_owned());
|
||||
}
|
||||
|
||||
|
||||
Bot::new_from(bot_login_name, oauth_token, prefix, botchannels)
|
||||
|
||||
|
@ -98,7 +97,7 @@ impl Bot
|
|||
}
|
||||
|
||||
|
||||
Bot {
|
||||
let mut bot = Bot {
|
||||
prefix,
|
||||
incoming_msgs : Mutex::new(incoming_messages),
|
||||
client,
|
||||
|
@ -106,7 +105,15 @@ impl Bot
|
|||
listeners : vec![],
|
||||
commands : vec![],
|
||||
admins,
|
||||
modules: vec![],
|
||||
channel_module_status: Mutex::new(vec![]),
|
||||
};
|
||||
|
||||
for cmd in built_in_objects::create_commands() {
|
||||
bot.load_command(cmd);
|
||||
}
|
||||
|
||||
bot
|
||||
}
|
||||
|
||||
/// Runs the bot
|
||||
|
@ -115,17 +122,15 @@ impl Bot
|
|||
for chnl in &self.botchannels {
|
||||
self.client.join(chnl.to_owned()).unwrap();
|
||||
}
|
||||
|
||||
|
||||
let bot = Arc::new(self);
|
||||
|
||||
let join_handle = tokio::spawn(async move {
|
||||
|
||||
let mut in_msgs_lock = bot.incoming_msgs.lock().await;
|
||||
let a = bot.clone();
|
||||
let mut in_msgs_lock = a.incoming_msgs.lock().await;
|
||||
|
||||
while let Some(message) = in_msgs_lock.recv().await {
|
||||
// dbg!("Received message: {:?}", message.clone());
|
||||
|
||||
while let Some(message) = in_msgs_lock.recv().await {
|
||||
for listener in &(*bot).listeners {
|
||||
|
||||
let a = listener.clone();
|
||||
|
@ -134,14 +139,47 @@ impl Bot
|
|||
let _ = listener.execute_fn(bot.clone(),message.clone()).await;
|
||||
}
|
||||
}
|
||||
for cmd in &(*bot).commands {
|
||||
|
||||
if let ServerMessage::Privmsg(msg) = message.clone() {
|
||||
|
||||
for cmd in &(*bot).commands {
|
||||
|
||||
let a = cmd.clone();
|
||||
if a.command_triggered(bot.clone(),message.clone()) {
|
||||
|
||||
let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
|
||||
let a = cmd.clone();
|
||||
if a.command_triggered(bot.clone(),msg.clone()) {
|
||||
|
||||
let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for module in &(*bot).modules {
|
||||
|
||||
let cms_lock = bot.channel_module_status.lock().await;
|
||||
if cms_lock.contains(&(msg.channel_login.clone(),module.get_name(),"disabled".to_string()))
|
||||
{ continue; }
|
||||
|
||||
for listener in module.get_listeners() {
|
||||
|
||||
let a = listener.clone();
|
||||
if a.cond_triggered(bot.clone(),message.clone()) {
|
||||
|
||||
let _ = listener.execute_fn(bot.clone(),message.clone()).await;
|
||||
}
|
||||
}
|
||||
for cmd in module.get_commands() {
|
||||
|
||||
let a = cmd.clone();
|
||||
if a.command_triggered(bot.clone(),msg.clone()) {
|
||||
|
||||
let _ = cmd.execute_fn(bot.clone(),message.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {} ;
|
||||
|
||||
|
||||
}
|
||||
drop(in_msgs_lock);
|
||||
});
|
||||
|
@ -169,4 +207,32 @@ impl Bot
|
|||
self.admins.clone()
|
||||
}
|
||||
|
||||
}
|
||||
/// loads a `Module` and its bot objects
|
||||
pub fn load_module(&mut self,m: Module) {
|
||||
self.modules.push(m)
|
||||
}
|
||||
|
||||
pub async fn disable_module(&self,channel:String,module:String){
|
||||
let mut lock = self.channel_module_status.lock().await;
|
||||
if !lock.contains(&(channel.clone(),module.clone(),"disabled".to_string())) {
|
||||
lock.push((channel,module,"disabled".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn enable_module(&self,channel:String,module:String){
|
||||
let mut lock = self.channel_module_status.lock().await;
|
||||
if lock.contains(&(channel.clone(),module.clone(),"disabled".to_string())) {
|
||||
|
||||
let index = lock
|
||||
.iter()
|
||||
.position(|x| *x ==
|
||||
(channel.clone(),module.clone(),"disabled".to_string()))
|
||||
.unwrap();
|
||||
lock.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,4 +20,90 @@ where
|
|||
T: Future<Output = Result<String,String>> + Send + 'static,
|
||||
{
|
||||
Box::new(move |a,b| Box::pin(f(a,b)))
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// collection of functions to create built in objects
|
||||
pub mod built_in_objects {
|
||||
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use twitch_irc::message::ServerMessage;
|
||||
|
||||
use crate::{asyncfn_box, Bot, Command};
|
||||
|
||||
|
||||
/// create a vector of command build in objects
|
||||
pub fn create_commands() -> Vec<Command>
|
||||
{
|
||||
let mut cmds = vec![];
|
||||
|
||||
cmds.push(create_disable_cmd());
|
||||
cmds.push(create_enable_cmd());
|
||||
|
||||
cmds
|
||||
|
||||
}
|
||||
|
||||
fn create_disable_cmd() -> Command {
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new("disable".to_string(),"".to_string());
|
||||
|
||||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
for (i,arg) in msg.message_text.split(" ").enumerate() {
|
||||
if i > 1 {
|
||||
bot.disable_module(msg.channel_login.clone(), arg.to_string()).await;
|
||||
}
|
||||
}
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("Disabled!")).await ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
/* 3. Set and Store the execution body using `async_box()` */
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 4. optionally, remove admin only default flag */
|
||||
cmd.set_admin_only(false);
|
||||
|
||||
/* 5. optionally, set min badge*/
|
||||
cmd.set_min_badge("moderator".to_string());
|
||||
cmd
|
||||
|
||||
}
|
||||
|
||||
fn create_enable_cmd() -> Command {
|
||||
/* 1. Create a new blank cmd */
|
||||
let mut cmd = Command::new("enable".to_string(),"".to_string());
|
||||
|
||||
/* 2. Define an async fn callback execution */
|
||||
async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
for (i,arg) in msg.message_text.split(" ").enumerate() {
|
||||
if i > 1 {
|
||||
bot.enable_module(msg.channel_login.clone(), arg.to_string()).await;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = bot.client.say_in_reply_to(&msg, String::from("Enabled!")).await ;
|
||||
}
|
||||
Result::Err("Not Valid message type".to_string())
|
||||
}
|
||||
|
||||
/* 3. Set and Store the execution body using `async_box()` */
|
||||
cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
|
||||
/* 4. optionally, remove admin only default flag */
|
||||
cmd.set_admin_only(false);
|
||||
|
||||
/* 5. optionally, set min badge*/
|
||||
cmd.set_min_badge("moderator".to_string());
|
||||
cmd
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use twitch_irc::message::ServerMessage;
|
||||
use twitch_irc::message::{PrivmsgMessage, ServerMessage};
|
||||
|
||||
use crate::{asyncfn_box, botcore::bot::Bot};
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub struct Command
|
|||
min_badge : String,
|
||||
admin_only : bool,
|
||||
prefix : String,
|
||||
custom_cond_fn : fn(Arc<Bot>,ServerMessage) -> bool,
|
||||
custom_cond_fn : fn(Arc<Bot>,PrivmsgMessage) -> bool,
|
||||
}
|
||||
|
||||
impl Command
|
||||
|
@ -49,12 +49,12 @@ impl Command
|
|||
exec_fn : Arc::new(asyncfn_box(execbody)),
|
||||
min_badge : "vip".to_string(),
|
||||
admin_only : true,
|
||||
custom_cond_fn : |_:Arc<Bot>,_:ServerMessage| true,
|
||||
custom_cond_fn : |_:Arc<Bot>,_:PrivmsgMessage| true,
|
||||
}
|
||||
}
|
||||
|
||||
/// set a trigger conditin callback that returns true if the listener shoud trigger
|
||||
pub fn set_custom_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,ServerMessage) -> bool) {
|
||||
pub fn set_custom_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,PrivmsgMessage) -> bool) {
|
||||
self.custom_cond_fn = cond_fn;
|
||||
}
|
||||
|
||||
|
@ -70,12 +70,9 @@ impl Command
|
|||
/// checks if the trigger condition is met
|
||||
/// specifically if the message is a valid command and min badge roles provided
|
||||
///
|
||||
pub fn command_triggered(&self,bot:Arc<Bot>,msg:ServerMessage) -> bool {
|
||||
pub fn command_triggered(&self,bot:Arc<Bot>,msg:PrivmsgMessage) -> bool {
|
||||
|
||||
|
||||
fn cmd_called(cmd:&Command,bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
// dbg!(msg.clone());
|
||||
fn cmd_called(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
|
||||
let mut prefixed_cmd = "".to_string();
|
||||
if cmd.prefix == "" {
|
||||
prefixed_cmd.push_str(&bot.get_prefix());
|
||||
|
@ -83,44 +80,35 @@ impl Command
|
|||
prefixed_cmd.push_str(&cmd.prefix);
|
||||
}
|
||||
prefixed_cmd.push_str(&cmd.command);
|
||||
return msg.message_text.starts_with(prefixed_cmd.as_str())
|
||||
} else { false }
|
||||
return message.message_text.starts_with(prefixed_cmd.as_str())
|
||||
}
|
||||
|
||||
|
||||
fn caller_badge_ok(cmd:&Command,_bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
// dbg!(msg.clone())
|
||||
// dbg!(cmd.min_badge.clone());
|
||||
for badge in msg.badges {
|
||||
|
||||
match cmd.min_badge.as_str() {
|
||||
"broadcaster" => {
|
||||
if badge.name == cmd.min_badge { return true }
|
||||
else { return false }
|
||||
},
|
||||
"moderator" => {
|
||||
match badge.name.as_str() {
|
||||
"moderator" | "broadcaster" => return true,
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
"vip" => {
|
||||
match badge.name.as_str() {
|
||||
"vip" | "moderator" | "broadcaster" => return true,
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => return false,
|
||||
}
|
||||
fn caller_badge_ok(cmd:&Command,_bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
|
||||
for badge in message.badges {
|
||||
|
||||
match cmd.min_badge.as_str() {
|
||||
"broadcaster" => {
|
||||
if badge.name == cmd.min_badge { return true }
|
||||
else { return false }
|
||||
},
|
||||
"moderator" => {
|
||||
match badge.name.as_str() {
|
||||
"moderator" | "broadcaster" => return true,
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
"vip" => {
|
||||
match badge.name.as_str() {
|
||||
"vip" | "moderator" | "broadcaster" => return true,
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,18 +117,15 @@ impl Command
|
|||
///
|
||||
/// callers who are admins can run admin_only commands
|
||||
/// callers can run non-admin_only commands
|
||||
fn admin_only_ok(cmd:&Command,bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
|
||||
if let ServerMessage::Privmsg(msg) = message {
|
||||
if (cmd.admin_only && bot.get_admins().contains(&msg.sender.login)) || !cmd.admin_only {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else { false }
|
||||
fn admin_only_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
|
||||
if (cmd.admin_only && bot.get_admins().contains(&message.sender.login)) || !cmd.admin_only {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn custom_cond_ok(cmd:&Command,bot:Arc<Bot>,message:ServerMessage) -> bool {
|
||||
fn custom_cond_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool {
|
||||
(cmd.custom_cond_fn)(bot,message)
|
||||
}
|
||||
|
||||
|
|
51
src/botcore/modules.rs
Normal file
51
src/botcore/modules.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
|
||||
use crate::{Command, Listener};
|
||||
|
||||
|
||||
/// Bot `Module` that groups a set of `bot_objects`
|
||||
///
|
||||
/// Elevated chatters can disable modules by their name or chat alias
|
||||
pub struct Module
|
||||
{
|
||||
name: String,
|
||||
_alias: String,
|
||||
listeners: Vec<Listener>,
|
||||
commands: Vec<Command>,
|
||||
}
|
||||
|
||||
impl Module
|
||||
{
|
||||
/// create a new module
|
||||
pub fn new(name:String,alias:String) -> Module {
|
||||
Module {
|
||||
name,
|
||||
_alias: alias,
|
||||
listeners: vec![],
|
||||
commands: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads a `Listener` into the module
|
||||
pub fn load_listener(&mut self,l : Listener) {
|
||||
self.listeners.push(l);
|
||||
}
|
||||
|
||||
/// Loads a `Command` into the module
|
||||
pub fn load_command(&mut self,c : Command) {
|
||||
self.commands.push(c);
|
||||
}
|
||||
|
||||
pub fn get_listeners(&self) -> Vec<Listener> {
|
||||
self.listeners.clone()
|
||||
}
|
||||
|
||||
pub fn get_commands(&self) -> Vec<Command> {
|
||||
self.commands.clone()
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
}
|
215
src/lib.rs
215
src/lib.rs
|
@ -2,30 +2,126 @@
|
|||
//!
|
||||
//! Customize by adding additional bot objects
|
||||
//!
|
||||
//! # Example Simple Bot
|
||||
//! ```
|
||||
//! ## New Bot
|
||||
//!
|
||||
//! Uses Env defined variables to create and run the bot
|
||||
//!
|
||||
//! ```rust
|
||||
//! use forcebot_rs_v2::Bot;
|
||||
//!
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//!pub async fn main() {
|
||||
//!
|
||||
//! /* 1. Create the bot using env */
|
||||
//! let bot = Bot::new();
|
||||
//!
|
||||
//! /* 2. Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//!}
|
||||
//!
|
||||
//! ```
|
||||
//! pub async fn main() {
|
||||
//!
|
||||
//! # Example Code Add Listener
|
||||
//! /* 1. Create the bot using env */
|
||||
//! let bot = Bot::new();
|
||||
//!
|
||||
//! Bot with a simple listener
|
||||
//! /* 2. Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//! Example listener listens for a moderator badge and reply in chat
|
||||
//! }
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! ## Module with Custom Command
|
||||
//!
|
||||
//! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage.
|
||||
//!
|
||||
//! Bot objects are recommended to be loaded through a `Module`
|
||||
//!
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
//! use forcebot_rs_v2::Bot;
|
||||
//! use forcebot_rs_v2::asyncfn_box;
|
||||
//! use forcebot_rs_v2::Command;
|
||||
//! use forcebot_rs_v2::Module;
|
||||
//! use twitch_irc::message::ServerMessage;
|
||||
//!
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! pub async fn main() {
|
||||
//!
|
||||
//! /* Create the bot using env */
|
||||
//! let mut bot = Bot::new();
|
||||
//!
|
||||
//! /* 1. Create a new module */
|
||||
//! let mut custom_mod = Module::new("test".to_string(), "".to_string());
|
||||
//!
|
||||
//! /* 2. Create a new cmd */
|
||||
//! let mut cmd = Command::new("test".to_string(),"".to_string());
|
||||
//!
|
||||
//! 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())
|
||||
//! }
|
||||
//!
|
||||
//! cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
//! cmd.set_admin_only(false);
|
||||
//! cmd.set_min_badge("moderator".to_string());
|
||||
//!
|
||||
//! /* 3. Load the cmd into a new module */
|
||||
//! custom_mod.load_command(cmd);
|
||||
//!
|
||||
//! /* 4. Load the module into the bot */
|
||||
//! bot.load_module(custom_mod);
|
||||
//!
|
||||
//! /* Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//! }
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! ## Simple Debug Listener
|
||||
//! Bot with a simple listener that listens for all messages and prints in output
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
//! use forcebot_rs_v2::{asyncfn_box, Bot, Listener};
|
||||
//! use twitch_irc::message::ServerMessage;
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! pub async fn main() {
|
||||
//!
|
||||
//! /* 1. Create the bot using env */
|
||||
//! let mut bot = Bot::new();
|
||||
//!
|
||||
//! /* 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 `async_box()` */
|
||||
//! listener.set_exec_fn(asyncfn_box(execbody));
|
||||
//!
|
||||
//! /* 3. Load the listener into the bot */
|
||||
//! bot.load_listener(listener);
|
||||
//!
|
||||
//! /* 4. Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//! }
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! ## Modertor Reactor
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
//! use forcebot_rs_v2::Bot;
|
||||
|
@ -43,12 +139,15 @@
|
|||
//! /* 1. Create a new blank Listener */
|
||||
//! let mut listener = Listener::new();
|
||||
//!
|
||||
//! /* 2. Set a trigger condition callback */
|
||||
//! /* 2. Set a trigger condition function for listener */
|
||||
//!
|
||||
//! listener.set_trigger_cond_fn(
|
||||
//! |_:Arc<Bot>,message:ServerMessage|
|
||||
//! if let ServerMessage::Privmsg(msg) = message {
|
||||
//! if let ServerMessage::Privmsg(msg) = message {
|
||||
//! // dbg!(msg.clone());
|
||||
//! for badge in msg.badges {
|
||||
//! if matches!(badge, x if x.name == "moderator") {
|
||||
//! // dbg!("moderator found");
|
||||
//! return true;
|
||||
//! }
|
||||
//! }
|
||||
|
@ -56,79 +155,31 @@
|
|||
//! } else { false }
|
||||
//! );
|
||||
//!
|
||||
//! /* 3. Define an async fn callback execution */
|
||||
//! async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
//! if let ServerMessage::Privmsg(msg) = message {
|
||||
//! match bot.client.say_in_reply_to(&msg, String::from("test")).await {
|
||||
//! Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
//! Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
//! }
|
||||
//! }
|
||||
//! Result::Err("Not Valid message type".to_string())
|
||||
//! }
|
||||
//!
|
||||
//! /* 4. Set the execution body using `async_box()` */
|
||||
//! listener.set_exec_fn(asyncfn_box(execbody));
|
||||
//!
|
||||
//! /* 5. Load the Listener into the bot */
|
||||
//! bot.load_listener(listener);
|
||||
//!
|
||||
//! /* Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Example Bot with Custom Command
|
||||
//! ```
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
//! use forcebot_rs_v2::Bot;
|
||||
//! use forcebot_rs_v2::asyncfn_box;
|
||||
//! use forcebot_rs_v2::Command;
|
||||
//! use twitch_irc::message::ServerMessage;
|
||||
//!
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! pub async fn main() {
|
||||
//!
|
||||
//! /* Create the bot using env */
|
||||
//! let mut bot = Bot::new();
|
||||
//!
|
||||
//! /* 1. Create a new blank cmd */
|
||||
//! let mut cmd = Command::new("tester".to_string(),"".to_string());
|
||||
//!
|
||||
//! /* 2. Define an async fn callback execution */
|
||||
//! /* 3. Define an async fn callback execution */
|
||||
//! async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> {
|
||||
//! if let ServerMessage::Privmsg(msg) = message {
|
||||
//! match bot.client.say_in_reply_to(&msg, String::from("cmd tested")).await {
|
||||
//! Ok(_) => return Result::Ok("Success".to_string()) ,
|
||||
//! Err(_) => return Result::Err("Not Valid message type".to_string())
|
||||
//! }
|
||||
//! let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ;
|
||||
//! return Result::Ok("Success".to_string()) ;
|
||||
//! }
|
||||
//! Result::Err("Not Valid message type".to_string())
|
||||
//! }
|
||||
//!
|
||||
//! /* 3. Set and Store the execution body using `async_box()` */
|
||||
//! cmd.set_exec_fn(asyncfn_box(execbody));
|
||||
//!
|
||||
//! /* 4. optionally, remove admin only default flag */
|
||||
//! cmd.set_admin_only(false);
|
||||
//!
|
||||
//! /* 5. optionally, set min badge*/
|
||||
//! cmd.set_min_badge("broadcaster".to_string());
|
||||
//!
|
||||
//! /* 6. Load the cmd into the bot */
|
||||
//! bot.load_command(cmd);
|
||||
//!
|
||||
//! /* Run the bot */
|
||||
//! bot.run().await;
|
||||
//! /* 4. Set and Store the execution body using `async_box()` */
|
||||
//! listener.set_exec_fn(asyncfn_box(execbody));
|
||||
//!
|
||||
//! /* 5. Load the listener into the bot */
|
||||
//! bot.load_listener(listener);
|
||||
//!
|
||||
//! /* Run the bot */
|
||||
//! bot.run().await;
|
||||
//!
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
|
||||
|
||||
pub mod botcore;
|
||||
pub use crate::botcore::bot::Bot;
|
||||
pub use crate::botcore::bot_objects::asyncfn_box;
|
||||
pub use crate::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;
|
Loading…
Add table
Add a link
Reference in a new issue