Discord working
This commit is contained in:
parent
2d7af6d149
commit
1914ee2ee8
45
Cargo.lock
generated
45
Cargo.lock
generated
|
@ -747,29 +747,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"
|
||||||
|
@ -2915,3 +2892,25 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yourcloud"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"color-eyre",
|
||||||
|
"config",
|
||||||
|
"discord",
|
||||||
|
"redact",
|
||||||
|
"reqwest",
|
||||||
|
"reqwest-middleware",
|
||||||
|
"reqwest-retry",
|
||||||
|
"reqwest-tracing",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"urlencoding",
|
||||||
|
]
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
[package]
|
[package]
|
||||||
name = "homecloud"
|
name = "yourcloud"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.82"
|
|
||||||
axum = "0.7.5"
|
axum = "0.7.5"
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
config = "0.14.0"
|
config = "0.14.0"
|
||||||
|
|
54
flake.lock
54
flake.lock
|
@ -16,28 +16,9 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1710146030,
|
|
||||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-hooks": {
|
"git-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"gitignore": "gitignore",
|
"gitignore": "gitignore",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
|
@ -45,11 +26,11 @@
|
||||||
"nixpkgs-stable": "nixpkgs-stable"
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712579741,
|
"lastModified": 1722857853,
|
||||||
"narHash": "sha256-igpsH+pa6yFwYOdah3cFciCk8gw+ytniG9quf5f/q84=",
|
"narHash": "sha256-3Zx53oz/MSIyevuWO/SumxABkrIvojnB7g9cimxkhiE=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "70f504012f0a132ac33e56988e1028d88a48855c",
|
"rev": "06939f6b7ec4d4f465bf3132a05367cccbbf64da",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -81,11 +62,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1712608508,
|
"lastModified": 1722630782,
|
||||||
"narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
|
"narHash": "sha256-hMyG9/WlUi0Ho9VkRrrez7SeNlDzLxalm9FwY7n/Noo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
|
"rev": "d04953086551086b44b6f3c6b7eeb26294f207da",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -97,16 +78,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710695816,
|
"lastModified": 1720386169,
|
||||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
"narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
"rev": "194846768975b7ad2c4988bdb82572c00222c0d7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-23.11",
|
"ref": "nixos-24.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -116,21 +97,6 @@
|
||||||
"git-hooks": "git-hooks",
|
"git-hooks": "git-hooks",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// TODO: handle messages
|
// TODO: handle messages
|
||||||
// TODO: data persistence? (sqlite? sled?)
|
// TODO: data persistence? (sqlite? sled?)
|
||||||
|
|
||||||
use std::{any::Any, future};
|
use std::{any::Any, fmt, future};
|
||||||
|
|
||||||
use discord::model::{ChannelId, Event, Message, ReadyEvent};
|
use discord::model::{ChannelId, Event, Message, ReadyEvent};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
@ -13,30 +13,30 @@ const COMMAND_PREFIX: &str = "!";
|
||||||
struct Discord {
|
struct Discord {
|
||||||
discord: discord::Discord,
|
discord: discord::Discord,
|
||||||
connection: Option<Arc<Mutex<discord::Connection>>>,
|
connection: Option<Arc<Mutex<discord::Connection>>>,
|
||||||
|
me: Option<discord::model::CurrentUser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Discord {
|
impl Discord {
|
||||||
pub fn try_new(conf: Arc<Config>) -> Result<Self> {
|
pub fn try_new(conf: Arc<Config>) -> Result<Self> {
|
||||||
let discord = discord::Discord::from_bot_token(
|
if let Some(bot_token) = conf.discord.as_ref().map(|d| &d.bot_token) {
|
||||||
conf.discord
|
let discord = discord::Discord::from_bot_token(bot_token.expose_secret())?;
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.bot_token
|
|
||||||
.clone()
|
|
||||||
.expose_secret(),
|
|
||||||
)?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
discord,
|
discord,
|
||||||
connection: None,
|
connection: None,
|
||||||
|
me: None,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
return Err(eyre!("discord configuration was empty"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect(&mut self) -> Result<ReadyEvent> {
|
pub async fn connect(&mut self) -> Result<ReadyEvent> {
|
||||||
if self.connection.is_some() {
|
if self.connection.is_some() {
|
||||||
return Err(anyhow::anyhow!("already connected"));
|
return Err(eyre!("already connected"));
|
||||||
}
|
}
|
||||||
let (connection, ready_ev) = self.discord.connect()?;
|
let (connection, ready_ev) = self.discord.connect()?;
|
||||||
self.connection = Some(Arc::new(Mutex::new(connection)));
|
self.connection = Some(Arc::new(Mutex::new(connection)));
|
||||||
|
self.me = self.discord.get_current_user().ok();
|
||||||
Ok(ready_ev)
|
Ok(ready_ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +195,20 @@ impl Discord {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_message(&self, msg: Message) -> Result<()> {
|
pub fn handle_message(&self, msg: Message) -> Result<()> {
|
||||||
|
if let Some(me) = &self.me {
|
||||||
|
if msg.author.id == me.id {
|
||||||
|
trace!("Ignoring message from self");
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if msg.author.bot {
|
||||||
|
info!(
|
||||||
|
"Ignoring bot message in channel {} with content: {}",
|
||||||
|
msg.channel_id, msg.content
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Recieved Discord message in channel {} with content: {}",
|
"Recieved Discord message in channel {} with content: {}",
|
||||||
msg.channel_id, msg.content
|
msg.channel_id, msg.content
|
||||||
|
@ -221,6 +235,13 @@ impl Discord {
|
||||||
s if s.starts_with("ping") => {
|
s if s.starts_with("ping") => {
|
||||||
let _ = self.send_message(msg.channel_id, "`pong`")?;
|
let _ = self.send_message(msg.channel_id, "`pong`")?;
|
||||||
}
|
}
|
||||||
|
s if s.starts_with("dm-me") => {
|
||||||
|
let dm = self.discord.create_dm(msg.author.id)?;
|
||||||
|
self.send_message(
|
||||||
|
dm.id,
|
||||||
|
format!("DM'ing you as requested via `{}dm-me", COMMAND_PREFIX).as_str(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -36,17 +36,10 @@ pub struct ConfigLoadResult {
|
||||||
|
|
||||||
const CONFIG_FILE_PATH: &str = "./conf.toml";
|
const CONFIG_FILE_PATH: &str = "./conf.toml";
|
||||||
const ENCRYPTED_CONFIG_FILE_PATH: &str = "./conf.toml.sops";
|
const ENCRYPTED_CONFIG_FILE_PATH: &str = "./conf.toml.sops";
|
||||||
const TMP_CONFIG_FILE_NAME: &str = "homecloud-conf.toml";
|
const TMP_CONFIG_FILE_NAME: &str = "yourcloud-conf.toml";
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Result<Self> {
|
pub fn load() -> Result<Self> {
|
||||||
let c = Self::builder()?.build()?;
|
|
||||||
Ok(c.try_deserialize()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument]
|
|
||||||
pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
|
|
||||||
info!("builder");
|
|
||||||
let mut p: PathBuf = CONFIG_FILE_PATH.into();
|
let mut p: PathBuf = CONFIG_FILE_PATH.into();
|
||||||
let mut tmp_file_to_cleanup: Option<PathBuf> = None;
|
let mut tmp_file_to_cleanup: Option<PathBuf> = None;
|
||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
|
@ -62,10 +55,10 @@ impl Config {
|
||||||
info!("Detected encrypted config file '{}' - attempting to use `sops` to decrypt it to '{}' ", ENCRYPTED_CONFIG_FILE_PATH, tmp_file.display());
|
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")
|
let sops_result = Command::new("sops")
|
||||||
.args([
|
.args([
|
||||||
OsStr::new("--decrypt"),
|
|
||||||
&p.into_os_string(),
|
|
||||||
OsStr::new("--output"),
|
OsStr::new("--output"),
|
||||||
&tmp_file.clone().into_os_string(),
|
&tmp_file.clone().into_os_string(),
|
||||||
|
OsStr::new("--decrypt"),
|
||||||
|
OsStr::new(ENCRYPTED_CONFIG_FILE_PATH),
|
||||||
])
|
])
|
||||||
.output();
|
.output();
|
||||||
p = tmp_file.clone();
|
p = tmp_file.clone();
|
||||||
|
@ -78,18 +71,24 @@ impl Config {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: log whether or not we were able to load conf.toml?
|
|
||||||
let result = Ok(Self::default_builder()
|
let c = Self::builder(p)?.build()?;
|
||||||
.map_err(Error::from)?
|
|
||||||
.add_source(config::File::from(p).required(false))
|
let result = c.try_deserialize();
|
||||||
.add_source(config::Environment::with_prefix("homecloud").separator("__")));
|
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
if let Some(path) = tmp_file_to_cleanup {
|
if let Some(path) = tmp_file_to_cleanup {
|
||||||
let _ = std::fs::remove_file(path);
|
let _ = std::fs::remove_file(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
Ok(result?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builder(file: PathBuf) -> Result<ConfigBuilder<DefaultState>> {
|
||||||
|
Ok(Self::default_builder()
|
||||||
|
.map_err(Report::from)?
|
||||||
|
.add_source(config::File::from(file).required(false))
|
||||||
|
.add_source(config::Environment::with_prefix("yourcloud").separator("__")))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
pub fn default_builder() -> Result<ConfigBuilder<DefaultState>> {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::prelude::*;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
observe::setup_logging();
|
||||||
let conf: Arc<Config> = match Config::load() {
|
let conf: Arc<Config> = match Config::load() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Error loading configuration: {err}");
|
error!("Error loading configuration: {err}");
|
||||||
|
@ -19,7 +20,6 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
Ok(conf) => Arc::new(conf),
|
Ok(conf) => Arc::new(conf),
|
||||||
};
|
};
|
||||||
observe::setup_logging(conf.clone());
|
|
||||||
debug!("Configuration: {conf:?}");
|
debug!("Configuration: {conf:?}");
|
||||||
|
|
||||||
let mut set = tokio::task::JoinSet::new();
|
let mut set = tokio::task::JoinSet::new();
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
use crate::prelude::*;
|
pub fn setup_logging() {
|
||||||
|
|
||||||
pub fn setup_logging(_conf: Arc<Config>) {
|
|
||||||
color_eyre::install().expect("Failed to install color_eyre");
|
color_eyre::install().expect("Failed to install color_eyre");
|
||||||
|
|
||||||
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,yourcloud=trace");
|
||||||
|
|
||||||
tracing_subscriber::fmt().with_env_filter(filter).init();
|
tracing_subscriber::fmt().with_env_filter(filter).init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
// pub use color_eyre;
|
// pub use color_eyre;
|
||||||
pub use crate::config::Config;
|
pub use crate::config::Config;
|
||||||
pub use anyhow::Error;
|
pub use color_eyre::eyre::eyre;
|
||||||
pub use anyhow::Result;
|
pub use color_eyre::Report;
|
||||||
|
pub use color_eyre::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;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use reqwest::StatusCode;
|
||||||
|
|
||||||
use crate::{minecraft_server_status::MinecraftServerStatus, prelude::*};
|
use crate::{minecraft_server_status::MinecraftServerStatus, prelude::*};
|
||||||
|
|
||||||
struct WebserverError(anyhow::Error);
|
struct WebserverError(Report);
|
||||||
type WebserverResult<T> = std::result::Result<T, WebserverError>;
|
type WebserverResult<T> = std::result::Result<T, WebserverError>;
|
||||||
|
|
||||||
pub async fn start(_conf: Arc<Config>) -> Result<()> {
|
pub async fn start(_conf: Arc<Config>) -> Result<()> {
|
||||||
|
@ -74,7 +74,7 @@ impl IntoResponse for WebserverError {
|
||||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
// `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<Report>,
|
||||||
{
|
{
|
||||||
fn from(err: E) -> Self {
|
fn from(err: E) -> Self {
|
||||||
Self(err.into())
|
Self(err.into())
|
||||||
|
|
Loading…
Reference in a new issue