Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
Daniel Flanagan | 6dd5db6550 |
142
Cargo.lock
generated
142
Cargo.lock
generated
|
@ -41,6 +41,54 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "antidote"
|
name = "antidote"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -240,6 +288,30 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chatbot"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"axum",
|
||||||
|
"clap",
|
||||||
|
"color-eyre",
|
||||||
|
"config",
|
||||||
|
"discord",
|
||||||
|
"redact",
|
||||||
|
"reqwest",
|
||||||
|
"reqwest-middleware",
|
||||||
|
"reqwest-retry",
|
||||||
|
"reqwest-tracing",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"urlencoding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.37"
|
version = "0.4.37"
|
||||||
|
@ -255,6 +327,33 @@ dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim 0.11.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-eyre"
|
name = "color-eyre"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
|
@ -282,6 +381,12 @@ dependencies = [
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "config"
|
name = "config"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
|
@ -401,7 +506,7 @@ dependencies = [
|
||||||
"ident_case",
|
"ident_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim 0.10.0",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -747,29 +852,6 @@ version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "homecloud"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"axum",
|
|
||||||
"color-eyre",
|
|
||||||
"config",
|
|
||||||
"discord",
|
|
||||||
"redact",
|
|
||||||
"reqwest",
|
|
||||||
"reqwest-middleware",
|
|
||||||
"reqwest-retry",
|
|
||||||
"reqwest-tracing",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_with",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
"urlencoding",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -2095,6 +2177,12 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.58"
|
version = "2.0.58"
|
||||||
|
@ -2548,6 +2636,12 @@ version = "2.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
[package]
|
[package]
|
||||||
name = "homecloud"
|
name = "chatbot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
axum = "0.7.5"
|
axum = "0.7.5"
|
||||||
|
clap = "4.5.4"
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
config = "0.14.0"
|
config = "0.14.0"
|
||||||
discord = { git = "https://github.com/SpaceManiac/discord-rs" }
|
discord = { git = "https://github.com/SpaceManiac/discord-rs" }
|
||||||
|
|
12
flake.lock
12
flake.lock
|
@ -45,11 +45,11 @@
|
||||||
"nixpkgs-stable": "nixpkgs-stable"
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712579741,
|
"lastModified": 1714478972,
|
||||||
"narHash": "sha256-igpsH+pa6yFwYOdah3cFciCk8gw+ytniG9quf5f/q84=",
|
"narHash": "sha256-q//cgb52vv81uOuwz1LaXElp3XAe1TqrABXODAEF6Sk=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "70f504012f0a132ac33e56988e1028d88a48855c",
|
"rev": "2849da033884f54822af194400f8dff435ada242",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -81,11 +81,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712608508,
|
"lastModified": 1714635257,
|
||||||
"narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
|
"narHash": "sha256-4cPymbty65RvF1DWQfc+Bc8B233A1BWxJnNULJKQ1EY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
|
"rev": "63c3a29ca82437c87573e4c6919b09a24ea61b0f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -5,26 +5,22 @@
|
||||||
|
|
||||||
use std::{any::Any, future};
|
use std::{any::Any, future};
|
||||||
|
|
||||||
use discord::model::{ChannelId, Event, Message, ReadyEvent};
|
use discord::{
|
||||||
|
model::{ChannelId, Event, Message, ReadyEvent},
|
||||||
|
Discord as DDiscord,
|
||||||
|
};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
const COMMAND_PREFIX: &str = "!";
|
const COMMAND_PREFIX: &str = "!";
|
||||||
|
|
||||||
struct Discord {
|
struct Discord {
|
||||||
discord: discord::Discord,
|
discord: DDiscord,
|
||||||
connection: Option<Arc<Mutex<discord::Connection>>>,
|
connection: Option<Arc<Mutex<discord::Connection>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Discord {
|
impl Discord {
|
||||||
pub fn try_new(conf: Arc<Config>) -> Result<Self> {
|
pub fn try_new(bot_token: &str) -> Result<Self> {
|
||||||
let discord = discord::Discord::from_bot_token(
|
let discord = DDiscord::from_bot_token(bot_token)?;
|
||||||
conf.discord
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.bot_token
|
|
||||||
.clone()
|
|
||||||
.expose_secret(),
|
|
||||||
)?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
discord,
|
discord,
|
||||||
connection: None,
|
connection: None,
|
||||||
|
@ -230,15 +226,19 @@ impl Discord {
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub async fn start(conf: Arc<Config>) -> Result<()> {
|
pub async fn start(conf: Arc<Config>) -> Result<()> {
|
||||||
if conf.discord.is_none() {
|
match &conf.discord {
|
||||||
|
None => {
|
||||||
warn!("Chatbot starting without Discord token. Nothing will happen.");
|
warn!("Chatbot starting without Discord token. Nothing will happen.");
|
||||||
// wait forever
|
// wait forever
|
||||||
future::pending::<()>().await;
|
future::pending::<()>().await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Some(d) => {
|
||||||
let mut discord = Discord::try_new(conf.clone())?;
|
let mut discord = Discord::try_new(d.bot_token.expose_secret())?;
|
||||||
let ready_ev = discord.connect().await;
|
let ready_ev = discord.connect().await;
|
||||||
info!("Discord connection ready: {ready_ev:?}");
|
info!("Discord connection ready: {ready_ev:?}");
|
||||||
let adiscord = Arc::new(discord);
|
let adiscord = Arc::new(discord);
|
||||||
adiscord.handle_commands().await
|
adiscord.handle_commands().await
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
use crate::prelude::*;
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder};
|
use config::{builder::DefaultState, Config as CConfig, ConfigBuilder};
|
||||||
use redact::serde::redact_secret;
|
use redact::serde::redact_secret;
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::fs::OpenOptions;
|
use crate::prelude::*;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::process::Command;
|
|
||||||
use std::{collections::HashMap, fmt::Debug};
|
|
||||||
|
|
||||||
const CURRENT_VERSION: u64 = 1;
|
const CURRENT_VERSION: u64 = 1;
|
||||||
|
|
||||||
|
@ -30,13 +27,7 @@ pub struct Config {
|
||||||
pub open_ai: Option<OpenAI>,
|
pub open_ai: Option<OpenAI>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConfigLoadResult {
|
|
||||||
pub config: Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONFIG_FILE_PATH: &str = "./conf.toml";
|
const CONFIG_FILE_PATH: &str = "./conf.toml";
|
||||||
const ENCRYPTED_CONFIG_FILE_PATH: &str = "./conf.toml.sops";
|
|
||||||
const TMP_CONFIG_FILE_NAME: &str = "homecloud-conf.toml";
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Result<Self> {
|
pub fn load() -> Result<Self> {
|
||||||
|
@ -44,52 +35,24 @@ impl Config {
|
||||||
Ok(c.try_deserialize()?)
|
Ok(c.try_deserialize()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
|
||||||
pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
|
pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||||
info!("builder");
|
let p = std::path::PathBuf::from(CONFIG_FILE_PATH);
|
||||||
let mut p: PathBuf = CONFIG_FILE_PATH.into();
|
|
||||||
let mut tmp_file_to_cleanup: Option<PathBuf> = None;
|
|
||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
// TODO: this won't output since tracing is not setup before we load
|
// TODO: this won't output since tracing is not setup before we load
|
||||||
// config, so we need something like
|
// config, so we need something like
|
||||||
// https://docs.rs/tracing-capture/latest/tracing_capture/
|
// https://docs.rs/tracing-capture/latest/tracing_capture/
|
||||||
// to capture trace events to be output _after_ configuration has
|
// to capture trace events to be output _after_ configuration has
|
||||||
// loaded and the "actual" subscriber is setup
|
// loaded and the "actual" subscriber is setup
|
||||||
if PathBuf::from(ENCRYPTED_CONFIG_FILE_PATH).exists() {
|
|
||||||
let tmp_file = Path::join(&std::env::temp_dir(), TMP_CONFIG_FILE_NAME);
|
|
||||||
let mut options = OpenOptions::new();
|
|
||||||
options.mode(0o600); // Give read/write for owner and read for others.
|
|
||||||
info!("Detected encrypted config file '{}' - attempting to use `sops` to decrypt it to '{}' ", ENCRYPTED_CONFIG_FILE_PATH, tmp_file.display());
|
|
||||||
let sops_result = Command::new("sops")
|
|
||||||
.args([
|
|
||||||
OsStr::new("--decrypt"),
|
|
||||||
&p.into_os_string(),
|
|
||||||
OsStr::new("--output"),
|
|
||||||
&tmp_file.clone().into_os_string(),
|
|
||||||
])
|
|
||||||
.output();
|
|
||||||
p = tmp_file.clone();
|
|
||||||
tmp_file_to_cleanup = Some(tmp_file);
|
|
||||||
info!("p: {}, sops_result: {:?}", p.display(), sops_result);
|
|
||||||
} else {
|
|
||||||
warn!(
|
warn!(
|
||||||
"Config file '{}' doesn't exist, so defaults will likely be loaded!",
|
"Config file '{}' doesn't exist, so defaults will likely be loaded!",
|
||||||
p.display(),
|
p.display(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: log whether or not we were able to load conf.toml?
|
// TODO: log whether or not we were able to load conf.toml?
|
||||||
let result = Ok(Self::default_builder()
|
Ok(Self::default_builder()
|
||||||
.map_err(Error::from)?
|
.map_err(Error::from)?
|
||||||
.add_source(config::File::from(p).required(false))
|
.add_source(config::File::from(p).required(false))
|
||||||
.add_source(config::Environment::with_prefix("homecloud").separator("__")));
|
.add_source(config::Environment::with_prefix("chatbot").separator("__")))
|
||||||
|
|
||||||
// cleanup
|
|
||||||
if let Some(path) = tmp_file_to_cleanup {
|
|
||||||
let _ = std::fs::remove_file(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub fn setup_logging(_conf: Arc<Config>) {
|
||||||
|
|
||||||
let filter = EnvFilter::builder()
|
let filter = EnvFilter::builder()
|
||||||
.with_default_directive(LevelFilter::TRACE.into())
|
.with_default_directive(LevelFilter::TRACE.into())
|
||||||
.parse_lossy("info,homecloud=trace");
|
.parse_lossy("info,chatbot=trace");
|
||||||
|
|
||||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,4 @@ pub use anyhow::Result;
|
||||||
pub use redact::Secret;
|
pub use redact::Secret;
|
||||||
pub use serde::{Deserialize, Serialize};
|
pub use serde::{Deserialize, Serialize};
|
||||||
pub use std::sync::Arc;
|
pub use std::sync::Arc;
|
||||||
pub use tracing::{debug, error, info, instrument, trace, warn};
|
pub use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
|
@ -41,7 +41,6 @@ async fn health() -> impl IntoResponse {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches server statuses for the configured minecraft servers simultaneously.
|
|
||||||
async fn minecraft_server_status() -> WebserverResult<impl IntoResponse> {
|
async fn minecraft_server_status() -> WebserverResult<impl IntoResponse> {
|
||||||
let c = Arc::new(MinecraftServerStatus::try_new()?);
|
let c = Arc::new(MinecraftServerStatus::try_new()?);
|
||||||
let reqs: Vec<&str> = vec!["h.lyte.dev:26965", "ourcraft.lyte.dev"];
|
let reqs: Vec<&str> = vec!["h.lyte.dev:26965", "ourcraft.lyte.dev"];
|
||||||
|
@ -70,8 +69,9 @@ impl IntoResponse for WebserverError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
// This enables using `?` on functions that return `Result<_, anyhow::Error>`
|
||||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
// to turn them into `Result<_, AppError>`. That way you don't need to do that
|
||||||
|
// manually.
|
||||||
impl<E> From<E> for WebserverError
|
impl<E> From<E> for WebserverError
|
||||||
where
|
where
|
||||||
E: Into<anyhow::Error>,
|
E: Into<anyhow::Error>,
|
||||||
|
|
Loading…
Reference in a new issue