summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock120
-rw-r--r--Cargo.toml3
-rw-r--r--flake.lock34
-rw-r--r--flake.nix5
-rw-r--r--parts/dev.nix5
-rw-r--r--parts/module.nix15
-rw-r--r--src/handlers/error.rs6
-rw-r--r--src/handlers/event/message.rs16
-rw-r--r--src/handlers/event/mod.rs10
-rw-r--r--src/handlers/event/pinboard.rs31
-rw-r--r--src/handlers/event/reactboard.rs143
-rw-r--r--src/main.rs8
-rw-r--r--src/settings.rs10
-rw-r--r--src/utils.rs2
15 files changed, 356 insertions, 54 deletions
diff --git a/.gitignore b/.gitignore
index 4206ea8..9953a8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,5 @@ result
.vs/
.vscode/
+# redis
+dump.rdb
diff --git a/Cargo.lock b/Cargo.lock
index 303384f..08e0a5d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -249,6 +249,20 @@ dependencies = [
]
[[package]]
+name = "combine"
+version = "4.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "memchr",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -901,6 +915,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1137,6 +1157,53 @@ dependencies = [
]
[[package]]
+name = "redis"
+version = "0.23.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f49cdc0bb3f412bf8e7d1bd90fe1d9eb10bc5c399ba90973c14662a27b3f8ba"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "combine",
+ "futures-util",
+ "itoa",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls 0.21.8",
+ "rustls-native-certs",
+ "ryu",
+ "sha1_smol",
+ "socket2 0.4.10",
+ "tokio",
+ "tokio-rustls 0.24.1",
+ "tokio-util",
+ "url",
+]
+
+[[package]]
+name = "redis-macros"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60eb39e2b44d4c0f9c84e7c5fc4fc3adc8dd26ec48f1ac3a160033f7c03b18fd"
+dependencies = [
+ "redis",
+ "redis-macros-derive",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "redis-macros-derive"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39550b9e94ce430a349c5490ca4efcae90ab8189603320f88c1d69f0326f169e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1290,6 +1357,18 @@ dependencies = [
]
[[package]]
+name = "rustls-native-certs"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
+dependencies = [
+ "openssl-probe",
+ "rustls-pemfile",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
name = "rustls-pemfile"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1321,6 +1400,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
+name = "schannel"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1337,6 +1425,29 @@ dependencies = [
]
[[package]]
+name = "security-framework"
+version = "2.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "serde"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1433,6 +1544,12 @@ dependencies = [
]
[[package]]
+name = "sha1_smol"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
+
+[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1571,8 +1688,11 @@ dependencies = [
"once_cell",
"poise",
"rand 0.8.5",
+ "redis",
+ "redis-macros",
"reqwest",
"serde",
+ "serde_json",
"tokio",
"url",
]
diff --git a/Cargo.toml b/Cargo.toml
index 9969c79..5b6f48f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,11 +18,14 @@ log = "0.4.20"
poise = "0.5.7"
once_cell = "1.18.0"
rand = "0.8.5"
+redis = { version = "0.23.3", features = ["tokio-comp", "tokio-rustls-comp"] }
+redis-macros = "0.2.1"
reqwest = { version = "0.11.22", default-features = false, features = [
"rustls-tls",
"json",
] }
serde = "1.0.193"
+serde_json = "1.0.108"
tokio = { version = "1.33.0", features = [
"macros",
"rt-multi-thread",
diff --git a/flake.lock b/flake.lock
index c15f48f..5815a4a 100644
--- a/flake.lock
+++ b/flake.lock
@@ -37,6 +37,21 @@
"type": "github"
}
},
+ "flake-root": {
+ "locked": {
+ "lastModified": 1692742795,
+ "narHash": "sha256-f+Y0YhVCIJ06LemO+3Xx00lIcqQxSKJHXT/yk1RTKxw=",
+ "owner": "srid",
+ "repo": "flake-root",
+ "rev": "d9a70d9c7a5fd7f3258ccf48da9335e9b47c3937",
+ "type": "github"
+ },
+ "original": {
+ "owner": "srid",
+ "repo": "flake-root",
+ "type": "github"
+ }
+ },
"flake-utils": {
"inputs": {
"systems": "systems"
@@ -158,13 +173,30 @@
"type": "github"
}
},
+ "proc-flake": {
+ "locked": {
+ "lastModified": 1692742849,
+ "narHash": "sha256-Nv8SOX+O6twFfPnA9BfubbPLZpqc+UeK6JvIWnWkdb0=",
+ "owner": "srid",
+ "repo": "proc-flake",
+ "rev": "25291b6e3074ad5dd573c1cb7d96110a9591e10f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "srid",
+ "repo": "proc-flake",
+ "type": "github"
+ }
+ },
"root": {
"inputs": {
"fenix": "fenix",
+ "flake-root": "flake-root",
"naersk": "naersk",
"nixpkgs": "nixpkgs",
"parts": "parts",
- "pre-commit": "pre-commit"
+ "pre-commit": "pre-commit",
+ "proc-flake": "proc-flake"
}
},
"rust-analyzer-src": {
diff --git a/flake.nix b/flake.nix
index 1738cc2..b4ec346 100644
--- a/flake.nix
+++ b/flake.nix
@@ -28,6 +28,9 @@
inputs.nixpkgs.follows = "nixpkgs";
};
+ proc-flake.url = "github:srid/proc-flake";
+ flake-root.url = "github:srid/flake-root";
+
pre-commit = {
url = "github:cachix/pre-commit-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
@@ -39,6 +42,8 @@
parts.lib.mkFlake {inherit inputs;} {
imports = [
inputs.pre-commit.flakeModule
+ inputs.proc-flake.flakeModule
+ inputs.flake-root.flakeModule
./parts/deployment.nix
./parts/dev.nix
diff --git a/parts/dev.nix b/parts/dev.nix
index 4cd51d6..5628e33 100644
--- a/parts/dev.nix
+++ b/parts/dev.nix
@@ -49,12 +49,17 @@
pkgs.linkFarm "ci-gate" paths;
};
+ proc.groups.daemons.processes = {
+ redis.command = lib.getExe' pkgs.redis "redis-server";
+ };
+
devShells = {
default = pkgs.mkShell {
packages = with pkgs; [
# general
actionlint
nodePackages_latest.prettier
+ config.proc.groups.daemons.package
# rust
cargo
diff --git a/parts/module.nix b/parts/module.nix
index 5c1af12..5048c13 100644
--- a/parts/module.nix
+++ b/parts/module.nix
@@ -22,6 +22,18 @@ in {
options.services.teawiebot = {
enable = mkEnableOption "teawiebot";
package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "teawiebot" {};
+
+ redisUrl = mkOption {
+ description = mdDoc ''
+ Redis URL for teawieBot
+ '';
+ type = types.str;
+ default = "unix:${config.services.redis.servers.teawiebot.unixSocket}";
+ example = literalExpression ''
+ "redis://localhost/"
+ '';
+ };
+
environmentFile = mkOption {
description = mdDoc ''
Environment file as defined in {manpage}`systemd.exec(5)`
@@ -35,6 +47,8 @@ in {
};
config = mkIf cfg.enable {
+ services.redis.servers.teawiebot.enable = true;
+
systemd.services."teawiebot" = {
enable = true;
wantedBy = mkDefault ["multi-user.target"];
@@ -48,6 +62,7 @@ in {
Restart = "always";
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
+ Environment = ["REDIS_URL=${cfg.redisUrl}"];
# hardening
DynamicUser = true;
diff --git a/src/handlers/error.rs b/src/handlers/error.rs
index b4e1361..e256bcf 100644
--- a/src/handlers/error.rs
+++ b/src/handlers/error.rs
@@ -11,7 +11,7 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Report>) {
FrameworkError::Setup { error, .. } => error!("error setting up client! {error:#?}"),
FrameworkError::Command { error, ctx } => {
- error!("error in command {}:\n{error:?}", ctx.command().name);
+ error!("Error in command {}:\n{error:?}", ctx.command().name);
ctx.send(|c| {
c.embed(|e| {
e.title("Something went wrong!")
@@ -30,12 +30,12 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Report>) {
event: _,
framework: _,
} => {
- error!("error while handling event:\n{error:#?}");
+ error!("Error while handling event:\n{error:#?}");
}
error => {
if let Err(e) = poise::builtins::on_error(error).await {
- error!("error while handling an error: {}", e);
+ error!("Unhandled error occured:\n{e:#?}");
}
}
}
diff --git a/src/handlers/event/message.rs b/src/handlers/event/message.rs
index 88faf85..c90ae3a 100644
--- a/src/handlers/event/message.rs
+++ b/src/handlers/event/message.rs
@@ -1,8 +1,8 @@
-use crate::settings::Settings;
+use crate::Settings;
use crate::{consts, Data};
use color_eyre::eyre::{Report, Result};
-use log::*;
+use log::info;
use poise::serenity_prelude::{Context, Message};
use poise::FrameworkContext;
@@ -10,9 +10,9 @@ pub async fn handle(
ctx: &Context,
framework: FrameworkContext<'_, Data, Report>,
msg: &Message,
- settings: &Settings,
+ data: &Data,
) -> Result<()> {
- if should_echo(framework, msg, settings) {
+ if should_echo(framework, msg, &data.settings) {
msg.reply(ctx, &msg.content).await?;
}
@@ -25,8 +25,12 @@ fn should_echo(
settings: &Settings,
) -> bool {
let gid = msg.guild_id.unwrap_or_default();
- if msg.author.id == framework.bot_id || !settings.is_guild_allowed(gid) {
- info!("not running copypasta command in {gid}");
+ if msg.author.id == framework.bot_id {
+ info!("I don't like repeating myself...");
+ }
+
+ if !settings.is_guild_allowed(gid) {
+ info!("Not echoing in guild {gid}");
return false;
}
diff --git a/src/handlers/event/mod.rs b/src/handlers/event/mod.rs
index bbfc642..a587c77 100644
--- a/src/handlers/event/mod.rs
+++ b/src/handlers/event/mod.rs
@@ -16,18 +16,16 @@ pub async fn handle(
) -> Result<()> {
match event {
Event::Ready { data_about_bot } => {
- log::info!("logged in as {}", data_about_bot.user.name)
+ log::info!("Logged in as {}!", data_about_bot.user.name)
}
Event::Message { new_message } => {
- message::handle(ctx, framework, new_message, &data.settings).await?
+ message::handle(ctx, framework, new_message, data).await?
}
- Event::ChannelPinsUpdate { pin } => pinboard::handle(ctx, pin, &data.settings).await,
+ Event::ChannelPinsUpdate { pin } => pinboard::handle(ctx, pin, data).await?,
- Event::ReactionAdd { add_reaction } => {
- reactboard::handle(ctx, add_reaction, &data.settings).await?
- }
+ Event::ReactionAdd { add_reaction } => reactboard::handle(ctx, add_reaction, data).await?,
_ => {}
}
diff --git a/src/handlers/event/pinboard.rs b/src/handlers/event/pinboard.rs
index 0c87a5b..33d2680 100644
--- a/src/handlers/event/pinboard.rs
+++ b/src/handlers/event/pinboard.rs
@@ -1,15 +1,15 @@
-use crate::settings::Settings;
-use crate::utils;
+use crate::{utils, Data};
+use color_eyre::eyre::{eyre, Context as _, Result};
use log::*;
use poise::serenity_prelude::model::prelude::*;
use poise::serenity_prelude::Context;
-pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, settings: &Settings) {
- if let Some(sources) = &settings.pinboard_sources {
+pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, data: &Data) -> Result<()> {
+ if let Some(sources) = &data.settings.pinboard_sources {
if !sources.contains(&pin.channel_id) {
- warn!("can't access source of pin!");
- return;
+ warn!("Can't access source of pin!");
+ return Ok(());
}
}
@@ -18,16 +18,23 @@ pub async fn handle(ctx: &Context, pin: &ChannelPinsUpdateEvent, settings: &Sett
.channel_id
.pins(&ctx.http)
.await
- .expect("couldn't get a list of pins!?");
+ .expect("Couldn't get a list of pins!?");
for pin in pins {
// We call `take` because it's supposed to be just for the latest message.
- redirect(ctx, &pin, pinner.take(), settings.pinboard_target).await;
- pin.unpin(&ctx).await.expect("couldn't unpin message");
+ redirect(ctx, &pin, pinner.take(), data.settings.pinboard_target).await?;
+ pin.unpin(&ctx).await?;
}
+
+ Ok(())
}
-async fn redirect(ctx: &Context, pin: &Message, pinner: Option<UserId>, target: ChannelId) {
+async fn redirect(
+ ctx: &Context,
+ pin: &Message,
+ pinner: Option<UserId>,
+ target: ChannelId,
+) -> Result<()> {
let pinner = pinner.map_or("*someone*".to_owned(), |u| format!("<@{u}>"));
let embed = utils::resolve_message_to_embed(ctx, pin).await;
@@ -38,7 +45,9 @@ async fn redirect(ctx: &Context, pin: &Message, pinner: Option<UserId>, target:
.set_embed(embed)
})
.await
- .expect("couldn't redirect message");
+ .wrap_err_with(|| eyre!("couldn't redirect message"))?;
+
+ Ok(())
}
/// (Desperate, best-effort) attempt to get the user that pinned the last message
diff --git a/src/handlers/event/reactboard.rs b/src/handlers/event/reactboard.rs
index 3972931..2a417da 100644
--- a/src/handlers/event/reactboard.rs
+++ b/src/handlers/event/reactboard.rs
@@ -1,14 +1,32 @@
-use crate::{settings::Settings, utils};
+use crate::{utils, Data};
use color_eyre::eyre::{eyre, Context as _, Result};
use log::*;
-use poise::serenity_prelude::{Context, Message, MessageReaction, Reaction};
+use poise::serenity_prelude::{ChannelId, Context, Message, MessageId, MessageReaction, Reaction};
+use redis::AsyncCommands as _;
+use redis_macros::{FromRedisValue, ToRedisArgs};
+use serde::{Deserialize, Serialize};
-pub async fn handle(ctx: &Context, reaction: &Reaction, settings: &Settings) -> Result<()> {
+#[derive(Clone, Debug, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
+struct ReactBoardEntry {
+ original_id: MessageId,
+ reaction_count: u64,
+ channel_id: ChannelId,
+ message_id: MessageId,
+}
+
+#[derive(Default, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
+struct ReactBoardInfo {
+ reactions: Vec<ReactBoardEntry>,
+}
+
+const REACT_BOARD_KEY: &str = "reactboard-v1";
+
+pub async fn handle(ctx: &Context, reaction: &Reaction, data: &Data) -> Result<()> {
let msg = reaction
.message(&ctx.http)
.await
- .wrap_err("couldn't get reaction from message!")?;
+ .wrap_err_with(|| "Couldn't get reaction from message!")?;
let matched = msg
.clone()
@@ -17,13 +35,13 @@ pub async fn handle(ctx: &Context, reaction: &Reaction, settings: &Settings) ->
.find(|r| r.reaction_type == reaction.emoji)
.ok_or_else(|| {
eyre!(
- "couldn't find any matching reactions for {} in message {}!",
+ "Couldn't find any matching reactions for {} in message {}!",
reaction.emoji.as_data(),
msg.id
)
})?;
- send_to_reactboard(ctx, &matched, &msg, settings).await?;
+ send_to_reactboard(ctx, &matched, &msg, data).await?;
Ok(())
}
@@ -32,32 +50,117 @@ async fn send_to_reactboard(
ctx: &Context,
reaction: &MessageReaction,
msg: &Message,
- settings: &Settings,
+ data: &Data,
) -> Result<()> {
- if !settings.can_use_reaction(reaction) {
- info!("reaction {} can't be used!", reaction.reaction_type);
+ // make sure everything is in order...
+ if !data.settings.can_use_reaction(reaction) {
+ info!("Reaction {} can't be used!", reaction.reaction_type);
return Ok(());
}
- if reaction.count == settings.reactboard_requirement.unwrap_or(5) {
+ if reaction.count < data.settings.reactboard_requirement.unwrap_or(5) {
+ info!(
+ "Ignoring message {} on reactboard, not enough reactions",
+ msg.id
+ );
+ return Ok(());
+ }
+
+ let mut con = data.redis.get_async_connection().await?;
+ let req = con.get(REACT_BOARD_KEY).await;
+
+ let mut reactboard: ReactBoardInfo = if let Err(why) = req {
+ // set the value to the default if the key is uninitialized
+ match why.kind() {
+ redis::ErrorKind::TypeError => {
+ warn!("Initializing {REACT_BOARD_KEY} key in Redis...");
+ con.set(REACT_BOARD_KEY, ReactBoardInfo::default()).await?;
+ con.get(REACT_BOARD_KEY).await?
+ }
+ _ => return Err(why.into()),
+ }
+ } else {
+ req?
+ };
+
+ // try to find previous reactboard entry by the id of the original message
+ let old_index = reactboard
+ .reactions
+ .iter()
+ .position(|r| r.original_id == msg.id);
+
+ let content = format!("{} **#{}**", reaction.reaction_type, reaction.count);
+
+ // bump reaction count if previous entry exists
+ if let Some(old_index) = old_index {
+ let old_entry = reactboard.reactions[old_index].clone();
+
+ // bail if we don't need to edit anything
+ if old_entry.reaction_count >= reaction.count {
+ info!("Message {} doesn't need updating", msg.id);
+ return Ok(());
+ }
+
+ info!(
+ "Bumping {} reaction count from {} to {}",
+ msg.id, old_entry.reaction_count, reaction.count
+ );
+
+ ctx.http
+ .get_message(
+ *old_entry.channel_id.as_u64(),
+ *old_entry.message_id.as_u64(),
+ )
+ .await
+ .wrap_err_with(|| {
+ format!(
+ "Couldn't get previous message from ReactBoardEntry {} in Redis DB!",
+ old_entry.original_id
+ )
+ })?
+ .edit(ctx, |m| m.content(content))
+ .await?;
+
+ // update reaction count in redis
+ let mut new_entry = old_entry.clone();
+ new_entry.reaction_count = reaction.count;
+
+ reactboard.reactions.remove(old_index);
+ reactboard.reactions.push(new_entry.clone());
+
+ info!(
+ "Updating ReactBoard entry {} in {REACT_BOARD_KEY}\nOld:\n{old_entry:#?}\nNew:\n{new_entry:#?}",
+ msg.id
+ );
+ con.set(REACT_BOARD_KEY, reactboard).await?;
+ // make new message and add entry to redis otherwise
+ } else {
let embed = utils::resolve_message_to_embed(ctx, msg).await;
- settings
+ let resp = data
+ .settings
.reactboard_target
- .send_message(&ctx.http, |m| {
+ .send_message(ctx, |m| {
m.allowed_mentions(|am| am.empty_parse())
- .content(format!(
- "{} **#{}**",
- reaction.reaction_type, reaction.count
- ))
+ .content(content)
.set_embed(embed)
})
.await?;
- } else {
+
+ let entry = ReactBoardEntry {
+ original_id: msg.id,
+ reaction_count: reaction.count,
+ channel_id: resp.channel_id,
+ message_id: resp.id,
+ };
+
+ reactboard.reactions.push(entry.clone());
+
info!(
- "not putting message {} on reactboard, not enough reactions",
- msg.id
- )
+ "Creating new ReactBoard entry {} in {REACT_BOARD_KEY}:\n{:#?}",
+ msg.id, entry
+ );
+ con.set(REACT_BOARD_KEY, reactboard).await?;
}
Ok(())
diff --git a/src/main.rs b/src/main.rs
index 0e9400b..6dc99a1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,6 +20,7 @@ type Context<'a> = poise::Context<'a, Data, Report>;
#[derive(Clone)]
pub struct Data {
settings: Settings,
+ redis: redis::Client,
}
impl Data {
@@ -27,7 +28,12 @@ impl Data {
let settings =
Settings::new().ok_or_else(|| eyre!("Couldn't create new settings object!"))?;
- Ok(Self { settings })
+ let redis_url = std::env::var("REDIS_URL")
+ .wrap_err_with(|| eyre!("Couldn't find Redis URL in environment!"))?;
+
+ let redis = redis::Client::open(redis_url)?;
+
+ Ok(Self { settings, redis })
}
}
diff --git a/src/settings.rs b/src/settings.rs
index 5cf0dec..406b990 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -45,17 +45,17 @@ impl Settings {
})
.unwrap_or_default();
- info!("pinboard target is {}", pinboard_target);
+ info!("PinBoard target is {}", pinboard_target);
if let Some(sources) = &pinboard_sources {
- info!("pinboard sources are {:#?}", sources);
+ info!("PinBoard sources are {:#?}", sources);
}
- info!("reactboard target is {}", reactboard_target);
+ info!("ReactBoard target is {}", reactboard_target);
info!(
- "reactboard custom reactions are {:#?}",
+ "ReactBoard custom reactions are {:#?}",
reactboard_custom_reactions
);
info!(
- "reactboard unicode reactions are {:#?}",
+ "ReactBoard unicode reactions are {:#?}",
reactboard_unicode_reactions
);
diff --git a/src/utils.rs b/src/utils.rs
index c0353f0..10140f4 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -24,7 +24,7 @@ pub fn random_choice<const N: usize>(arr: [&str; N]) -> Result<String> {
let mut rng = rand::thread_rng();
let resp = arr
.choose(&mut rng)
- .ok_or_else(|| eyre!("couldn't choose from array!"))?;
+ .ok_or_else(|| eyre!("Couldn't choose random object from array:\n{arr:#?}!"))?;
Ok((*resp).to_string())
}