Make instance channel unbounFOO

This commit is contained in:
Joscha 2024-12-27 19:38:18 +01:00
parent 38556a16dd
commit 9798136dc4
2 changed files with 94 additions and 68 deletions

View file

@ -1,79 +1,82 @@
use std::time::Duration; use std::{sync::Arc, time::Duration};
use async_trait::async_trait;
use euphoxide::{ use euphoxide::{
api::{Data, Message, Nick, Send}, api::{Data, Message, Nick, ParsedPacket, Send},
client::conn::ClientConnHandle, client::{conn::ClientConnHandle, state::State},
}; };
use euphoxide_bot::{ use euphoxide_bot::{
bot::{Bot, BotEvent}, bot::Bot,
command::{
botrulez::{FullHelp, HasCommandInfos, HasStartTime, Ping, ShortHelp, Uptime},
Command, CommandExt, Commands, Context, Info, Propagate,
},
instance::ServerConfig, instance::ServerConfig,
}; };
use jiff::Timestamp;
async fn set_nick(conn: &ClientConnHandle) -> anyhow::Result<()> { struct Pyramid;
conn.send_only(Nick {
name: "examplebot".to_string(),
})
.await?;
Ok(()) #[async_trait]
} impl Command<BotState> for Pyramid {
fn info(&self, _ctx: &Context) -> Info {
async fn send_pong(conn: &ClientConnHandle, msg: Message) -> anyhow::Result<()> { Info::new().with_description("build a pyramid")
conn.send_only(Send {
content: "Pong!".to_string(),
parent: Some(msg.id),
})
.await?;
Ok(())
}
async fn send_pyramid(conn: &ClientConnHandle, msg: Message) -> anyhow::Result<()> {
let mut parent = msg.id;
for _ in 0..3 {
let first = conn
.send(Send {
content: "brick".to_string(),
parent: Some(parent),
})
.await?;
conn.send_only(Send {
content: "brick".to_string(),
parent: Some(parent),
})
.await?;
parent = first.await?.0.id;
tokio::time::sleep(Duration::from_secs(1)).await;
} }
conn.send_only(Send { async fn execute(
content: "brick".to_string(), &self,
parent: Some(parent), _arg: &str,
}) msg: &Message,
.await?; ctx: &Context,
_bot: &BotState,
) -> euphoxide::Result<Propagate> {
let mut parent = msg.id;
Ok(()) for _ in 0..3 {
let first = ctx.reply(parent, "brick").await?;
ctx.reply_only(parent, "brick").await?;
parent = first.await?.0.id;
tokio::time::sleep(Duration::from_secs(1)).await;
}
ctx.reply_only(parent, "brick").await?;
Ok(Propagate::No)
}
} }
async fn on_data(conn: ClientConnHandle, data: Data) { #[derive(Clone)]
let result = match data { struct BotState {
Data::SnapshotEvent(_) => set_nick(&conn).await, start_time: Timestamp,
Data::SendEvent(event) if event.0.content == "!ping" => send_pong(&conn, event.0).await, commands: Arc<Commands<Self>>,
Data::SendEvent(event) if event.0.content == "!pyramid" => { }
send_pyramid(&conn, event.0).await
}
_ => Ok(()),
};
if let Err(err) = result { impl HasStartTime for BotState {
println!("Error while responding: {err}"); fn start_time(&self) -> Timestamp {
self.start_time
}
}
impl HasCommandInfos for BotState {
fn command_infos(&self, ctx: &Context) -> Vec<Info> {
self.commands.infos(ctx)
} }
} }
async fn run() -> anyhow::Result<()> { async fn run() -> anyhow::Result<()> {
let commands = Commands::new()
.then(Ping::default())
.then(Uptime)
.then(ShortHelp::new("/me demonstrates how to use euphoxide"))
.then(FullHelp::new())
.then(Pyramid.global("pyramid"));
let commands = Arc::new(commands);
let state = BotState {
start_time: Timestamp::now(),
commands: commands.clone(),
};
let mut bot = Bot::new(); let mut bot = Bot::new();
let config = ServerConfig::default() let config = ServerConfig::default()
@ -83,10 +86,7 @@ async fn run() -> anyhow::Result<()> {
bot.add_instance(config); bot.add_instance(config);
while let Some(event) = bot.recv().await { while let Some(event) = bot.recv().await {
if let BotEvent::Packet { conn, packet, .. } = event { commands.on_bot_event(event, &state).await?;
let data = packet.into_data()?;
tokio::task::spawn(on_data(conn, data));
}
} }
Ok(()) Ok(())

View file

@ -7,6 +7,8 @@ pub mod clap;
use std::future::Future; use std::future::Future;
use async_trait::async_trait; use async_trait::async_trait;
use bang::{General, Global, Specific};
use basic::{Described, Prefixed};
use euphoxide::{ use euphoxide::{
api::{self, Data, Message, MessageId, ParsedPacket, SendEvent, SendReply}, api::{self, Data, Message, MessageId, ParsedPacket, SendEvent, SendReply},
client::{ client::{
@ -108,7 +110,7 @@ pub enum Propagate {
#[allow(unused_variables)] #[allow(unused_variables)]
#[async_trait] #[async_trait]
pub trait Command<B, E> { pub trait Command<B, E = euphoxide::Error> {
fn info(&self, ctx: &Context) -> Info { fn info(&self, ctx: &Context) -> Info {
Info::default() Info::default()
} }
@ -122,6 +124,34 @@ pub trait Command<B, E> {
) -> Result<Propagate, E>; ) -> Result<Propagate, E>;
} }
pub trait CommandExt<B, E>: Sized {
fn described(self) -> Described<Self> {
Described::new(self)
}
fn hidden(self) -> Described<Self> {
Described::hidden(self)
}
fn prefixed(self, prefix: impl ToString) -> Prefixed<Self> {
Prefixed::new(prefix, self)
}
fn general(self, name: impl ToString) -> General<Self> {
General::new(name, self)
}
fn global(self, name: impl ToString) -> Global<Self> {
Global::new(name, self)
}
fn specific(self, name: impl ToString) -> Specific<Self> {
Specific::new(name, self)
}
}
impl<B, E, C: Command<B, E>> CommandExt<B, E> for C {}
pub struct Commands<B, E = euphoxide::Error> { pub struct Commands<B, E = euphoxide::Error> {
commands: Vec<Box<dyn Command<B, E> + Sync + Send>>, commands: Vec<Box<dyn Command<B, E> + Sync + Send>>,
} }
@ -171,11 +201,7 @@ impl<B, E> Commands<B, E> {
Ok(Propagate::Yes) Ok(Propagate::Yes)
} }
pub async fn on_instance_event( pub async fn on_instance_event(&self, event: InstanceEvent, bot: &B) -> Result<Propagate, E> {
&self,
event: InstanceEvent,
bot: &B,
) -> Result<Propagate, E> {
if let InstanceEvent::Packet { if let InstanceEvent::Packet {
conn, conn,
state, state,