Skip to content

Commit

Permalink
Use anyhow and thiserror (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
MinnDevelopment authored Jul 20, 2023
1 parent dcebe61 commit 95db2a8
Show file tree
Hide file tree
Showing 17 changed files with 57 additions and 77 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ version = "1.2.6"
edition = "2021"

[workspace.dependencies]
anyhow = "1.0"
thiserror = "1.0"
twilight-http-ratelimiting = "0.15"
twilight-model = "0.15"
serde_json = "1.0"
Expand Down
3 changes: 0 additions & 3 deletions commons/src/errors.rs

This file was deleted.

4 changes: 1 addition & 3 deletions commons/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@

pub mod errors;
#[macro_use]
pub mod util;
pub mod util;
4 changes: 2 additions & 2 deletions commons/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::{num::NonZeroU64, ops::Add};
macro_rules! resolve {
($x:expr) => {
match $x.await {
Ok(response) => response.model().await.map_err(commons::errors::AsyncError::from),
Err(err) => Err(commons::errors::AsyncError::from(err)),
Ok(response) => response.model().await.map_err(anyhow::Error::from),
Err(err) => Err(anyhow::Error::from(err)),
}
};
}
Expand Down
1 change: 1 addition & 0 deletions discord-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "1.2.5"
edition.workspace = true

[dependencies]
anyhow = { workspace = true }
twilight-http-ratelimiting = { workspace = true }
twilight-model = { workspace = true }
tracing = { workspace = true }
Expand Down
7 changes: 3 additions & 4 deletions discord-api/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use twilight_model::{
},
};

use commons::errors::AsyncError;
use commons::resolve;

use crate::config::{DiscordConfig, RoleNameConfig};
Expand Down Expand Up @@ -54,7 +53,7 @@ impl Gateway {
}
}

pub async fn run(mut self) -> Result<(), AsyncError> {
pub async fn run(mut self) -> anyhow::Result<()> {
let mut shard = Shard::with_config(
ShardId::ONE,
ShardConfig::builder(self.http.token().unwrap().into(), Self::INTENTS)
Expand Down Expand Up @@ -82,7 +81,7 @@ impl Gateway {
}
}
_ => {}
}
}
}

log::info!("Connection terminated");
Expand All @@ -94,7 +93,7 @@ impl Gateway {
(name, name)
}

async fn init_roles(&mut self, config: &RoleNameConfig, guild_id: &str) -> Result<bool, AsyncError> {
async fn init_roles(&mut self, config: &RoleNameConfig, guild_id: &str) -> anyhow::Result<bool> {
let guild_id: Id<GuildMarker> = Id::from_str(guild_id)?;
let role_names = config.values();

Expand Down
2 changes: 1 addition & 1 deletion discord-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ mod tests {
"enabled_events": ["live", "update", "vod"],
"enable_command": true
}"#;

let discord: DiscordConfig = serde_json::from_slice(file).unwrap();

assert_eq!(discord.guild_id, Some("81384788765712384".into()));
Expand Down
2 changes: 2 additions & 0 deletions strumbot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ edition.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
thiserror = { workspace = true }
anyhow = { workspace = true }
serde_json = { workspace = true }
serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true }
Expand Down
12 changes: 6 additions & 6 deletions strumbot/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use twilight_model::guild::{Guild, Permissions};
use twilight_model::id::{marker::GuildMarker, Id};
use twitch_api::config::TwitchConfig;

use commons::{errors::AsyncError as Error, resolve};
use commons::resolve;

use crate::errors::InitError;

Expand Down Expand Up @@ -43,26 +43,26 @@ impl Config {
self.role_map.get(event).cloned()
}

pub async fn init_roles(&mut self, client: &Client) -> Result<(), Error> {
pub async fn init_roles(&mut self, client: &Client) -> anyhow::Result<()> {
let guild = if let Some(ref id) = self.discord.guild_id {
Self::get_guild(client, id.parse()?).await?
} else {
let guilds = client.current_user_guilds().limit(2)?.await?.models().await?;
match guilds[..] {
[ref guild] => Self::get_guild(client, guild.id).await?,
[] => return Err(Box::new(InitError::NoGuilds)),
_ => return Err(Box::new(InitError::TooManyGuilds)),
[] => return Err(InitError::NoGuilds.into()),
_ => return Err(InitError::TooManyGuilds.into()),
}
};

self.init_roles_from_guild(client, guild).await;
Ok(())
}

async fn get_guild(client: &Client, id: Id<GuildMarker>) -> Result<Guild, Error> {
async fn get_guild(client: &Client, id: Id<GuildMarker>) -> anyhow::Result<Guild> {
match client.guild(id).await {
Ok(guild) => Ok(guild.model().await?),
Err(err) => Err(Box::new(err)),
Err(err) => Err(err.into()),
}
}

Expand Down
7 changes: 3 additions & 4 deletions strumbot/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::error::Error;
use std::fmt::{self, Display, Formatter};

#[derive(Debug)]
use thiserror::Error;

#[derive(Error, Debug)]
pub enum InitError {
NoGuilds,
TooManyGuilds,
Expand All @@ -15,5 +16,3 @@ impl Display for InitError {
}
}
}

impl Error for InitError {}
14 changes: 6 additions & 8 deletions strumbot/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use commons::errors::AsyncError;
use config::Config;
use database_api::{Database, DatabaseError, FileDatabase};
use discord_api::{Gateway, WebhookClient};
Expand All @@ -21,11 +20,10 @@ mod config;
mod errors;
mod watcher;

type Async = Result<(), AsyncError>;
type Cache = FileDatabase;

#[tokio::main]
async fn main() -> Async {
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();

let config: String = match tokio::fs::read_to_string("config.json").await {
Expand Down Expand Up @@ -152,17 +150,17 @@ fn start_watcher(
break;
}
Err(e) => {
log::error!("[{}] Error when updating stream watcher: {}", key, e);
log::error!("[{key}] Error when updating stream watcher: {e:?}");
}
Ok(WatcherState::Updated) => {
if cache_enabled {
// Save the current watcher state to cache file
match db.save(&key, &watcher).await {
Err(DatabaseError::Io(e)) => {
log::error!("[{}] Failed to save cache: {}", key, e);
log::error!("[{key}] Failed to save cache: {e:?}");
}
Err(DatabaseError::Serde(e)) => {
log::error!("[{}] Could not serialize watcher: {}", key, e);
log::error!("[{key}] Could not serialize watcher: {e:?}");
}
Ok(_) => {}
}
Expand All @@ -176,7 +174,7 @@ fn start_watcher(
}

if let Err(err) = db.delete(&key).await {
log::error!("{} Failed to delete database entry: {}", key, err);
log::error!("[{key}] Failed to delete database entry: {err:?}");
}
receive.close();
});
Expand All @@ -194,7 +192,7 @@ async fn load_cache(
client: &Arc<TwitchClient>,
webhook: &Arc<WebhookClient>,
db: &Arc<Cache>,
) -> Async {
) -> anyhow::Result<()> {
if let Ok(data) = fs::metadata(".config").await {
if !data.is_dir() {
log::error!("Cannot load cache: .config is not a directory");
Expand Down
9 changes: 4 additions & 5 deletions strumbot/src/watcher.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::sync::Arc;

use commons::errors::AsyncError as Error;
use commons::util::Timestamp;
use discord_api::{config::EventName, WebhookClient};
use eos::DateTime;
Expand Down Expand Up @@ -128,7 +127,7 @@ impl StreamWatcher {
client: &TwitchClient,
webhook: &WebhookClient,
stream: StreamUpdate,
) -> Result<WatcherState, Error> {
) -> anyhow::Result<WatcherState> {
match stream {
StreamUpdate::Live(stream) if self.segments.is_empty() => {
self.on_go_live(client, webhook, *stream).await?;
Expand Down Expand Up @@ -157,7 +156,7 @@ impl StreamWatcher {
client: &TwitchClient,
webhook: &WebhookClient,
stream: Stream,
) -> Result<(), Error> {
) -> anyhow::Result<()> {
self.offline_timestamp = None;
self.start_timestamp = stream.started_at;
self.user_id = stream.user_id.clone();
Expand Down Expand Up @@ -196,7 +195,7 @@ impl StreamWatcher {
client: &TwitchClient,
webhook: &WebhookClient,
stream: Stream,
) -> Result<bool, Error> {
) -> anyhow::Result<bool> {
self.offline_timestamp = None;
let old_game = match self.segments.last() {
Some(seg) => seg.game.clone(), // have to clone so the borrow isn't an issue later
Expand Down Expand Up @@ -261,7 +260,7 @@ impl StreamWatcher {
Ok(true)
}

async fn on_offline(&mut self, client: &TwitchClient, webhook: &WebhookClient) -> Result<bool, Error> {
async fn on_offline(&mut self, client: &TwitchClient, webhook: &WebhookClient) -> anyhow::Result<bool> {
// Check if the offline grace period is over (usually 2 minutes)
match self.offline_timestamp {
None => {
Expand Down
2 changes: 2 additions & 0 deletions twitch-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version = "1.2.5"
edition.workspace = true

[dependencies]
anyhow = { workspace = true }
thiserror = { workspace = true }
serde_json = { workspace = true }
lru = { workspace = true }
tracing = { workspace = true }
Expand Down
50 changes: 11 additions & 39 deletions twitch-api/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,29 @@
use std::{
error::Error,
fmt::{Display, Formatter},
};

use reqwest::{header::ToStrError, StatusCode};
use thiserror::Error;

pub type AsyncError = Box<dyn Error + Send + Sync>;
pub type SerdeError = serde_json::Error;

#[derive(Debug)]
#[derive(Error, Debug)]
pub enum RequestError {
#[error("http request failed with code {0}")]
Http(StatusCode),
#[error("request timed out")]
Timeout,
Unexpected(AsyncError),
Deserialize(SerdeError),
#[error("unexpected error: {0:?}")]
Unexpected(#[from] anyhow::Error),
#[error("failed to deserialize {0:?}")]
Deserialize(#[from] serde_json::Error),
#[error("{0} not found for query {1}")]
NotFound(&'static str, String),
}

impl Display for RequestError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
RequestError::Http(status) => write!(f, "HTTP {}", status),
RequestError::Unexpected(e) => write!(f, "Unexpected error: {}", e),
RequestError::Deserialize(e) => write!(f, "Deserialize error: {}", e),
RequestError::Timeout => write!(f, "Timeout error"),
RequestError::NotFound(kind, query) => write!(f, "{kind} not found for query {query}"),
}
}
}

impl std::error::Error for RequestError {}

impl From<reqwest::Error> for RequestError {
fn from(e: reqwest::Error) -> Self {
RequestError::Unexpected(Box::new(e))
}
}

impl From<AsyncError> for RequestError {
fn from(e: AsyncError) -> Self {
RequestError::Unexpected(e)
RequestError::Unexpected(e.into())
}
}

impl From<ToStrError> for RequestError {
fn from(e: ToStrError) -> Self {
RequestError::Unexpected(Box::new(e))
RequestError::Unexpected(e.into())
}
}

Expand All @@ -54,9 +32,3 @@ impl From<StatusCode> for RequestError {
RequestError::Http(code)
}
}

impl From<SerdeError> for RequestError {
fn from(e: SerdeError) -> Self {
RequestError::Deserialize(e)
}
}
2 changes: 1 addition & 1 deletion twitch-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ pub mod model;
#[macro_use]
pub mod oauth;
pub mod client;
pub mod error;
pub mod config;
pub mod error;

// Serde deserialization into Instant
pub(crate) mod expires_at {
Expand Down
Loading

0 comments on commit 95db2a8

Please sign in to comment.