Use once_cell
to keep the configuration
In order to keep the configuration globally available use `once_cell`. Also check for a valid email address in the part which is receiving the data from the api.
This commit is contained in:
parent
05e63acca5
commit
7ad6f610d1
6 changed files with 61 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -534,6 +534,7 @@ dependencies = [
|
||||||
"nom",
|
"nom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"quoted_printable",
|
"quoted_printable",
|
||||||
|
"serde",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -918,6 +919,7 @@ dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel_migrations",
|
"diesel_migrations",
|
||||||
"lettre",
|
"lettre",
|
||||||
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
|
@ -14,7 +14,7 @@ anyhow = "1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
time = { version = "0.3", features = ["serde-human-readable"] }
|
time = { version = "0.3", features = ["serde-human-readable"] }
|
||||||
lettre = { version = "0.10", features = ["tracing"] }
|
lettre = { version = "0.10", features = ["serde", "tracing"] }
|
||||||
diesel = { version = "2", features = ["postgres", "r2d2", "time"] }
|
diesel = { version = "2", features = ["postgres", "r2d2", "time"] }
|
||||||
diesel_migrations = "2"
|
diesel_migrations = "2"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
@ -25,3 +25,4 @@ tokio = { version = "1", features = ["full"] }
|
||||||
axum = "0.6"
|
axum = "0.6"
|
||||||
tower = { version = "0.4", features = ["util"] }
|
tower = { version = "0.4", features = ["util"] }
|
||||||
tower-http = { version = "0.3", features = ["trace"] }
|
tower-http = { version = "0.3", features = ["trace"] }
|
||||||
|
once_cell = "1"
|
||||||
|
|
|
@ -8,3 +8,6 @@ pass = "remindrs"
|
||||||
# [server]
|
# [server]
|
||||||
# address = "::1"
|
# address = "::1"
|
||||||
# port = 8080
|
# port = 8080
|
||||||
|
|
||||||
|
# [email]
|
||||||
|
# from = "remindrs@localhost"
|
||||||
|
|
|
@ -7,6 +7,7 @@ use axum::{
|
||||||
Json,
|
Json,
|
||||||
};
|
};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use lettre::message::Mailbox;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tracing::{error, trace};
|
use tracing::{error, trace};
|
||||||
|
@ -35,7 +36,7 @@ pub struct Reminder {
|
||||||
planned: OffsetDateTime,
|
planned: OffsetDateTime,
|
||||||
title: String,
|
title: String,
|
||||||
message: String,
|
message: String,
|
||||||
receiver: String,
|
receiver: Mailbox,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unused_async)]
|
#[allow(clippy::unused_async)]
|
||||||
|
@ -48,7 +49,7 @@ pub async fn create_reminder(
|
||||||
planned: data.planned,
|
planned: data.planned,
|
||||||
title: &data.title,
|
title: &data.title,
|
||||||
message: &data.message,
|
message: &data.message,
|
||||||
receiver: &data.receiver,
|
receiver: &data.receiver.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!(?data, "received data");
|
trace!(?data, "received data");
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use anyhow::{bail, Error, Result};
|
use anyhow::{anyhow, bail, Error, Result};
|
||||||
|
use lettre::{message::Mailbox, Address};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
env, fs,
|
env, fs,
|
||||||
|
@ -7,6 +9,8 @@ use std::{
|
||||||
};
|
};
|
||||||
use tracing::{error, info, trace, warn};
|
use tracing::{error, info, trace, warn};
|
||||||
|
|
||||||
|
static CONFIG: OnceCell<Config> = OnceCell::new();
|
||||||
|
|
||||||
fn default_database_host() -> String {
|
fn default_database_host() -> String {
|
||||||
"localhost".to_string()
|
"localhost".to_string()
|
||||||
}
|
}
|
||||||
|
@ -75,15 +79,42 @@ impl Default for Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_email_from() -> Mailbox {
|
||||||
|
Mailbox::new(
|
||||||
|
Some(env!("CARGO_BIN_NAME").to_string()),
|
||||||
|
Address::new(env!("CARGO_BIN_NAME"), "localhost").unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Email {
|
||||||
|
/// Address the notification emails are sent from
|
||||||
|
#[serde(default = "default_email_from")]
|
||||||
|
pub from: Mailbox,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Email {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
from: default_email_from(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Database configuration
|
/// Database configuration
|
||||||
pub database: Database,
|
pub database: Database,
|
||||||
|
|
||||||
/// server configuration
|
/// Server configuration
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub server: Server,
|
pub server: Server,
|
||||||
|
|
||||||
|
/// Email configuration
|
||||||
|
#[serde(default)]
|
||||||
|
pub email: Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -130,4 +161,15 @@ impl Config {
|
||||||
Ok(Self::try_paths()?)
|
Ok(Self::try_paths()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init(file: Option<PathBuf>) -> Result<()> {
|
||||||
|
CONFIG
|
||||||
|
.set(Self::load_config(file)?)
|
||||||
|
.map_err(|_| anyhow!("configuration already initialized"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get() -> &'static Self {
|
||||||
|
CONFIG.get().expect("config is not initialized")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -51,14 +51,14 @@ fn remind(
|
||||||
.load::<Reminder>(&mut db_pool.get()?)?;
|
.load::<Reminder>(&mut db_pool.get()?)?;
|
||||||
|
|
||||||
if result.is_empty() {
|
if result.is_empty() {
|
||||||
info!("no reminders present, parking indefinitely");
|
info!("no reminders present, waiting for new reminder");
|
||||||
std::thread::park();
|
std::thread::park();
|
||||||
} else {
|
} else {
|
||||||
for reminder in result {
|
for reminder in result {
|
||||||
trace!(?reminder, "checking reminder");
|
trace!(?reminder, "checking reminder");
|
||||||
if reminder.planned <= OffsetDateTime::now_utc() {
|
if reminder.planned <= OffsetDateTime::now_utc() {
|
||||||
let email = Message::builder()
|
let email = Message::builder()
|
||||||
.from(format!("{}@localhost", env!("CARGO_BIN_NAME")).parse()?)
|
.from(Config::get().email.from.clone())
|
||||||
.to(reminder.receiver.parse()?)
|
.to(reminder.receiver.parse()?)
|
||||||
.subject(&reminder.title)
|
.subject(&reminder.title)
|
||||||
.body(reminder.message.to_string())?;
|
.body(reminder.message.to_string())?;
|
||||||
|
@ -105,8 +105,9 @@ async fn main() -> Result<()> {
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
);
|
);
|
||||||
|
|
||||||
let config = Config::load_config(args.config)?;
|
Config::init(args.config)?;
|
||||||
let mut db_pool = get_connection_pool(&config)?;
|
|
||||||
|
let mut db_pool = get_connection_pool(Config::get())?;
|
||||||
trace!(migrations = ?db_pool
|
trace!(migrations = ?db_pool
|
||||||
.get()?
|
.get()?
|
||||||
.run_pending_migrations(MIGRATIONS)
|
.run_pending_migrations(MIGRATIONS)
|
||||||
|
@ -120,7 +121,7 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let db_pool = get_connection_pool(&config)?;
|
let db_pool = get_connection_pool(Config::get())?;
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/v1/reminder", post(api::create_reminder))
|
.route("/v1/reminder", post(api::create_reminder))
|
||||||
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
||||||
|
@ -129,7 +130,7 @@ async fn main() -> Result<()> {
|
||||||
db_pool,
|
db_pool,
|
||||||
reminder: Arc::new(reminder),
|
reminder: Arc::new(reminder),
|
||||||
});
|
});
|
||||||
let addr = SocketAddr::from((config.server.address, config.server.port));
|
let addr = SocketAddr::from((Config::get().server.address, Config::get().server.port));
|
||||||
|
|
||||||
info!("{} listening on {}", env!("CARGO_PKG_NAME"), addr);
|
info!("{} listening on {}", env!("CARGO_PKG_NAME"), addr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue