Add botrulez
This commit is contained in:
parent
5655fa7c4a
commit
a0d55482cc
7 changed files with 266 additions and 1 deletions
|
|
@ -22,7 +22,7 @@ tokio-tungstenite = { version = "0.18.0", features = ["rustls-tls-native-roots"]
|
||||||
version = "4.1.3"
|
version = "4.1.3"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["std"]
|
features = ["std", "derive", "deprecated"]
|
||||||
|
|
||||||
[dev-dependencies] # For example bot
|
[dev-dependencies] # For example bot
|
||||||
tokio = { version = "1.23.0", features = ["rt-multi-thread"] }
|
tokio = { version = "1.23.0", features = ["rt-multi-thread"] }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! Building blocks for bots.
|
//! Building blocks for bots.
|
||||||
|
|
||||||
|
pub mod botrulez;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
|
|
|
||||||
10
src/bot/botrulez.rs
Normal file
10
src/bot/botrulez.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
//! The main [botrulez](https://github.com/jedevc/botrulez) commands.
|
||||||
|
mod full_help;
|
||||||
|
mod ping;
|
||||||
|
mod short_help;
|
||||||
|
mod uptime;
|
||||||
|
|
||||||
|
pub use self::full_help::{FullHelp, HasDescriptions};
|
||||||
|
pub use self::ping::Ping;
|
||||||
|
pub use self::short_help::ShortHelp;
|
||||||
|
pub use self::uptime::{format_duration, format_time, HasStartTime, Uptime};
|
||||||
76
src/bot/botrulez/full_help.rs
Normal file
76
src/bot/botrulez/full_help.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use crate::api::Message;
|
||||||
|
use crate::bot::command::{ClapCommand, Context};
|
||||||
|
use crate::bot::commands::CommandInfo;
|
||||||
|
use crate::conn;
|
||||||
|
|
||||||
|
/// Show full bot help.
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct Args {}
|
||||||
|
|
||||||
|
pub struct FullHelp {
|
||||||
|
pub before: String,
|
||||||
|
pub after: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FullHelp {
|
||||||
|
pub fn new<S1: ToString, S2: ToString>(before: S1, after: S2) -> Self {
|
||||||
|
Self {
|
||||||
|
before: before.to_string(),
|
||||||
|
after: after.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasDescriptions {
|
||||||
|
fn descriptions(&self) -> &[CommandInfo];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<B, E> ClapCommand<B, E> for FullHelp
|
||||||
|
where
|
||||||
|
B: HasDescriptions + Send,
|
||||||
|
E: From<conn::Error>,
|
||||||
|
{
|
||||||
|
type Args = Args;
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
_args: Self::Args,
|
||||||
|
msg: &Message,
|
||||||
|
ctx: &Context,
|
||||||
|
bot: &mut B,
|
||||||
|
) -> Result<(), E> {
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
if !self.before.is_empty() {
|
||||||
|
result.push_str(&self.before);
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
for help in bot.descriptions() {
|
||||||
|
if !help.visible {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let usage = help.kind.usage(&help.name, &ctx.joined.session.name);
|
||||||
|
let line = if let Some(description) = &help.description {
|
||||||
|
format!("{usage} - {description}\n")
|
||||||
|
} else {
|
||||||
|
format!("{usage}\n")
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push_str(&line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.after.is_empty() {
|
||||||
|
result.push_str(&self.after);
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.reply(msg.id, result).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/bot/botrulez/ping.rs
Normal file
43
src/bot/botrulez/ping.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use crate::api::Message;
|
||||||
|
use crate::bot::command::{ClapCommand, Context};
|
||||||
|
use crate::conn;
|
||||||
|
|
||||||
|
/// Trigger a short reply.
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct Args {}
|
||||||
|
|
||||||
|
pub struct Ping(pub String);
|
||||||
|
|
||||||
|
impl Ping {
|
||||||
|
pub fn new<S: ToString>(reply: S) -> Self {
|
||||||
|
Self(reply.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Ping {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new("Pong!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<B, E> ClapCommand<B, E> for Ping
|
||||||
|
where
|
||||||
|
E: From<conn::Error>,
|
||||||
|
{
|
||||||
|
type Args = Args;
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
_args: Self::Args,
|
||||||
|
msg: &Message,
|
||||||
|
ctx: &Context,
|
||||||
|
_bot: &mut B,
|
||||||
|
) -> Result<(), E> {
|
||||||
|
ctx.reply(msg.id, &self.0).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/bot/botrulez/short_help.rs
Normal file
37
src/bot/botrulez/short_help.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use crate::api::Message;
|
||||||
|
use crate::bot::command::{ClapCommand, Context};
|
||||||
|
use crate::conn;
|
||||||
|
|
||||||
|
/// Show short bot help.
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct Args {}
|
||||||
|
|
||||||
|
pub struct ShortHelp(pub String);
|
||||||
|
|
||||||
|
impl ShortHelp {
|
||||||
|
pub fn new<S: ToString>(text: S) -> Self {
|
||||||
|
Self(text.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<B, E> ClapCommand<B, E> for ShortHelp
|
||||||
|
where
|
||||||
|
E: From<conn::Error>,
|
||||||
|
{
|
||||||
|
type Args = Args;
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
_args: Self::Args,
|
||||||
|
msg: &Message,
|
||||||
|
ctx: &Context,
|
||||||
|
_bot: &mut B,
|
||||||
|
) -> Result<(), E> {
|
||||||
|
ctx.reply(msg.id, &self.0).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/bot/botrulez/uptime.rs
Normal file
98
src/bot/botrulez/uptime.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use clap::Parser;
|
||||||
|
use time::macros::format_description;
|
||||||
|
use time::{Duration, OffsetDateTime, UtcOffset};
|
||||||
|
|
||||||
|
use crate::api::Message;
|
||||||
|
use crate::bot::command::{ClapCommand, Context};
|
||||||
|
use crate::conn;
|
||||||
|
|
||||||
|
/// Show how long the bot has been online.
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct Args {
|
||||||
|
/// Show how long the bot has been connected without interruption.
|
||||||
|
#[arg(long, short)]
|
||||||
|
connected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Uptime;
|
||||||
|
|
||||||
|
pub trait HasStartTime {
|
||||||
|
fn start_time(&self) -> OffsetDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_time(t: OffsetDateTime) -> String {
|
||||||
|
let t = t.to_offset(UtcOffset::UTC);
|
||||||
|
let format = format_description!("[year]-[month]-[day] [hour]:[minute]:[second] UTC");
|
||||||
|
t.format(format).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_duration(d: Duration) -> String {
|
||||||
|
let d_abs = d.abs();
|
||||||
|
let days = d_abs.whole_days();
|
||||||
|
let hours = d_abs.whole_hours() % 60;
|
||||||
|
let mins = d_abs.whole_minutes() % 60;
|
||||||
|
let secs = d_abs.whole_seconds() % 60;
|
||||||
|
|
||||||
|
let mut segments = vec![];
|
||||||
|
if days > 0 {
|
||||||
|
segments.push(format!("{days}d"));
|
||||||
|
}
|
||||||
|
if hours > 0 {
|
||||||
|
segments.push(format!("{hours}h"));
|
||||||
|
}
|
||||||
|
if mins > 0 {
|
||||||
|
segments.push(format!("{mins}m"));
|
||||||
|
}
|
||||||
|
if secs > 0 {
|
||||||
|
segments.push(format!("{secs}s"));
|
||||||
|
}
|
||||||
|
if segments.is_empty() {
|
||||||
|
segments.push("0s".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let segments = segments.join(" ");
|
||||||
|
if d.is_positive() {
|
||||||
|
format!("in {segments}")
|
||||||
|
} else {
|
||||||
|
format!("{segments} ago")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<B, E> ClapCommand<B, E> for Uptime
|
||||||
|
where
|
||||||
|
B: HasStartTime + Send,
|
||||||
|
E: From<conn::Error>,
|
||||||
|
{
|
||||||
|
type Args = Args;
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
args: Self::Args,
|
||||||
|
msg: &Message,
|
||||||
|
ctx: &Context,
|
||||||
|
bot: &mut B,
|
||||||
|
) -> Result<(), E> {
|
||||||
|
let start = bot.start_time();
|
||||||
|
let now = OffsetDateTime::now_utc();
|
||||||
|
|
||||||
|
let mut reply = format!(
|
||||||
|
"/me has been up since {} ({})",
|
||||||
|
format_time(start),
|
||||||
|
format_duration(start - now),
|
||||||
|
);
|
||||||
|
|
||||||
|
if args.connected {
|
||||||
|
let since = ctx.joined.since;
|
||||||
|
reply.push_str(&format!(
|
||||||
|
", connected since {} ({})",
|
||||||
|
format_time(since),
|
||||||
|
format_duration(since - now),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.reply(msg.id, reply).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue