use anyhow::Result;
use runbot::prelude::*;
use std::{sync::Arc, time::Duration};
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
let bot_ctx = BotContextBuilder::new()
.url("ws://localhost:3001")
.add_processor(DEMO_MESSAGE_PROCESSOR_FN)
.add_processor(DEMO_NOTICE_PROCESSOR_FN)
.add_processor(DEMO_AUTO_APPROVE_FN)
.add_processor(DEMO_COMMAND_BAN)
.add_processor(EXAMPLE_MOD)
.build()
.unwrap();
loop_client(bot_ctx).await.unwrap();
}
#[processor]
pub async fn demo_message_processor_fn(
bot_ctx: Arc<BotContext>,
message: &Message,
) -> Result<bool> {
if message.raw_message.eq("hello") {
if let MessageSubType::Friend = message.sub_type {
let async_response = bot_ctx
.send_private_message(message.user_id, "world".to_string())
.await?;
let bot_ctx = bot_ctx.clone();
tokio::spawn(async move {
let msg_id = async_response.wait_response().await.unwrap().message_id;
tokio::time::sleep(Duration::from_secs(10)).await;
bot_ctx.delete_msg(msg_id).await.unwrap();
});
return Ok(true);
}
}
Ok(false)
}
#[processor]
pub async fn demo_notice_processor_fn(bot_ctx: Arc<BotContext>, notice: &Notice) -> Result<bool> {
match notice {
Notice::FriendRecall(friend_recall) => {
bot_ctx
.send_private_message(
friend_recall.user_id,
format!("{} 撤回了一条消息", friend_recall.user_id),
)
.await?;
return Ok(true);
}
_ => {}
}
Ok(false)
}
#[processor]
pub async fn demo_auto_approve_fn(bot_ctx: Arc<BotContext>, request: &Request) -> Result<bool> {
match request {
Request::Friend(friend_request) => {
bot_ctx
.set_friend_add_request(friend_request.flag.as_str(), true, None)
.await?;
return Ok(true);
}
_ => {}
}
Ok(false)
}
#[processor(command = "[-|/|~]ban {time:n}[unit:s|m|h]? {user:n}+")]
pub async fn demo_command_ban(
bot_ctx: Arc<BotContext>,
message: &Message,
time: i64,
unit: Option<String>,
user: Vec<i64>,
) -> Result<bool> {
let unit = match unit {
Some(unit) => match unit.as_str() {
"s" => 1,
"m" => 60,
"h" => 3600,
_ => unreachable!(),
},
None => 1,
};
let time = time * unit;
let msg = format!("禁用用户 {:?} {time}秒", user);
match message.message_type {
MessageType::Group => {
bot_ctx.send_group_message(message.group_id, msg).await?;
}
MessageType::Private => {
bot_ctx.send_private_message(message.user_id, msg).await?;
}
_ => {}
}
Ok(true)
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_demo_command_ban() {
let bot_ctx = BotContextBuilder::new().build().unwrap();
let message = Message {
message_type: MessageType::Group,
message: vec![MessageData::Text(MessageText {
text: "-ban 10 1234567890".to_string(),
})],
..Default::default()
};
let result = DemoCommandBan
.process_message(bot_ctx, &message)
.await
.unwrap();
assert!(result);
}
}
#[module(
name = "ExampleMod",
help = "help()",
processors = "mod_process_a+mod_process_b_instance()"
)]
impl Module for ExampleMod {}
fn help() -> &'static str {
"我是帮助"
}
#[processor]
async fn mod_process_a(_bot_ctx: Arc<BotContext>, _messgae: &Message) -> Result<bool> {
Ok(false)
}
#[processor]
async fn mod_process_b(_bot_ctx: Arc<BotContext>, _messgae: &Message) -> Result<bool> {
Ok(false)
}
fn mod_process_b_instance() -> Processor {
MOD_PROCESS_B.into()
}