once_cell -> std

This commit is contained in:
seth 2024-03-30 03:04:32 -04:00
parent a41a84fd2d
commit 90387c5a3b
No known key found for this signature in database
GPG key ID: D31BD0D494BBEE86
28 changed files with 157 additions and 153 deletions

1
Cargo.lock generated
View file

@ -1497,7 +1497,6 @@ dependencies = [
"gray_matter", "gray_matter",
"log", "log",
"octocrab", "octocrab",
"once_cell",
"owo-colors 4.0.0", "owo-colors 4.0.0",
"poise", "poise",
"rand", "rand",

View file

@ -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"
once_cell = "1.19.0"
owo-colors = "4.0.0" owo-colors = "4.0.0"
rand = "0.8.5" rand = "0.8.5"
redis = { version = "0.25.2", features = ["tokio-comp", "tokio-rustls-comp"] } redis = { version = "0.25.2", features = ["tokio-comp", "tokio-rustls-comp"] }

View file

@ -1,5 +1,3 @@
use crate::api::REQWEST_CLIENT;
use eyre::Result; use eyre::Result;
use log::debug; use log::debug;
@ -8,7 +6,7 @@ const DADJOKE: &str = "https://icanhazdadjoke.com";
pub async fn get_joke() -> Result<String> { pub async fn get_joke() -> Result<String> {
debug!("Making request to {DADJOKE}"); debug!("Making request to {DADJOKE}");
let resp = REQWEST_CLIENT let resp = super::client()
.get(DADJOKE) .get(DADJOKE)
.header("Accept", "text/plain") .header("Accept", "text/plain")
.send() .send()

View file

@ -1,16 +1,18 @@
use std::sync::Arc; use std::sync::{Arc, OnceLock};
use eyre::{Context, OptionExt, Result}; use eyre::{Context, OptionExt, Result};
use log::debug; use log::debug;
use octocrab::Octocrab; use octocrab::Octocrab;
use once_cell::sync::Lazy;
static OCTOCRAB: Lazy<Arc<Octocrab>> = Lazy::new(octocrab::instance); fn octocrab() -> &'static Arc<Octocrab> {
static OCTOCRAB: OnceLock<Arc<Octocrab>> = OnceLock::new();
OCTOCRAB.get_or_init(octocrab::instance)
}
pub async fn get_latest_prism_version() -> Result<String> { pub async fn get_latest_prism_version() -> Result<String> {
debug!("Fetching the latest version of Prism Launcher"); debug!("Fetching the latest version of Prism Launcher");
let version = OCTOCRAB let version = octocrab()
.repos("PrismLauncher", "PrismLauncher") .repos("PrismLauncher", "PrismLauncher")
.releases() .releases()
.get_latest() .get_latest()
@ -23,7 +25,7 @@ pub async fn get_latest_prism_version() -> Result<String> {
pub async fn get_prism_stargazers_count() -> Result<u32> { pub async fn get_prism_stargazers_count() -> Result<u32> {
debug!("Fetching Prism Launcher's stargazer count"); debug!("Fetching Prism Launcher's stargazer count");
let stargazers_count = OCTOCRAB let stargazers_count = octocrab()
.repos("PrismLauncher", "PrismLauncher") .repos("PrismLauncher", "PrismLauncher")
.get() .get()
.await .await

View file

@ -1,4 +1,8 @@
use once_cell::sync::Lazy; use std::sync::OnceLock;
use eyre::Result;
use log::debug;
use reqwest::{Client, Response};
pub mod dadjoke; pub mod dadjoke;
pub mod github; pub mod github;
@ -7,15 +11,36 @@ pub mod pluralkit;
pub mod prism_meta; pub mod prism_meta;
pub mod rory; pub mod rory;
pub static USER_AGENT: Lazy<String> = Lazy::new(|| { pub fn client() -> &'static reqwest::Client {
let version = option_env!("CARGO_PKG_VERSION").unwrap_or("development"); static CLIENT: OnceLock<Client> = OnceLock::new();
CLIENT.get_or_init(|| {
let version = option_env!("CARGO_PKG_VERSION").unwrap_or("development");
let user_agent = format!("refraction/{version}");
Client::builder()
.user_agent(user_agent)
.build()
.unwrap_or_default()
})
}
format!("refraction/{version}") pub async fn get_url(url: &str) -> Result<Response> {
}); debug!("Making request to {url}");
let resp = client().get(url).send().await?;
resp.error_for_status_ref()?;
pub static REQWEST_CLIENT: Lazy<reqwest::Client> = Lazy::new(|| { Ok(resp)
reqwest::Client::builder() }
.user_agent(USER_AGENT.to_string())
.build() pub async fn text_from_url(url: &str) -> Result<String> {
.unwrap_or_default() let resp = get_url(url).await?;
});
let text = resp.text().await?;
Ok(text)
}
pub async fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
let resp = get_url(url).await?;
let bytes = resp.bytes().await?;
Ok(bytes.to_vec())
}

View file

@ -1,5 +1,3 @@
use crate::{api::REQWEST_CLIENT, utils};
use eyre::{eyre, OptionExt, Result}; use eyre::{eyre, OptionExt, Result};
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,7 +30,7 @@ pub struct Files {
pub async fn get_files(id: &str) -> Result<Response<Files>> { pub async fn get_files(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 = REQWEST_CLIENT.get(url).send().await?; let resp = super::client().get(url).send().await?;
resp.error_for_status_ref()?; resp.error_for_status_ref()?;
let resp: Response<Files> = resp.json().await?; let resp: Response<Files> = resp.json().await?;
@ -49,7 +47,7 @@ pub async fn get_files(id: &str) -> Result<Response<Files>> {
pub async fn get_raw_file(paste_id: &str, file_id: &str) -> eyre::Result<String> { pub async fn get_raw_file(paste_id: &str, file_id: &str) -> eyre::Result<String> {
let url = format!("{PASTE_GG}{PASTES}/{paste_id}/files/{file_id}/raw"); let url = format!("{PASTE_GG}{PASTES}/{paste_id}/files/{file_id}/raw");
let text = utils::text_from_url(&url).await?; let text = super::text_from_url(&url).await?;
Ok(text) Ok(text)
} }

View file

@ -1,5 +1,3 @@
use crate::api::REQWEST_CLIENT;
use eyre::{Context, Result}; use eyre::{Context, Result};
use log::debug; use log::debug;
use poise::serenity_prelude::{MessageId, UserId}; use poise::serenity_prelude::{MessageId, UserId};
@ -17,7 +15,7 @@ pub async fn get_sender(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 = REQWEST_CLIENT.get(url).send().await?; let resp = super::client().get(url).send().await?;
resp.error_for_status_ref()?; resp.error_for_status_ref()?;
let data: Message = resp.json().await?; let data: Message = resp.json().await?;

View file

@ -1,5 +1,3 @@
use crate::api::REQWEST_CLIENT;
use eyre::{OptionExt, Result}; use eyre::{OptionExt, Result};
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -20,7 +18,7 @@ pub async fn get_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}");
let resp = REQWEST_CLIENT.get(url).send().await?; let resp = super::client().get(url).send().await?;
resp.error_for_status_ref()?; resp.error_for_status_ref()?;
let data: MinecraftPackageJson = resp.json().await?; let data: MinecraftPackageJson = resp.json().await?;

View file

@ -1,5 +1,3 @@
use crate::api::REQWEST_CLIENT;
use eyre::{Context, Result}; use eyre::{Context, Result};
use log::debug; use log::debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -20,10 +18,7 @@ pub async fn get(id: Option<u64>) -> Result<Response> {
debug!("Making request to {url}"); debug!("Making request to {url}");
let resp = REQWEST_CLIENT let resp = super::client().get(url).send().await?;
.get(format!("{RORY}{PURR}/{target}"))
.send()
.await?;
resp.error_for_status_ref()?; resp.error_for_status_ref()?;
let data: Response = resp let data: Response = resp

View file

@ -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(consts::COLORS["blue"]); .color(consts::colors()["blue"]);
let reply = CreateReply::default().embed(embed); let reply = CreateReply::default().embed(embed);
ctx.send(reply).await?; ctx.send(reply).await?;

View file

@ -27,7 +27,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(consts::COLORS["yellow"]); .color(consts::colors()["yellow"]);
let reply = CreateReply::default().embed(embed); let reply = CreateReply::default().embed(embed);
ctx.send(reply).await?; ctx.send(reply).await?;

View file

@ -1,16 +1,18 @@
#![allow(non_camel_case_types, clippy::upper_case_acronyms)] #![allow(non_camel_case_types, clippy::upper_case_acronyms)]
use crate::tags::Tag; use crate::{consts, tags::Tag, Context};
use crate::{consts, Context};
use std::env; use std::env;
use std::sync::OnceLock;
use eyre::{eyre, Result}; use eyre::{eyre, Result};
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::{Color, CreateEmbed, User}; use poise::serenity_prelude::{Color, CreateEmbed, User};
use poise::CreateReply; use poise::CreateReply;
include!(concat!(env!("OUT_DIR"), "/generated.rs")); include!(concat!(env!("OUT_DIR"), "/generated.rs"));
static TAGS: Lazy<Vec<Tag>> = Lazy::new(|| serde_json::from_str(env!("TAGS")).unwrap()); fn tags() -> &'static Vec<Tag> {
static TAGS: OnceLock<Vec<Tag>> = OnceLock::new();
TAGS.get_or_init(|| serde_json::from_str(env!("TAGS")).unwrap())
}
/// Send a tag /// Send a tag
#[poise::command( #[poise::command(
@ -27,7 +29,7 @@ pub async fn tag(
trace!("Running tag command"); trace!("Running tag command");
let tag_id = name.as_str(); let tag_id = name.as_str();
let tag = TAGS let tag = tags()
.iter() .iter()
.find(|t| t.id == tag_id) .find(|t| t.id == tag_id)
.ok_or_else(|| eyre!("Tried to get non-existent tag: {tag_id}"))?; .ok_or_else(|| eyre!("Tried to get non-existent tag: {tag_id}"))?;
@ -38,7 +40,7 @@ pub async fn tag(
let mut e = CreateEmbed::new(); let mut e = CreateEmbed::new();
if let Some(color) = &frontmatter.color { if let Some(color) = &frontmatter.color {
let color = *consts::COLORS let color = *consts::colors()
.get(color.as_str()) .get(color.as_str())
.unwrap_or(&Color::default()); .unwrap_or(&Color::default());
e = e.color(color); e = e.color(color);
@ -76,7 +78,7 @@ pub async fn tag(
} }
fn help() -> String { fn help() -> String {
let tag_list = TAGS let tag_list = tags()
.iter() .iter()
.map(|tag| format!("`{}`", tag.id)) .map(|tag| format!("`{}`", tag.id))
.collect::<Vec<String>>() .collect::<Vec<String>>()

View file

@ -1,6 +1,6 @@
use std::{fmt::Write, str::FromStr}; use std::{fmt::Write, str::FromStr};
use crate::{utils, Context}; use crate::{api, utils, Context};
use eyre::{bail, Result}; use eyre::{bail, Result};
use log::trace; use log::trace;
@ -144,7 +144,7 @@ pub async fn set_welcome(
return Ok(()); return Ok(());
} }
utils::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?;
return Ok(()); return Ok(());

View file

@ -1,15 +1,17 @@
use std::collections::HashMap; use std::{collections::HashMap, sync::OnceLock};
use once_cell::sync::Lazy;
use poise::serenity_prelude::Color; use poise::serenity_prelude::Color;
pub static COLORS: Lazy<HashMap<&str, Color>> = Lazy::new(|| { pub fn colors() -> &'static HashMap<&'static str, Color> {
HashMap::from([ static COLORS: OnceLock<HashMap<&str, Color>> = OnceLock::new();
("red", Color::from((239, 68, 68))), COLORS.get_or_init(|| {
("green", Color::from((34, 197, 94))), HashMap::from([
("blue", Color::from((96, 165, 250))), ("red", Color::from((239, 68, 68))),
("yellow", Color::from((253, 224, 71))), ("green", Color::from((34, 197, 94))),
("orange", Color::from((251, 146, 60))), ("blue", Color::from((96, 165, 250))),
// TODO purple & pink :D ("yellow", Color::from((253, 224, 71))),
]) ("orange", Color::from((251, 146, 60))),
}); // TODO purple & pink :D
])
})
}

View file

@ -34,7 +34,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(consts::COLORS["red"]); .color(consts::colors()["red"]);
let reply = CreateReply::default().embed(embed); let reply = CreateReply::default().embed(embed);

View file

@ -1,8 +1,9 @@
use crate::{api, Data}; use crate::{api, Data};
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
pub type Issue = Option<(String, String)>; pub type Issue = Option<(String, String)>;
@ -103,12 +104,15 @@ fn intel_hd(log: &str) -> Issue {
} }
fn java_option(log: &str) -> Issue { fn java_option(log: &str) -> Issue {
static VM_OPTION_REGEX: Lazy<Regex> = static VM_OPTION_REGEX: OnceLock<Regex> = OnceLock::new();
Lazy::new(|| Regex::new(r"Unrecognized VM option '(.+)'[\r\n]").unwrap()); static UNRECOGNIZED_OPTION_REGEX: OnceLock<Regex> = OnceLock::new();
static OPTION_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"Unrecognized option: (.+)[\r\n]").unwrap());
if let Some(captures) = VM_OPTION_REGEX.captures(log) { let vm_option =
VM_OPTION_REGEX.get_or_init(|| Regex::new(r"Unrecognized VM option '(.+)'[\r\n]").unwrap());
let unrecognized_option = UNRECOGNIZED_OPTION_REGEX
.get_or_init(|| Regex::new(r"Unrecognized option: (.+)[\r\n]").unwrap());
if let Some(captures) = vm_option.captures(log) {
let title = if &captures[1] == "UseShenandoahGC" { let title = if &captures[1] == "UseShenandoahGC" {
"Wrong Java Arguments" "Wrong Java Arguments"
} else { } else {
@ -120,7 +124,7 @@ fn java_option(log: &str) -> Issue {
)); ));
} }
if let Some(captures) = OPTION_REGEX.captures(log) { if let Some(captures) = unrecognized_option.captures(log) {
return Some(( return Some((
"Wrong Java Arguments".to_string(), "Wrong Java Arguments".to_string(),
format!("Remove `{}` from your Java arguments", &captures[1]), format!("Remove `{}` from your Java arguments", &captures[1]),
@ -180,10 +184,11 @@ fn optinotfine(log: &str) -> Issue {
} }
async fn outdated_launcher(log: &str, data: &Data) -> Result<Issue> { async fn outdated_launcher(log: &str, data: &Data) -> Result<Issue> {
static OUTDATED_LAUNCHER_REGEX: Lazy<Regex> = static OUTDATED_LAUNCHER_REGEX: OnceLock<Regex> = OnceLock::new();
Lazy::new(|| Regex::new("Prism Launcher version: [0-9].[0-9].[0-9]").unwrap()); let outdated_launcher = OUTDATED_LAUNCHER_REGEX
.get_or_init(|| Regex::new("Prism Launcher version: [0-9].[0-9].[0-9]").unwrap());
let Some(captures) = OUTDATED_LAUNCHER_REGEX.captures(log) else { let Some(captures) = outdated_launcher.captures(log) else {
return Ok(None); return Ok(None);
}; };
@ -235,13 +240,12 @@ which is why the issue was not present."
} }
fn wrong_java(log: &str) -> Issue { fn wrong_java(log: &str) -> Issue {
static SWITCH_VERSION_REGEX: Lazy<Regex> = Lazy::new(|| { static SWITCH_VERSION_REGEX: OnceLock<Regex> = OnceLock::new();
Regex::new( let switch_version = SWITCH_VERSION_REGEX.get_or_init(|| Regex::new(
r"(?m)Please switch to one of the following Java versions for this instance:[\r\n]+(Java version [\d.]+)", r"(?m)Please switch to one of the following Java versions for this instance:[\r\n]+(Java version [\d.]+)",
).unwrap() ).unwrap());
});
if let Some(captures) = SWITCH_VERSION_REGEX.captures(log) { if let Some(captures) = switch_version.captures(log) {
let versions = captures[1].split('\n').collect::<Vec<&str>>().join(", "); let versions = captures[1].split('\n').collect::<Vec<&str>>().join(", ");
return Some(( return Some((
"Wrong Java Version".to_string(), "Wrong Java Version".to_string(),

View file

@ -1,5 +1,4 @@
use crate::consts::COLORS; use crate::{consts, Data};
use crate::Data;
use eyre::Result; use eyre::Result;
use log::{debug, trace}; use log::{debug, trace};
@ -49,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(consts::colors()["green"])
.description("No issues found automatically"); .description("No issues found automatically");
} else { } else {
e = e.color(COLORS["red"]); e = e.color(consts::colors()["red"]);
for (title, description) in issues { for (title, description) in issues {
e = e.field(title, description, false); e = e.field(title, description, false);

View file

@ -1,8 +1,9 @@
use crate::utils; use crate::api;
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -10,17 +11,18 @@ pub struct _0x0;
impl super::LogProvider for _0x0 { impl super::LogProvider for _0x0 {
async fn find_match(&self, message: &Message) -> Option<String> { async fn find_match(&self, message: &Message) -> Option<String> {
static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"https://0x0\.st/\w*.\w*").unwrap()); static REGEX: OnceLock<Regex> = OnceLock::new();
let regex = REGEX.get_or_init(|| Regex::new(r"https://0x0\.st/\w*.\w*").unwrap());
trace!("Checking if message {} is a 0x0 paste", message.id); trace!("Checking if message {} is a 0x0 paste", message.id);
REGEX regex
.find_iter(&message.content) .find_iter(&message.content)
.map(|m| m.as_str().to_string()) .map(|m| m.as_str().to_string())
.nth(0) .nth(0)
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {
let log = utils::text_from_url(content).await?; let log = api::text_from_url(content).await?;
Ok(log) Ok(log)
} }

View file

@ -2,7 +2,7 @@ use eyre::Result;
use log::trace; use log::trace;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use crate::utils; use crate::api;
pub struct Attachment; pub struct Attachment;
@ -22,7 +22,7 @@ impl super::LogProvider for Attachment {
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {
let attachment = utils::bytes_from_url(content).await?; let attachment = api::bytes_from_url(content).await?;
let log = String::from_utf8(attachment)?; let log = String::from_utf8(attachment)?;
Ok(log) Ok(log)
} }

View file

@ -1,8 +1,9 @@
use crate::utils; use crate::api;
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -13,16 +14,17 @@ pub struct Haste;
impl super::LogProvider for Haste { impl super::LogProvider for Haste {
async fn find_match(&self, message: &Message) -> Option<String> { async fn find_match(&self, message: &Message) -> Option<String> {
static REGEX: Lazy<Regex> = static REGEX: OnceLock<Regex> = OnceLock::new();
Lazy::new(|| Regex::new(r"https://hst\.sh(?:/raw)?/(\w+(?:\.\w*)?)").unwrap()); let regex =
REGEX.get_or_init(|| Regex::new(r"https://hst\.sh(?:/raw)?/(\w+(?:\.\w*)?)").unwrap());
trace!("Checking if message {} is a hst.sh paste", message.id); trace!("Checking if message {} is a hst.sh paste", message.id);
super::get_first_capture(&REGEX, &message.content) super::get_first_capture(regex, &message.content)
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {
let url = format!("{HASTE}{RAW}/{content}"); let url = format!("{HASTE}{RAW}/{content}");
let log = utils::text_from_url(&url).await?; let log = api::text_from_url(&url).await?;
Ok(log) Ok(log)
} }

View file

@ -1,8 +1,9 @@
use crate::utils; use crate::api;
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -13,15 +14,16 @@ pub struct MCLogs;
impl super::LogProvider for MCLogs { impl super::LogProvider for MCLogs {
async fn find_match(&self, message: &Message) -> Option<String> { async fn find_match(&self, message: &Message) -> Option<String> {
static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"https://mclo\.gs/(\w+)").unwrap()); static REGEX: OnceLock<Regex> = OnceLock::new();
let regex = REGEX.get_or_init(|| Regex::new(r"https://mclo\.gs/(\w+)").unwrap());
trace!("Checking if message {} is an mclo.gs paste", message.id); trace!("Checking if message {} is an mclo.gs paste", message.id);
super::get_first_capture(&REGEX, &message.content) super::get_first_capture(regex, &message.content)
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {
let url = format!("{MCLOGS}{RAW}/{content}"); let url = format!("{MCLOGS}{RAW}/{content}");
let log = utils::text_from_url(&url).await?; let log = api::text_from_url(&url).await?;
Ok(log) Ok(log)
} }

View file

@ -2,7 +2,6 @@ use std::slice::Iter;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use eyre::Result; use eyre::Result;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -25,7 +24,7 @@ pub trait LogProvider {
async fn fetch(&self, content: &str) -> Result<String>; async fn fetch(&self, content: &str) -> Result<String>;
} }
fn get_first_capture(regex: &Lazy<Regex>, string: &str) -> Option<String> { fn get_first_capture(regex: &Regex, string: &str) -> Option<String> {
regex regex
.captures_iter(string) .captures_iter(string)
.find_map(|c| c.get(1).map(|c| c.as_str().to_string())) .find_map(|c| c.get(1).map(|c| c.as_str().to_string()))

View file

@ -1,8 +1,9 @@
use crate::api::paste_gg; use crate::api::paste_gg;
use std::sync::OnceLock;
use eyre::{OptionExt, Result}; use eyre::{OptionExt, Result};
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -10,11 +11,11 @@ pub struct PasteGG;
impl super::LogProvider for PasteGG { impl super::LogProvider for PasteGG {
async fn find_match(&self, message: &Message) -> Option<String> { async fn find_match(&self, message: &Message) -> Option<String> {
static REGEX: Lazy<Regex> = static REGEX: OnceLock<Regex> = OnceLock::new();
Lazy::new(|| Regex::new(r"https://paste.gg/p/\w+/(\w+)").unwrap()); let regex = REGEX.get_or_init(|| Regex::new(r"https://paste.gg/p/\w+/(\w+)").unwrap());
trace!("Checking if message {} is a paste.gg paste", message.id); trace!("Checking if message {} is a paste.gg paste", message.id);
super::get_first_capture(&REGEX, &message.content) super::get_first_capture(regex, &message.content)
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {

View file

@ -1,8 +1,9 @@
use crate::utils; use crate::api;
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::Message; use poise::serenity_prelude::Message;
use regex::Regex; use regex::Regex;
@ -13,16 +14,17 @@ pub struct PasteBin;
impl super::LogProvider for PasteBin { impl super::LogProvider for PasteBin {
async fn find_match(&self, message: &Message) -> Option<String> { async fn find_match(&self, message: &Message) -> Option<String> {
static REGEX: Lazy<Regex> = static REGEX: OnceLock<Regex> = OnceLock::new();
Lazy::new(|| Regex::new(r"https://pastebin\.com(?:/raw)?/(\w+)").unwrap()); let regex =
REGEX.get_or_init(|| Regex::new(r"https://pastebin\.com(?:/raw)?/(\w+)").unwrap());
trace!("Checking if message {} is a pastebin paste", message.id); trace!("Checking if message {} is a pastebin paste", message.id);
super::get_first_capture(&REGEX, &message.content) super::get_first_capture(regex, &message.content)
} }
async fn fetch(&self, content: &str) -> Result<String> { async fn fetch(&self, content: &str) -> Result<String> {
let url = format!("{PASTEBIN}{RAW}/{content}"); let url = format!("{PASTEBIN}{RAW}/{content}");
let log = utils::text_from_url(&url).await?; let log = api::text_from_url(&url).await?;
Ok(log) Ok(log)
} }

View file

@ -1,13 +1,17 @@
use std::sync::OnceLock;
use eyre::Result; use eyre::Result;
use log::trace; use log::trace;
use once_cell::sync::Lazy;
use poise::serenity_prelude::{Context, Message}; use poise::serenity_prelude::{Context, Message};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use regex::Regex; use regex::Regex;
static ETA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\beta\b").unwrap()); fn regex() -> &'static Regex {
static REGEX: OnceLock<Regex> = OnceLock::new();
REGEX.get_or_init(|| Regex::new(r"\beta\b").unwrap())
}
const ETA_MESSAGES: [&str; 16] = [ const MESSAGES: [&str; 16] = [
"Sometime", "Sometime",
"Some day", "Some day",
"Not far", "Not far",
@ -27,7 +31,7 @@ const ETA_MESSAGES: [&str; 16] = [
]; ];
pub async fn handle(ctx: &Context, message: &Message) -> Result<()> { pub async fn handle(ctx: &Context, message: &Message) -> Result<()> {
if !ETA_REGEX.is_match(&message.content) { if !regex().is_match(&message.content) {
trace!( trace!(
"The message '{}' (probably) doesn't say ETA", "The message '{}' (probably) doesn't say ETA",
message.content message.content
@ -37,7 +41,7 @@ pub async fn handle(ctx: &Context, message: &Message) -> Result<()> {
let response = format!( let response = format!(
"{} <:pofat:1031701005559144458>", "{} <:pofat:1031701005559144458>",
ETA_MESSAGES MESSAGES
.choose(&mut rand::thread_rng()) .choose(&mut rand::thread_rng())
.unwrap_or(&"sometime") .unwrap_or(&"sometime")
); );

View file

@ -33,7 +33,7 @@ use storage::Storage;
type Context<'a> = poise::Context<'a, Data, Report>; type Context<'a> = poise::Context<'a, Data, Report>;
#[derive(Clone)] #[derive(Clone, Debug, Default)]
pub struct Data { pub struct Data {
config: Config, config: Config,
storage: Option<Storage>, storage: Option<Storage>,

View file

@ -1,34 +1,7 @@
use crate::api::REQWEST_CLIENT;
use eyre::Result;
use log::debug;
use poise::serenity_prelude::{CreateEmbedAuthor, User}; use poise::serenity_prelude::{CreateEmbedAuthor, User};
use reqwest::Response;
pub mod resolve_message; pub mod resolve_message;
pub async fn get_url(url: &str) -> Result<Response> {
debug!("Making request to {url}");
let resp = REQWEST_CLIENT.get(url).send().await?;
resp.error_for_status_ref()?;
Ok(resp)
}
pub async fn text_from_url(url: &str) -> Result<String> {
let resp = get_url(url).await?;
let text = resp.text().await?;
Ok(text)
}
pub async fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
let resp = get_url(url).await?;
let bytes = resp.bytes().await?;
Ok(bytes.to_vec())
}
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(
user.avatar_url() user.avatar_url()

View file

@ -1,9 +1,9 @@
use crate::api::pluralkit; use crate::api::pluralkit;
use std::str::FromStr;
use std::{str::FromStr, sync::OnceLock};
use eyre::{eyre, Context as _, Result}; use eyre::{eyre, Context as _, Result};
use log::{debug, trace}; use log::{debug, trace};
use once_cell::sync::Lazy;
use poise::serenity_prelude::{ use poise::serenity_prelude::{
Cache, CacheHttp, ChannelId, ChannelType, Colour, Context, CreateEmbed, CreateEmbedAuthor, Cache, CacheHttp, ChannelId, ChannelType, Colour, Context, CreateEmbed, CreateEmbedAuthor,
CreateEmbedFooter, GuildChannel, Member, Message, MessageId, Permissions, UserId, CreateEmbedFooter, GuildChannel, Member, Message, MessageId, Permissions, UserId,
@ -36,8 +36,9 @@ async fn member_can_view_channel(
member: &Member, member: &Member,
channel: &GuildChannel, channel: &GuildChannel,
) -> Result<bool> { ) -> Result<bool> {
static REQUIRED_PERMISSIONS: Lazy<Permissions> = static REQUIRED_PERMISSIONS: OnceLock<Permissions> = OnceLock::new();
Lazy::new(|| Permissions::VIEW_CHANNEL | Permissions::READ_MESSAGE_HISTORY); let required_permissions = REQUIRED_PERMISSIONS
.get_or_init(|| Permissions::VIEW_CHANNEL | Permissions::READ_MESSAGE_HISTORY);
let guild = ctx.http().get_guild(channel.guild_id).await?; let guild = ctx.http().get_guild(channel.guild_id).await?;
@ -60,7 +61,7 @@ async fn member_can_view_channel(
let can_view = guild let can_view = guild
.user_permissions_in(&channel_to_check, member) .user_permissions_in(&channel_to_check, member)
.contains(*REQUIRED_PERMISSIONS); .contains(*required_permissions);
Ok(can_view) Ok(can_view)
} }
@ -109,9 +110,8 @@ pub async fn to_embed(
} }
pub async fn from_message(ctx: &Context, msg: &Message) -> Result<Vec<CreateEmbed>> { pub async fn from_message(ctx: &Context, msg: &Message) -> Result<Vec<CreateEmbed>> {
static MESSAGE_PATTERN: Lazy<Regex> = Lazy::new(|| { static MESSAGE_PATTERN: OnceLock<Regex> = OnceLock::new();
Regex::new(r"(?:https?:\/\/)?(?:canary\.|ptb\.)?discord(?:app)?\.com\/channels\/(?<server_id>\d+)\/(?<channel_id>\d+)\/(?<message_id>\d+)").unwrap() let message_pattern = MESSAGE_PATTERN.get_or_init(|| Regex::new(r"(?:https?:\/\/)?(?:canary\.|ptb\.)?discord(?:app)?\.com\/channels\/(?<server_id>\d+)\/(?<channel_id>\d+)\/(?<message_id>\d+)").unwrap());
});
let Some(guild_id) = msg.guild_id else { let Some(guild_id) = msg.guild_id else {
debug!("Not resolving message in DM"); debug!("Not resolving message in DM");
@ -128,7 +128,7 @@ pub async fn from_message(ctx: &Context, msg: &Message) -> Result<Vec<CreateEmbe
let author = guild_id.member(ctx, author_id).await?; let author = guild_id.member(ctx, author_id).await?;
let matches = MESSAGE_PATTERN let matches = message_pattern
.captures_iter(&msg.content) .captures_iter(&msg.content)
.map(|capture| capture.extract()); .map(|capture| capture.extract());