code
Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
parent
524f8a67c2
commit
2cb48f9cb6
|
@ -5,6 +5,8 @@
|
|||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
.env
|
||||
target
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
@ -58,3 +60,8 @@ luac.out
|
|||
*.hex
|
||||
|
||||
|
||||
|
||||
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "mara"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
envy = "0.4"
|
||||
furbooru = "0.3"
|
||||
kankyo = "0.3"
|
||||
reqwest = { version = "0.11.4", default-features = false, features = ["json", "multipart", "rustls-tls"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.2"
|
||||
|
||||
# bot library
|
||||
robespierre = { git = "https://github.com/dblanovschi/robespierre", features = ["cache", "events", "framework", "framework-macros"] }
|
||||
robespierre-cache = { git = "https://github.com/dblanovschi/robespierre" }
|
||||
robespierre-http = { git = "https://github.com/dblanovschi/robespierre" }
|
||||
robespierre-events = { git = "https://github.com/dblanovschi/robespierre" }
|
||||
robespierre-models = { git = "https://github.com/dblanovschi/robespierre" }
|
|
@ -0,0 +1,13 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
rustc
|
||||
rust-analyzer
|
||||
rustfmt
|
||||
clippy
|
||||
cargo
|
||||
openssl
|
||||
pkg-config
|
||||
];
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use furbooru::Client;
|
||||
use robespierre::framework::standard::{macros::command, CommandResult, FwContext};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub struct ClientKey;
|
||||
|
||||
impl robespierre::typemap::Key for ClientKey {
|
||||
type Value = Arc<Mutex<Client>>;
|
||||
}
|
||||
|
||||
pub fn make(username: String, api_key: String) -> Arc<Mutex<Client>> {
|
||||
Arc::new(Mutex::new(
|
||||
Client::new(user_agent(username), api_key).unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn user_agent(username: String) -> String {
|
||||
format!(
|
||||
"{}/{} (owner: {})",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
username,
|
||||
)
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub async fn search(ctx: &FWContext, msg: &Message, args: &str) -> CommandResult {
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod furbooru;
|
|
@ -0,0 +1,25 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Config {
|
||||
#[serde(skip_serializing)]
|
||||
pub revolt_token: String,
|
||||
|
||||
pub furbooru_bot_owner: String,
|
||||
#[serde(skip_serializing)]
|
||||
pub furbooru_token: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn make(&self) -> Arc<Mutex<Config>> {
|
||||
Arc::new(Mutex::new(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConfigKey;
|
||||
|
||||
impl robespierre::typemap::Key for ConfigKey {
|
||||
type Value = Arc<Mutex<Config>>;
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
use anyhow::Result;
|
||||
use robespierre::framework::standard::{macros::command, CommandResult, FwContext};
|
||||
use robespierre::framework::standard::{Command, CommandCodeFn, StandardFramework};
|
||||
use robespierre::model::MessageExt;
|
||||
use robespierre::Authentication;
|
||||
use robespierre::CacheWrap;
|
||||
use robespierre::Context;
|
||||
use robespierre::EventHandlerWrap;
|
||||
use robespierre::FrameworkWrap;
|
||||
use robespierre::UserData;
|
||||
use robespierre_cache::CacheConfig;
|
||||
use robespierre_events::Connection;
|
||||
use robespierre_http::Http;
|
||||
use robespierre_models::{channel::Message, events::ReadyEvent};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
struct CommandCounterKey;
|
||||
|
||||
impl robespierre::typemap::Key for CommandCounterKey {
|
||||
type Value = Arc<AtomicUsize>;
|
||||
}
|
||||
|
||||
struct ReqwestClientKey;
|
||||
|
||||
impl robespierre::typemap::Key for ReqwestClientKey {
|
||||
type Value = Arc<Mutex<reqwest::Client>>;
|
||||
}
|
||||
|
||||
mod commands;
|
||||
use commands::*;
|
||||
mod config;
|
||||
use config::*;
|
||||
|
||||
static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let _ = kankyo::init();
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let config: Config = envy::from_env()?;
|
||||
|
||||
let mut data = robespierre::typemap::ShareMap::custom();
|
||||
data.insert::<ConfigKey>(config.clone().make());
|
||||
|
||||
let auth = Authentication::bot(config.revolt_token);
|
||||
|
||||
let http = Http::new(&auth).await?;
|
||||
let connection = Connection::connect(&auth).await?;
|
||||
|
||||
data.insert::<furbooru::ClientKey>(furbooru::make(
|
||||
config.furbooru_token,
|
||||
config.furbooru_bot_owner,
|
||||
));
|
||||
data.insert::<CommandCounterKey>(Arc::new(AtomicUsize::new(0)));
|
||||
data.insert::<ReqwestClientKey>(Arc::new(Mutex::new(
|
||||
reqwest::Client::builder()
|
||||
.user_agent(APP_USER_AGENT)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)));
|
||||
let context = Context::new(http, data).with_cache(CacheConfig::default());
|
||||
|
||||
let fw = StandardFramework::default()
|
||||
.configure(|c| c.prefix("!"))
|
||||
.group(|g| {
|
||||
g.name("General")
|
||||
.command(|| Command::new("ping", ping as CommandCodeFn))
|
||||
.command(|| Command::new("command_counter", command_counter as CommandCodeFn))
|
||||
.command(|| Command::new("front", current_front as CommandCodeFn))
|
||||
});
|
||||
let handler = FrameworkWrap::new(fw, Handler);
|
||||
let handler = CacheWrap::new(EventHandlerWrap::new(handler));
|
||||
connection.run(context, handler).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn ping(ctx: &FwContext, msg: &Message, _args: &str) -> CommandResult {
|
||||
msg.reply(ctx, "pong").await?;
|
||||
|
||||
let data = ctx.data_lock_read().await;
|
||||
let counter = data.get::<CommandCounterKey>().unwrap();
|
||||
counter.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn command_counter(ctx: &FwContext, msg: &Message, _args: &str) -> CommandResult {
|
||||
let data = ctx.data_lock_read().await;
|
||||
let counter = data.get::<CommandCounterKey>().unwrap();
|
||||
let count = counter.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
msg.reply(
|
||||
ctx,
|
||||
format!("I received {} commands since I started running", count),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn current_front(ctx: &FwContext, msg: &Message, _args: &str) -> CommandResult {
|
||||
let data = ctx.data_lock_read().await;
|
||||
let client = data.get::<ReqwestClientKey>().unwrap().clone();
|
||||
let client = client.lock().await;
|
||||
|
||||
let front = client
|
||||
.get("https://home.cetacean.club/front")
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.text()
|
||||
.await?;
|
||||
tracing::debug!("got front: {}", front);
|
||||
|
||||
msg.reply(ctx, format!("Current front: {}", front)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Handler;
|
||||
|
||||
#[robespierre::async_trait]
|
||||
impl robespierre::EventHandler for Handler {
|
||||
async fn on_ready(&self, _: Context, _: ReadyEvent) {
|
||||
tracing::info!("bot is ready");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue