clean up
This commit is contained in:
parent
9dfc3b21ff
commit
0b0779f8b7
32 changed files with 137 additions and 181 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -263,7 +263,7 @@ dependencies = [
|
||||||
"eyre",
|
"eyre",
|
||||||
"indenter",
|
"indenter",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"owo-colors 3.5.0",
|
"owo-colors",
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"owo-colors 3.5.0",
|
"owo-colors",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
]
|
]
|
||||||
|
@ -1235,12 +1235,6 @@ version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "owo-colors"
|
|
||||||
version = "4.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -1459,7 +1453,6 @@ dependencies = [
|
||||||
"gray_matter",
|
"gray_matter",
|
||||||
"log",
|
"log",
|
||||||
"octocrab",
|
"octocrab",
|
||||||
"owo-colors 4.0.0",
|
|
||||||
"poise",
|
"poise",
|
||||||
"redis",
|
"redis",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -1467,7 +1460,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -23,7 +23,6 @@ eyre = "0.6.11"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
poise = "0.6.1"
|
poise = "0.6.1"
|
||||||
octocrab = "0.37.0"
|
octocrab = "0.37.0"
|
||||||
owo-colors = "4.0.0"
|
|
||||||
redis = { version = "0.25.2", features = ["tokio-comp", "tokio-rustls-comp"] }
|
redis = { version = "0.25.2", features = ["tokio-comp", "tokio-rustls-comp"] }
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
reqwest = { version = "0.12.2", default-features = false, features = [
|
reqwest = { version = "0.12.2", default-features = false, features = [
|
||||||
|
@ -37,7 +36,17 @@ tokio = { version = "1.35.1", features = [
|
||||||
"rt-multi-thread",
|
"rt-multi-thread",
|
||||||
"signal",
|
"signal",
|
||||||
] }
|
] }
|
||||||
url = { version = "2.5.0", features = ["serde"] }
|
|
||||||
|
[lints.rust]
|
||||||
|
unsafe_code = "forbid"
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
complexity = "warn"
|
||||||
|
correctness = "deny"
|
||||||
|
pedantic = "warn"
|
||||||
|
perf = "warn"
|
||||||
|
style = "warn"
|
||||||
|
suspicious = "deny"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
2
build.rs
2
build.rs
|
@ -6,7 +6,7 @@ use gray_matter::{engine, Matter};
|
||||||
|
|
||||||
include!("src/tags.rs");
|
include!("src/tags.rs");
|
||||||
|
|
||||||
/// generate the ChoiceParameter enum and tag data we will use in the `tag` command
|
/// generate the `ChoiceParameter` enum and tag data we will use in the `tag` command
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use eyre::{Context, OptionExt, Result};
|
use eyre::{Context, OptionExt, Result};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use octocrab::Octocrab;
|
use octocrab::Octocrab;
|
||||||
|
|
||||||
fn octocrab() -> &'static Arc<Octocrab> {
|
fn octocrab() -> &'static Octocrab {
|
||||||
static OCTOCRAB: OnceLock<Arc<Octocrab>> = OnceLock::new();
|
static OCTOCRAB: OnceLock<Octocrab> = OnceLock::new();
|
||||||
OCTOCRAB.get_or_init(octocrab::instance)
|
OCTOCRAB.get_or_init(Octocrab::default)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_latest_prism_version() -> Result<String> {
|
pub async fn get_latest_prism_version() -> Result<String> {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::sync::OnceLock;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use reqwest::{Client, Response};
|
use reqwest::{Client, Response};
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
pub mod dadjoke;
|
pub mod dadjoke;
|
||||||
pub mod github;
|
pub mod github;
|
||||||
|
@ -44,3 +45,10 @@ pub async fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
|
||||||
let bytes = resp.bytes().await?;
|
let bytes = resp.bytes().await?;
|
||||||
Ok(bytes.to_vec())
|
Ok(bytes.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn json_from_url<T: DeserializeOwned>(url: &str) -> Result<T> {
|
||||||
|
let resp = get_url(url).await?;
|
||||||
|
|
||||||
|
let json = resp.json().await?;
|
||||||
|
Ok(json)
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ const PASTE_GG: &str = "https://api.paste.gg/v1";
|
||||||
const PASTES: &str = "/pastes";
|
const PASTES: &str = "/pastes";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||||
enum Status {
|
pub enum Status {
|
||||||
#[serde(rename = "success")]
|
#[serde(rename = "success")]
|
||||||
Success,
|
Success,
|
||||||
#[serde(rename = "error")]
|
#[serde(rename = "error")]
|
||||||
|
@ -15,10 +15,10 @@ enum Status {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Response<T> {
|
pub struct Response<T> {
|
||||||
status: Status,
|
pub status: Status,
|
||||||
pub result: Option<Vec<T>>,
|
pub result: Option<Vec<T>>,
|
||||||
error: Option<String>,
|
pub error: Option<String>,
|
||||||
message: Option<String>,
|
pub message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -27,12 +27,11 @@ pub struct Files {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_files(id: &str) -> Result<Response<Files>> {
|
pub async fn files_from(id: &str) -> Result<Response<Files>> {
|
||||||
let url = format!("{PASTE_GG}{PASTES}/{id}/files");
|
let url = format!("{PASTE_GG}{PASTES}/{id}/files");
|
||||||
debug!("Making request to {url}");
|
debug!("Making request to {url}");
|
||||||
let resp = super::client().get(url).send().await?;
|
|
||||||
resp.error_for_status_ref()?;
|
let resp: Response<Files> = super::json_from_url(&url).await?;
|
||||||
let resp: Response<Files> = resp.json().await?;
|
|
||||||
|
|
||||||
if resp.status == Status::Error {
|
if resp.status == Status::Error {
|
||||||
let message = resp
|
let message = resp
|
||||||
|
|
|
@ -11,17 +11,15 @@ pub struct Message {
|
||||||
const PLURAL_KIT: &str = "https://api.pluralkit.me/v2";
|
const PLURAL_KIT: &str = "https://api.pluralkit.me/v2";
|
||||||
const MESSAGES: &str = "/messages";
|
const MESSAGES: &str = "/messages";
|
||||||
|
|
||||||
pub async fn get_sender(message_id: MessageId) -> Result<UserId> {
|
pub async fn sender_from(message_id: MessageId) -> Result<UserId> {
|
||||||
let url = format!("{PLURAL_KIT}{MESSAGES}/{message_id}");
|
let url = format!("{PLURAL_KIT}{MESSAGES}/{message_id}");
|
||||||
|
|
||||||
debug!("Making request to {url}");
|
debug!("Making request to {url}");
|
||||||
let resp = super::client().get(url).send().await?;
|
|
||||||
resp.error_for_status_ref()?;
|
|
||||||
|
|
||||||
let data: Message = resp.json().await?;
|
let resp: Message = super::json_from_url(&url).await?;
|
||||||
|
|
||||||
let id: u64 =
|
let id: u64 =
|
||||||
data.sender.parse().wrap_err_with(|| {
|
resp.sender.parse().wrap_err_with(|| {
|
||||||
format!("Couldn't parse response from PluralKit as a UserId! Here's the response:\n{data:#?}")
|
format!("Couldn't parse response from PluralKit as a UserId! Here's the response:\n{resp:#?}")
|
||||||
})?;
|
})?;
|
||||||
let sender = UserId::from(id);
|
let sender = UserId::from(id);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub struct MinecraftPackageJson {
|
||||||
const META: &str = "https://meta.prismlauncher.org/v1";
|
const META: &str = "https://meta.prismlauncher.org/v1";
|
||||||
const MINECRAFT_PACKAGEJSON: &str = "/net.minecraft/package.json";
|
const MINECRAFT_PACKAGEJSON: &str = "/net.minecraft/package.json";
|
||||||
|
|
||||||
pub async fn get_latest_minecraft_version() -> Result<String> {
|
pub async fn latest_minecraft_version() -> Result<String> {
|
||||||
let url = format!("{META}{MINECRAFT_PACKAGEJSON}");
|
let url = format!("{META}{MINECRAFT_PACKAGEJSON}");
|
||||||
|
|
||||||
debug!("Making request to {url}");
|
debug!("Making request to {url}");
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::Context;
|
use crate::{Context, Error};
|
||||||
|
|
||||||
use eyre::Result;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::samples::HelpConfiguration;
|
use poise::samples::HelpConfiguration;
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ use poise::samples::HelpConfiguration;
|
||||||
pub async fn help(
|
pub async fn help(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "Provide information about a specific command"] command: Option<String>,
|
#[description = "Provide information about a specific command"] command: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
trace!("Running help command");
|
trace!("Running help command");
|
||||||
|
|
||||||
let configuration = HelpConfiguration {
|
let configuration = HelpConfiguration {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::api::dadjoke;
|
use crate::{api::dadjoke, Context, Error};
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
/// It's a joke
|
/// It's a joke
|
||||||
#[poise::command(slash_command, prefix_command, track_edits = true)]
|
#[poise::command(slash_command, prefix_command, track_edits = true)]
|
||||||
pub async fn joke(ctx: Context<'_>) -> Result<()> {
|
pub async fn joke(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
trace!("Running joke command");
|
trace!("Running joke command");
|
||||||
|
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use crate::{consts::Colors, Context};
|
use crate::{consts::Colors, Context, Error};
|
||||||
|
|
||||||
use eyre::{eyre, Context as _, OptionExt, Result};
|
use eyre::{eyre, Context as _, OptionExt};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::CreateEmbed;
|
use poise::serenity_prelude::CreateEmbed;
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
|
|
||||||
/// Returns the number of members in the server
|
/// Returns the number of members in the server
|
||||||
#[poise::command(slash_command, prefix_command, guild_only = true, track_edits = true)]
|
#[poise::command(slash_command, prefix_command, guild_only = true, track_edits = true)]
|
||||||
pub async fn members(ctx: Context<'_>) -> Result<()> {
|
pub async fn members(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
trace!("Running members command");
|
trace!("Running members command");
|
||||||
|
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
|
@ -29,7 +29,7 @@ pub async fn members(ctx: Context<'_>) -> Result<()> {
|
||||||
let embed = CreateEmbed::new()
|
let embed = CreateEmbed::new()
|
||||||
.title(format!("{member_count} total members!",))
|
.title(format!("{member_count} total members!",))
|
||||||
.description(format!("{online_count} online members",))
|
.description(format!("{online_count} online members",))
|
||||||
.color(Colors::BLUE);
|
.color(Colors::Blue);
|
||||||
let reply = CreateReply::default().embed(embed);
|
let reply = CreateReply::default().embed(embed);
|
||||||
|
|
||||||
ctx.send(reply).await?;
|
ctx.send(reply).await?;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::Context;
|
use crate::{Context, Error};
|
||||||
|
|
||||||
use eyre::Result;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
/// Replies with pong!
|
/// Replies with pong!
|
||||||
#[poise::command(slash_command, prefix_command, track_edits = true, ephemeral)]
|
#[poise::command(slash_command, prefix_command, track_edits = true, ephemeral)]
|
||||||
pub async fn ping(ctx: Context<'_>) -> Result<()> {
|
pub async fn ping(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
trace!("Running ping command!");
|
trace!("Running ping command!");
|
||||||
ctx.say("Pong!").await?;
|
ctx.say("Pong!").await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::api::rory;
|
use crate::{api::rory, Context, Error};
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
use eyre::Result;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::{CreateEmbed, CreateEmbedFooter};
|
use poise::serenity_prelude::{CreateEmbed, CreateEmbedFooter};
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
|
@ -11,7 +9,7 @@ use poise::CreateReply;
|
||||||
pub async fn rory(
|
pub async fn rory(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "specify a Rory ID"] id: Option<u64>,
|
#[description = "specify a Rory ID"] id: Option<u64>,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
trace!("Running rory command");
|
trace!("Running rory command");
|
||||||
|
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{utils, Context};
|
use crate::{utils, Context, Error};
|
||||||
|
|
||||||
use eyre::Result;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::{CreateEmbed, CreateMessage};
|
use poise::serenity_prelude::{CreateEmbed, CreateMessage};
|
||||||
|
|
||||||
|
@ -15,18 +14,12 @@ use poise::serenity_prelude::{CreateEmbed, CreateMessage};
|
||||||
pub async fn say(
|
pub async fn say(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "the message content"] content: String,
|
#[description = "the message content"] content: String,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
let channel = ctx.channel_id();
|
let channel = ctx.channel_id();
|
||||||
channel.say(ctx, &content).await?;
|
channel.say(ctx, &content).await?;
|
||||||
ctx.say("I said what you said!").await?;
|
ctx.say("I said what you said!").await?;
|
||||||
|
|
||||||
if let Some(channel_id) = ctx
|
if let Some(channel_id) = ctx.data().config.discord.channels.log_channel_id {
|
||||||
.data()
|
|
||||||
.config
|
|
||||||
.discord_config()
|
|
||||||
.channels()
|
|
||||||
.log_channel_id()
|
|
||||||
{
|
|
||||||
let author = utils::embed_author_from_user(ctx.author());
|
let author = utils::embed_author_from_user(ctx.author());
|
||||||
|
|
||||||
let embed = CreateEmbed::default()
|
let embed = CreateEmbed::default()
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use crate::{api, consts::Colors, Context};
|
use crate::{api, consts::Colors, Context, Error};
|
||||||
|
|
||||||
use eyre::Result;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::CreateEmbed;
|
use poise::serenity_prelude::CreateEmbed;
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
|
|
||||||
/// Returns GitHub stargazer count
|
/// Returns GitHub stargazer count
|
||||||
#[poise::command(slash_command, prefix_command, track_edits = true)]
|
#[poise::command(slash_command, prefix_command, track_edits = true)]
|
||||||
pub async fn stars(ctx: Context<'_>) -> Result<()> {
|
pub async fn stars(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
trace!("Running stars command");
|
trace!("Running stars command");
|
||||||
|
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
|
@ -27,7 +26,7 @@ pub async fn stars(ctx: Context<'_>) -> Result<()> {
|
||||||
|
|
||||||
let embed = CreateEmbed::new()
|
let embed = CreateEmbed::new()
|
||||||
.title(format!("⭐ {count} total stars!"))
|
.title(format!("⭐ {count} total stars!"))
|
||||||
.color(Colors::YELLOW);
|
.color(Colors::Yellow);
|
||||||
let reply = CreateReply::default().embed(embed);
|
let reply = CreateReply::default().embed(embed);
|
||||||
|
|
||||||
ctx.send(reply).await?;
|
ctx.send(reply).await?;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
use crate::{consts::Colors, tags::Tag, Context};
|
use crate::{consts::Colors, tags::Tag, Context, Error};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use eyre::{eyre, Result};
|
use eyre::eyre;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::{Color, CreateEmbed, User};
|
use poise::serenity_prelude::{Color, CreateEmbed, User};
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
|
@ -26,7 +26,7 @@ pub async fn tag(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "the tag to send"] name: Choice,
|
#[description = "the tag to send"] name: Choice,
|
||||||
#[description = "a user to mention"] user: Option<User>,
|
#[description = "a user to mention"] user: Option<User>,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
trace!("Running tag command");
|
trace!("Running tag command");
|
||||||
|
|
||||||
let tag_id = name.as_str();
|
let tag_id = name.as_str();
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::Data;
|
use crate::{Data, Error};
|
||||||
|
|
||||||
use eyre::Report;
|
|
||||||
|
|
||||||
mod general;
|
mod general;
|
||||||
mod moderation;
|
mod moderation;
|
||||||
|
@ -32,7 +30,7 @@ macro_rules! module_macro {
|
||||||
module_macro!(general);
|
module_macro!(general);
|
||||||
module_macro!(moderation);
|
module_macro!(moderation);
|
||||||
|
|
||||||
pub type Command = poise::Command<Data, Report>;
|
pub type Command = poise::Command<Data, Error>;
|
||||||
|
|
||||||
pub fn get() -> Vec<Command> {
|
pub fn get() -> Vec<Command> {
|
||||||
vec![
|
vec![
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
use std::{fmt::Write, str::FromStr};
|
use std::{fmt::Write, str::FromStr};
|
||||||
|
|
||||||
use crate::{api, utils, Context};
|
use crate::{api, utils, Context, Error};
|
||||||
|
|
||||||
use eyre::{bail, Result};
|
use eyre::Result;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
futures::TryStreamExt, Attachment, CreateActionRow, CreateButton, CreateEmbed, CreateMessage,
|
futures::TryStreamExt, Attachment, CreateActionRow, CreateButton, CreateEmbed, CreateMessage,
|
||||||
Mentionable, Message, ReactionType,
|
Mentionable, Message, ReactionType,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct WelcomeEmbed {
|
struct WelcomeEmbed {
|
||||||
title: String,
|
title: String,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
url: Option<Url>,
|
url: Option<String>,
|
||||||
hex_color: Option<String>,
|
hex_color: Option<String>,
|
||||||
image: Option<Url>,
|
image: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<WelcomeEmbed> for CreateMessage {
|
impl From<WelcomeEmbed> for CreateMessage {
|
||||||
|
@ -112,11 +111,11 @@ pub async fn set_welcome(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "A file to use"] file: Option<Attachment>,
|
#[description = "A file to use"] file: Option<Attachment>,
|
||||||
#[description = "A URL for a file to use"] url: Option<String>,
|
#[description = "A URL for a file to use"] url: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
trace!("Running set_welcome command!");
|
trace!("Running set_welcome command!");
|
||||||
|
|
||||||
let configured_channels = ctx.data().config.discord_config().channels();
|
let configured_channels = ctx.data().config.discord.channels;
|
||||||
let Some(channel_id) = configured_channels.welcome_channel_id() else {
|
let Some(channel_id) = configured_channels.welcome_channel_id else {
|
||||||
ctx.say("You don't have a welcome channel ID set, so I can't do anything :(")
|
ctx.say("You don't have a welcome channel ID set, so I can't do anything :(")
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -127,7 +126,7 @@ pub async fn set_welcome(
|
||||||
// download attachment from discord or URL
|
// download attachment from discord or URL
|
||||||
let file = if let Some(attachment) = file {
|
let file = if let Some(attachment) = file {
|
||||||
let Some(content_type) = &attachment.content_type else {
|
let Some(content_type) = &attachment.content_type else {
|
||||||
bail!("Welcome channel attachment was sent without a content type!");
|
return Err("Welcome channel attachment was sent without a content type!".into());
|
||||||
};
|
};
|
||||||
|
|
||||||
if !content_type.starts_with("application/json;") {
|
if !content_type.starts_with("application/json;") {
|
||||||
|
@ -139,11 +138,6 @@ pub async fn set_welcome(
|
||||||
let downloaded = attachment.download().await?;
|
let downloaded = attachment.download().await?;
|
||||||
String::from_utf8(downloaded)?
|
String::from_utf8(downloaded)?
|
||||||
} else if let Some(url) = url {
|
} else if let Some(url) = url {
|
||||||
if Url::parse(&url).is_err() {
|
|
||||||
ctx.say("Invalid url!").await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
api::text_from_url(&url).await?
|
api::text_from_url(&url).await?
|
||||||
} else {
|
} else {
|
||||||
ctx.say("A text file or URL must be provided!").await?;
|
ctx.say("A text file or URL must be provided!").await?;
|
||||||
|
@ -180,7 +174,7 @@ pub async fn set_welcome(
|
||||||
channel_id.say(ctx, message).await?;
|
channel_id.say(ctx, message).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(log_channel) = configured_channels.log_channel_id() {
|
if let Some(log_channel) = configured_channels.log_channel_id {
|
||||||
let author = utils::embed_author_from_user(ctx.author());
|
let author = utils::embed_author_from_user(ctx.author());
|
||||||
let embed = CreateEmbed::new()
|
let embed = CreateEmbed::new()
|
||||||
.title("set_welcome command used!")
|
.title("set_welcome command used!")
|
||||||
|
|
|
@ -2,7 +2,7 @@ use log::{info, warn};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
redis_url: Option<String>,
|
pub redis_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -21,8 +21,4 @@ impl Config {
|
||||||
|
|
||||||
Self::new(redis_url)
|
Self::new(redis_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redis_url(&self) -> Option<&str> {
|
|
||||||
self.redis_url.as_deref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ use poise::serenity_prelude::ChannelId;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct RefractionChannels {
|
pub struct RefractionChannels {
|
||||||
log_channel_id: Option<ChannelId>,
|
pub log_channel_id: Option<ChannelId>,
|
||||||
welcome_channel_id: Option<ChannelId>,
|
pub welcome_channel_id: Option<ChannelId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
channels: RefractionChannels,
|
pub channels: RefractionChannels,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefractionChannels {
|
impl RefractionChannels {
|
||||||
|
@ -45,14 +45,6 @@ impl RefractionChannels {
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|env_var| ChannelId::from_str(&env_var).ok())
|
.and_then(|env_var| ChannelId::from_str(&env_var).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_channel_id(&self) -> Option<&ChannelId> {
|
|
||||||
self.log_channel_id.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn welcome_channel_id(&self) -> Option<&ChannelId> {
|
|
||||||
self.welcome_channel_id.as_ref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -65,8 +57,4 @@ impl Config {
|
||||||
|
|
||||||
Self::new(channels)
|
Self::new(channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channels(&self) -> &RefractionChannels {
|
|
||||||
&self.channels
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ mod discord;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
bot: bot::Config,
|
pub bot: bot::Config,
|
||||||
discord: discord::Config,
|
pub discord: discord::Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -21,12 +21,4 @@ impl Config {
|
||||||
|
|
||||||
Self::new(bot, discord)
|
Self::new(bot, discord)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bot_config(&self) -> &bot::Config {
|
|
||||||
&self.bot
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn discord_config(&self) -> &discord::Config {
|
|
||||||
&self.discord
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,31 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use poise::serenity_prelude::Colour;
|
use poise::serenity_prelude::Colour;
|
||||||
|
|
||||||
|
const BLUE: u32 = 0x60A5FA;
|
||||||
|
const GREEN: u32 = 0x22C55E;
|
||||||
|
const ORANGE: u32 = 0xFB923C;
|
||||||
|
const RED: u32 = 0xEF4444;
|
||||||
|
const YELLOW: u32 = 0xFDE047;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Colors(i32);
|
pub enum Colors {
|
||||||
|
Blue,
|
||||||
|
#[default]
|
||||||
|
Green,
|
||||||
|
Orange,
|
||||||
|
Red,
|
||||||
|
Yellow,
|
||||||
|
}
|
||||||
|
|
||||||
impl Colors {
|
impl From<Colors> for Colour {
|
||||||
pub const RED: i32 = 0xEF4444;
|
fn from(value: Colors) -> Self {
|
||||||
pub const GREEN: i32 = 0x22C55E;
|
Self::from(match &value {
|
||||||
pub const BLUE: i32 = 0x60A5FA;
|
Colors::Blue => BLUE,
|
||||||
pub const YELLOW: i32 = 0xFDE047;
|
Colors::Green => GREEN,
|
||||||
pub const ORANGE: i32 = 0xFB923C;
|
Colors::Orange => ORANGE,
|
||||||
|
Colors::Red => RED,
|
||||||
pub fn as_i32(self) -> i32 {
|
Colors::Yellow => YELLOW,
|
||||||
self.0
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +35,12 @@ impl FromStr for Colors {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.to_lowercase().as_str() {
|
match s.to_lowercase().as_str() {
|
||||||
"red" => Ok(Colors(Self::RED)),
|
"blue" => Ok(Self::Blue),
|
||||||
"green" => Ok(Colors(Self::GREEN)),
|
"green" => Ok(Self::Green),
|
||||||
"blue" => Ok(Colors(Self::BLUE)),
|
"orange" => Ok(Self::Orange),
|
||||||
"yellow" => Ok(Colors(Self::YELLOW)),
|
"red" => Ok(Self::Red),
|
||||||
"orange" => Ok(Colors(Self::ORANGE)),
|
"yellow" => Ok(Self::Yellow),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Colors> for Colour {
|
|
||||||
fn from(value: Colors) -> Self {
|
|
||||||
Self::from(value.as_i32())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::{consts::Colors, Data};
|
use crate::{consts::Colors, Data, Error};
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use eyre::Report;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use poise::serenity_prelude::{CreateEmbed, Timestamp};
|
use poise::serenity_prelude::{CreateEmbed, Timestamp};
|
||||||
use poise::{CreateReply, FrameworkError};
|
use poise::{CreateReply, FrameworkError};
|
||||||
|
@ -16,7 +15,7 @@ macro_rules! writelne {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle(error: FrameworkError<'_, Data, Report>) {
|
pub async fn handle(error: FrameworkError<'_, Data, Error>) {
|
||||||
match error {
|
match error {
|
||||||
FrameworkError::Setup {
|
FrameworkError::Setup {
|
||||||
error, framework, ..
|
error, framework, ..
|
||||||
|
@ -34,7 +33,7 @@ pub async fn handle(error: FrameworkError<'_, Data, Report>) {
|
||||||
.title("Something went wrong!")
|
.title("Something went wrong!")
|
||||||
.description("oopsie")
|
.description("oopsie")
|
||||||
.timestamp(Timestamp::now())
|
.timestamp(Timestamp::now())
|
||||||
.color(Colors::RED);
|
.color(Colors::Red);
|
||||||
|
|
||||||
let reply = CreateReply::default().embed(embed);
|
let reply = CreateReply::default().embed(embed);
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,9 @@ async fn outdated_launcher(log: &str, data: &Data) -> Result<Issue> {
|
||||||
if let Ok(version) = storage.launcher_version().await {
|
if let Ok(version) = storage.launcher_version().await {
|
||||||
version
|
version
|
||||||
} else {
|
} else {
|
||||||
api::github::get_latest_prism_version().await?
|
let version = api::github::get_latest_prism_version().await?;
|
||||||
|
storage.cache_launcher_version(&version).await?;
|
||||||
|
version
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!("Not caching launcher version, as we're running without a storage backend");
|
trace!("Not caching launcher version, as we're running without a storage backend");
|
||||||
|
|
|
@ -48,10 +48,10 @@ pub async fn handle(ctx: &Context, message: &Message, data: &Data) -> Result<()>
|
||||||
|
|
||||||
if issues.is_empty() {
|
if issues.is_empty() {
|
||||||
e = e
|
e = e
|
||||||
.color(Colors::GREEN)
|
.color(Colors::Green)
|
||||||
.description("No issues found automatically");
|
.description("No issues found automatically");
|
||||||
} else {
|
} else {
|
||||||
e = e.color(Colors::RED);
|
e = e.color(Colors::Red);
|
||||||
|
|
||||||
for (title, description) in issues {
|
for (title, description) in issues {
|
||||||
e = e.field(title, description, false);
|
e = e.field(title, description, false);
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl super::LogProvider for PasteGG {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch(&self, content: &str) -> Result<String> {
|
async fn fetch(&self, content: &str) -> Result<String> {
|
||||||
let files = paste_gg::get_files(content).await?;
|
let files = paste_gg::files_from(content).await?;
|
||||||
let result = files
|
let result = files
|
||||||
.result
|
.result
|
||||||
.ok_or_eyre("Got an empty result from paste.gg!")?;
|
.ok_or_eyre("Got an empty result from paste.gg!")?;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use poise::serenity_prelude::{Context, CreateAllowedMentions, CreateMessage, Mes
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
pub async fn handle(ctx: &Context, message: &Message) -> Result<()> {
|
pub async fn handle(ctx: &Context, message: &Message) -> Result<()> {
|
||||||
let embeds = utils::resolve_message::from_message(ctx, message).await?;
|
let embeds = utils::messages::from_message(ctx, message).await?;
|
||||||
|
|
||||||
if !embeds.is_empty() {
|
if !embeds.is_empty() {
|
||||||
let allowed_mentions = CreateAllowedMentions::new().replied_user(false);
|
let allowed_mentions = CreateAllowedMentions::new().replied_user(false);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{api, Data};
|
use crate::{api, Data, Error};
|
||||||
|
|
||||||
use eyre::{Report, Result};
|
|
||||||
use log::{debug, info, trace};
|
use log::{debug, info, trace};
|
||||||
use poise::serenity_prelude::{ActivityData, Context, FullEvent, OnlineStatus};
|
use poise::serenity_prelude::{ActivityData, Context, FullEvent, OnlineStatus};
|
||||||
use poise::FrameworkContext;
|
use poise::FrameworkContext;
|
||||||
|
@ -10,20 +9,20 @@ mod delete_on_reaction;
|
||||||
mod eta;
|
mod eta;
|
||||||
mod expand_link;
|
mod expand_link;
|
||||||
mod give_role;
|
mod give_role;
|
||||||
pub mod pluralkit;
|
mod pluralkit;
|
||||||
mod support_onboard;
|
mod support_onboard;
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
event: &FullEvent,
|
event: &FullEvent,
|
||||||
_: FrameworkContext<'_, Data, Report>,
|
_: FrameworkContext<'_, Data, Error>,
|
||||||
data: &Data,
|
data: &Data,
|
||||||
) -> Result<()> {
|
) -> Result<(), Error> {
|
||||||
match event {
|
match event {
|
||||||
FullEvent::Ready { data_about_bot } => {
|
FullEvent::Ready { data_about_bot } => {
|
||||||
info!("Logged in as {}!", data_about_bot.user.name);
|
info!("Logged in as {}!", data_about_bot.user.name);
|
||||||
|
|
||||||
let latest_minecraft_version = api::prism_meta::get_latest_minecraft_version().await?;
|
let latest_minecraft_version = api::prism_meta::latest_minecraft_version().await?;
|
||||||
let activity = ActivityData::playing(format!("Minecraft {latest_minecraft_version}"));
|
let activity = ActivityData::playing(format!("Minecraft {latest_minecraft_version}"));
|
||||||
|
|
||||||
info!("Setting presence to activity {activity:#?}");
|
info!("Setting presence to activity {activity:#?}");
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub async fn is_message_proxied(message: &Message) -> Result<bool> {
|
||||||
);
|
);
|
||||||
sleep(PK_DELAY).await;
|
sleep(PK_DELAY).await;
|
||||||
|
|
||||||
let proxied = api::pluralkit::get_sender(message.id).await.is_ok();
|
let proxied = api::pluralkit::sender_from(message.id).await.is_ok();
|
||||||
|
|
||||||
Ok(proxied)
|
Ok(proxied)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ pub async fn handle(_: &Context, msg: &Message, storage: &Storage) -> Result<()>
|
||||||
);
|
);
|
||||||
sleep(PK_DELAY).await;
|
sleep(PK_DELAY).await;
|
||||||
|
|
||||||
if let Ok(sender) = api::pluralkit::get_sender(msg.id).await {
|
if let Ok(sender) = api::pluralkit::sender_from(msg.id).await {
|
||||||
storage.store_user_plurality(sender).await?;
|
storage.store_user_plurality(sender).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
src/main.rs
38
src/main.rs
|
@ -1,18 +1,10 @@
|
||||||
#![warn(clippy::all, clippy::pedantic, clippy::perf)]
|
|
||||||
#![allow(clippy::missing_errors_doc)]
|
|
||||||
#![forbid(unsafe_code)]
|
|
||||||
|
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
use eyre::{bail, Context as _, Report, Result};
|
use eyre::Context as _;
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
|
|
||||||
use poise::{
|
use poise::{
|
||||||
serenity_prelude as serenity, EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions,
|
serenity_prelude as serenity, EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
use owo_colors::OwoColorize;
|
|
||||||
|
|
||||||
use tokio::signal::ctrl_c;
|
use tokio::signal::ctrl_c;
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
use tokio::signal::unix::{signal, SignalKind};
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
|
@ -31,7 +23,8 @@ mod utils;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use storage::Storage;
|
use storage::Storage;
|
||||||
|
|
||||||
type Context<'a> = poise::Context<'a, Data, Report>;
|
type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
type Context<'a> = poise::Context<'a, Data, Error>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
|
@ -39,21 +32,14 @@ pub struct Data {
|
||||||
storage: Option<Storage>,
|
storage: Option<Storage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(config: Config, storage: Option<Storage>) -> Self {
|
|
||||||
Self { config, storage }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup(
|
async fn setup(
|
||||||
ctx: &serenity::Context,
|
ctx: &serenity::Context,
|
||||||
_: &serenity::Ready,
|
_: &serenity::Ready,
|
||||||
framework: &Framework<Data, Report>,
|
framework: &Framework<Data, Error>,
|
||||||
) -> Result<Data> {
|
) -> Result<Data, Error> {
|
||||||
let config = Config::new_from_env();
|
let config = Config::new_from_env();
|
||||||
|
|
||||||
let storage = if let Some(url) = config.bot_config().redis_url() {
|
let storage = if let Some(url) = &config.bot.redis_url {
|
||||||
Some(Storage::from_url(url)?)
|
Some(Storage::from_url(url)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -61,13 +47,15 @@ async fn setup(
|
||||||
|
|
||||||
if let Some(storage) = storage.as_ref() {
|
if let Some(storage) = storage.as_ref() {
|
||||||
if !storage.clone().has_connection() {
|
if !storage.clone().has_connection() {
|
||||||
bail!("You specified a storage backend but there's no connection! Is it running?")
|
return Err(
|
||||||
|
"You specified a storage backend but there's no connection! Is it running?".into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Redis connection looks good!");
|
trace!("Redis connection looks good!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = Data::new(config, storage);
|
let data = Data { config, storage };
|
||||||
|
|
||||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||||
info!("Registered global commands!");
|
info!("Registered global commands!");
|
||||||
|
@ -78,11 +66,11 @@ async fn setup(
|
||||||
async fn handle_shutdown(shard_manager: Arc<serenity::ShardManager>, reason: &str) {
|
async fn handle_shutdown(shard_manager: Arc<serenity::ShardManager>, reason: &str) {
|
||||||
warn!("{reason}! Shutting down bot...");
|
warn!("{reason}! Shutting down bot...");
|
||||||
shard_manager.shutdown_all().await;
|
shard_manager.shutdown_all().await;
|
||||||
println!("{}", "Everything is shutdown. Goodbye!".green());
|
println!("Everything is shutdown. Goodbye!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> eyre::Result<()> {
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
@ -134,7 +122,7 @@ async fn main() -> Result<()> {
|
||||||
let mut sigterm = ctrl_close()?;
|
let mut sigterm = ctrl_close()?;
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
result = client.start() => result.map_err(Report::from),
|
result = client.start() => result.map_err(eyre::Report::from),
|
||||||
_ = sigterm.recv() => {
|
_ = sigterm.recv() => {
|
||||||
handle_shutdown(shard_manager, "Received SIGTERM").await;
|
handle_shutdown(shard_manager, "Received SIGTERM").await;
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
|
|
@ -24,7 +24,7 @@ fn find_first_image(message: &Message) -> Option<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_real_author_id(message: &Message) -> UserId {
|
async fn find_real_author_id(message: &Message) -> UserId {
|
||||||
if let Ok(sender) = pluralkit::get_sender(message.id).await {
|
if let Ok(sender) = pluralkit::sender_from(message.id).await {
|
||||||
sender
|
sender
|
||||||
} else {
|
} else {
|
||||||
message.author.id
|
message.author.id
|
|
@ -1,6 +1,6 @@
|
||||||
use poise::serenity_prelude::{CreateEmbedAuthor, User};
|
use poise::serenity_prelude::{CreateEmbedAuthor, User};
|
||||||
|
|
||||||
pub mod resolve_message;
|
pub mod messages;
|
||||||
|
|
||||||
pub fn embed_author_from_user(user: &User) -> CreateEmbedAuthor {
|
pub fn embed_author_from_user(user: &User) -> CreateEmbedAuthor {
|
||||||
CreateEmbedAuthor::new(user.tag()).icon_url(
|
CreateEmbedAuthor::new(user.tag()).icon_url(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue