funny crate do funny thing
This commit is contained in:
parent
3826ada069
commit
803289d754
7 changed files with 160 additions and 43 deletions
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "twitchbot-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
twitch-irc = "5.0.1"
|
||||||
|
tokio = { version = "1.33.0", features = ["full"] }
|
26
src/bot.rs
26
src/bot.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex as StdMutex};
|
||||||
|
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
@ -14,7 +14,6 @@ use twitch_irc::{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type IncomingMessages = UnboundedReceiver<ServerMessage>;
|
type IncomingMessages = UnboundedReceiver<ServerMessage>;
|
||||||
pub type Client = TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>;
|
pub type Client = TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>;
|
||||||
/// rename types wrapped in `Arc<Mutex<...>>` to their respective name ending with `AM`
|
/// rename types wrapped in `Arc<Mutex<...>>` to their respective name ending with `AM`
|
||||||
|
@ -22,16 +21,16 @@ pub type Client = TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>;
|
||||||
pub type ClientAM = Arc<Mutex<Client>>;
|
pub type ClientAM = Arc<Mutex<Client>>;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Bot<'a, P> {
|
pub struct Bot<'a, P> {
|
||||||
username: &'a str,
|
username: &'a str,
|
||||||
oauth_token: &'a str,
|
oauth_token: &'a str,
|
||||||
payload: Arc<Mutex<P>>,
|
payload: Arc<StdMutex<P>>,
|
||||||
commands: Arc<Mutex<dyn Command<CommandPayLoad=P>>>
|
commands: Arc<Mutex<HashMap<String, Box<dyn Command<CommandPayLoad=P>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, P> Bot<'a, P>
|
impl<'a, P> Bot<'a, P>
|
||||||
|
where P: Send + 'static
|
||||||
{
|
{
|
||||||
/// Return a message stream and a client wrapped in `Arc<Mutex<...>>`
|
/// Return a message stream and a client wrapped in `Arc<Mutex<...>>`
|
||||||
fn incoming_messages_and_client(&self) -> (IncomingMessages, ClientAM) {
|
fn incoming_messages_and_client(&self) -> (IncomingMessages, ClientAM) {
|
||||||
|
@ -53,18 +52,18 @@ impl<'a, P> Bot<'a, P>
|
||||||
/// `payload` can be any type and will be wrapped to `Arc<Mutex<P>>` and passed to any command executed,
|
/// `payload` can be any type and will be wrapped to `Arc<Mutex<P>>` and passed to any command executed,
|
||||||
/// where the user can access the contents mutable.
|
/// where the user can access the contents mutable.
|
||||||
pub fn new<'b>(username: &'b str, oauth_token: &'b str, payload: P) -> Bot<'a, P>
|
pub fn new<'b>(username: &'b str, oauth_token: &'b str, payload: P) -> Bot<'a, P>
|
||||||
where
|
where
|
||||||
'b : 'a
|
'b : 'a
|
||||||
{
|
{
|
||||||
Bot {
|
Bot {
|
||||||
username,
|
username,
|
||||||
oauth_token,
|
oauth_token,
|
||||||
payload: Arc::new(Mutex::new(payload)),
|
payload: Arc::new(StdMutex::new(payload)),
|
||||||
commands: Arc::new(Mutex::new(HashMap::new())),
|
commands: Arc::new(Mutex::new(HashMap::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_command(&mut self, identifier: String, command: impl Command<CommandPayLoad=P>) {
|
pub async fn add_command(&mut self, identifier: String, command: Box<dyn Command<CommandPayLoad=P>>) {
|
||||||
let mut commands = self.commands.lock().await;
|
let mut commands = self.commands.lock().await;
|
||||||
commands.insert(identifier, command);
|
commands.insert(identifier, command);
|
||||||
}
|
}
|
||||||
|
@ -72,6 +71,7 @@ impl<'a, P> Bot<'a, P>
|
||||||
pub async fn run(&'a self) {
|
pub async fn run(&'a self) {
|
||||||
// set up client and message stream
|
// set up client and message stream
|
||||||
let (mut incoming_messages, client_am) = self.incoming_messages_and_client();
|
let (mut incoming_messages, client_am) = self.incoming_messages_and_client();
|
||||||
|
let commands = Arc::clone(&self.commands);
|
||||||
let payload = Arc::clone(&self.payload);
|
let payload = Arc::clone(&self.payload);
|
||||||
let initial_channel = self.username.to_owned();
|
let initial_channel = self.username.to_owned();
|
||||||
|
|
||||||
|
@ -93,7 +93,13 @@ impl<'a, P> Bot<'a, P>
|
||||||
ServerMessage::Part(_) => {}
|
ServerMessage::Part(_) => {}
|
||||||
ServerMessage::Ping(_) => {}
|
ServerMessage::Ping(_) => {}
|
||||||
ServerMessage::Pong(_) => {}
|
ServerMessage::Pong(_) => {}
|
||||||
ServerMessage::Privmsg(_) => {}
|
ServerMessage::Privmsg(msg) => {
|
||||||
|
let mut cmd = commands.lock().await;
|
||||||
|
if let Some(command) = cmd.get_mut(&msg.message_text) {
|
||||||
|
let mut queue = command.execute(Arc::clone(&payload), msg);
|
||||||
|
queue.execute(Arc::clone(&client_am)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
ServerMessage::Reconnect(_) => {}
|
ServerMessage::Reconnect(_) => {}
|
||||||
ServerMessage::RoomState(_) => {}
|
ServerMessage::RoomState(_) => {}
|
||||||
ServerMessage::UserNotice(_) => {}
|
ServerMessage::UserNotice(_) => {}
|
||||||
|
|
66
src/client_queue.rs
Normal file
66
src/client_queue.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use twitch_irc::message::ReplyToMessage;
|
||||||
|
use crate::bot::ClientAM;
|
||||||
|
|
||||||
|
pub enum ClientOps {
|
||||||
|
// channel login
|
||||||
|
Join(String),
|
||||||
|
// channel login
|
||||||
|
Part(String),
|
||||||
|
// channel login, message
|
||||||
|
Say(String, String),
|
||||||
|
// channel login, message
|
||||||
|
Me(String, String),
|
||||||
|
// // message
|
||||||
|
// Reply(String),
|
||||||
|
// // message
|
||||||
|
// ReplyMe(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct ClientQueue {
|
||||||
|
queue: Vec<ClientOps>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientQueue {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ClientQueue { queue: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join(&mut self, channel: String) {
|
||||||
|
self.queue.push(ClientOps::Join(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part(&mut self, channel: String) {
|
||||||
|
self.queue.push(ClientOps::Part(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn say(&mut self, channel: String, message: String) {
|
||||||
|
self.queue.push(ClientOps::Say(channel, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn me(&mut self, channel: String, message: String) {
|
||||||
|
self.queue.push(ClientOps::Me(channel, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn reply(&mut self, message: String) {
|
||||||
|
// self.queue.push(ClientOps::Reply(message));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn reply_me(&mut self, message: String) {
|
||||||
|
// self.queue.push(ClientOps::ReplyMe(message));
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub async fn execute(&self, client_am: ClientAM) {
|
||||||
|
let client = client_am.lock().await;
|
||||||
|
for op in self.queue.iter() {
|
||||||
|
match op {
|
||||||
|
ClientOps::Join(ch) => { client.join(ch.to_string()).unwrap() }
|
||||||
|
ClientOps::Part(ch) => { client.part(ch.to_string()) }
|
||||||
|
ClientOps::Say(ch, msg) => { client.say(ch.to_string(), msg.to_string()).await.unwrap() }
|
||||||
|
ClientOps::Me(ch, msg) => { client.me(ch.to_string(), msg.to_string()).await.unwrap() }
|
||||||
|
// ClientOps::Reply(ch) => {}
|
||||||
|
// ClientOps::ReplyMe(msg) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
use crate::bot::ClientAM;
|
use crate::ClientQueue;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex as StdMutex};
|
||||||
|
|
||||||
use tokio::sync::Mutex;
|
use twitch_irc::message::PrivmsgMessage;
|
||||||
|
|
||||||
pub trait Command {
|
pub trait Command: Send {
|
||||||
type CommandPayLoad;
|
type CommandPayLoad;
|
||||||
|
|
||||||
async fn execute(&self, pl_am: Arc<Mutex<Self::CommandPayLoad>>, client_am: ClientAM);
|
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue;
|
||||||
|
|
||||||
fn help(&self) -> String;
|
fn help(&self) -> String;
|
||||||
fn info(&self) -> String;
|
fn info(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
0
src/context.rs
Normal file
0
src/context.rs
Normal file
12
src/lib.rs
Normal file
12
src/lib.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
pub mod bot;
|
||||||
|
pub mod command;
|
||||||
|
pub mod client_queue;
|
||||||
|
pub mod context;
|
||||||
|
|
||||||
|
|
||||||
|
pub use bot::Bot;
|
||||||
|
pub use command::Command;
|
||||||
|
pub use client_queue::ClientQueue;
|
||||||
|
|
||||||
|
|
||||||
|
pub type Context = twitch_irc::message::PrivmsgMessage;
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex as StdMutex};
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use twitchbot_rs::{Bot, Command};
|
use twitchbot_rs::{Bot, ClientQueue, Command, Context};
|
||||||
use twitchbot_rs::bot::ClientAM;
|
use twitchbot_rs::bot::ClientAM;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,41 +9,65 @@ pub struct Payload {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// pub struct PingCommand;
|
pub struct PingCommand;
|
||||||
//
|
|
||||||
// impl Command for PingCommand {
|
impl Command for PingCommand {
|
||||||
// type CommandPayLoad = Payload;
|
type CommandPayLoad = Payload;
|
||||||
//
|
|
||||||
// async fn execute(&self, pl_am: Arc<Mutex<Self::CommandPayLoad>>, client_am: ClientAM) {
|
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: Context) -> ClientQueue {
|
||||||
// let client
|
let mut queue = ClientQueue::new();
|
||||||
// }
|
|
||||||
//
|
let pl = pl_am.lock().unwrap();
|
||||||
// fn help(&self) -> String {
|
queue.say("mzntori".to_string(), format!("Pong! {} {}", pl.content, ctx.sender.name));
|
||||||
// todo!()
|
println!("Pong executed! {}", pl.content);
|
||||||
// }
|
|
||||||
//
|
queue
|
||||||
// fn info(&self) -> String {
|
}
|
||||||
// todo!()
|
|
||||||
// }
|
fn help(&self) -> String {
|
||||||
// }
|
"pongs".to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(&self) -> String {
|
||||||
|
"do be ponging".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct UrmCommand;
|
||||||
|
|
||||||
|
impl Command for UrmCommand {
|
||||||
|
type CommandPayLoad = Payload;
|
||||||
|
|
||||||
|
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: Context) -> ClientQueue {
|
||||||
|
let mut pl = pl_am.lock().unwrap();
|
||||||
|
pl.content.push('1');
|
||||||
|
|
||||||
|
ClientQueue::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help(&self) -> String {
|
||||||
|
"pongs".to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(&self) -> String {
|
||||||
|
"do be ponging".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// let bot = Bot::new("");
|
|
||||||
let login = std::env::var("LOGIN").unwrap();
|
let login = std::env::var("LOGIN").unwrap();
|
||||||
let oauth = std::env::var("OAUTH").unwrap();
|
let oauth = std::env::var("OAUTH").unwrap();
|
||||||
let bot = Bot::new(
|
let mut bot = Bot::new(
|
||||||
login.as_str(),
|
login.as_str(),
|
||||||
oauth.as_str(),
|
oauth.as_str(),
|
||||||
Payload { content: String::new() },
|
Payload { content: String::new() },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bot.add_command("!ping".to_owned(), Box::new(PingCommand {})).await;
|
||||||
|
bot.add_command("!urm".to_owned(), Box::new(UrmCommand {})).await;
|
||||||
// bot.add_command()
|
|
||||||
|
|
||||||
bot.run().await;
|
bot.run().await;
|
||||||
|
|
||||||
println!("hello world!")
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue