mirror of https://github.com/mastodon/flodgatt
Before deleting redundnat macros
This commit is contained in:
parent
0a82bbe11b
commit
74a2ac3bb2
|
@ -1,13 +1,13 @@
|
|||
use crate::{config::deployment_cfg_types::*, err::FromStrOrDie, maybe_update};
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeploymentConfig<'a> {
|
||||
pub env: Env,
|
||||
pub log_level: LogLevel,
|
||||
pub address: FlodgattAddr,
|
||||
pub port: u16,
|
||||
pub unix_socket: Option<Socket>,
|
||||
pub port: Port2,
|
||||
pub unix_socket: Socket,
|
||||
pub cors: Cors<'a>,
|
||||
pub sse_interval: SseInterval,
|
||||
pub ws_interval: WsInterval,
|
||||
|
@ -16,40 +16,42 @@ impl Default for DeploymentConfig<'_> {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
env: Env::Development,
|
||||
log_level: LogLevel::Warn,
|
||||
address: FlodgattAddr::from_str_or_die(&"127.0.0.1".to_string()),
|
||||
port: 4000,
|
||||
unix_socket: None,
|
||||
log_level: LogLevel::default(),
|
||||
address: FlodgattAddr::default(),
|
||||
port: Port2::default(),
|
||||
unix_socket: Socket::default(),
|
||||
cors: Cors {
|
||||
allowed_methods: vec!["GET", "OPTIONS"],
|
||||
allowed_headers: vec!["Authorization", "Accept", "Cache-Control"],
|
||||
},
|
||||
sse_interval: SseInterval(Duration::from_millis(100)),
|
||||
ws_interval: WsInterval(Duration::from_millis(100)),
|
||||
sse_interval: SseInterval::default(),
|
||||
ws_interval: WsInterval::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DeploymentConfig<'_> {
|
||||
pub fn from_env(env_vars: HashMap<String, String>) -> Self {
|
||||
Self::default()
|
||||
let mut res = Self::default()
|
||||
.maybe_update_env(env_vars.get("NODE_ENV").map(Env::from_str_or_die))
|
||||
.maybe_update_env(env_vars.get("RUST_ENV").map(Env::from_str_or_die))
|
||||
.maybe_update_address(env_vars.get("BIND").map(FlodgattAddr::from_str_or_die))
|
||||
.maybe_update_port(env_vars.get("PORT").map(u16::from_str_or_die))
|
||||
.maybe_update_unix_socket(env_vars.get("SOCKET").map(Socket::from_str_or_die))
|
||||
.maybe_update_log_level(env_vars.get("RUST_LOG").map(LogLevel::from_str_or_die))
|
||||
.maybe_update_sse_interval(env_vars.get("SSE_FREQ").map(SseInterval::from_str_or_die))
|
||||
.maybe_update_ws_interval(env_vars.get("WS_FREQ").map(WsInterval::from_str_or_die))
|
||||
.log()
|
||||
.maybe_update_env(env_vars.get("RUST_ENV").map(Env::from_str_or_die));
|
||||
|
||||
res.log_level = LogLevel::from_env_var_or_die(env_vars.get("RUST_LOG"));
|
||||
res.address = FlodgattAddr::from_env_var_or_die(env_vars.get("BIND"));
|
||||
res.port = Port2::from_env_var_or_die(env_vars.get("PORT"));
|
||||
res.unix_socket = Socket::from_env_var_or_die(env_vars.get("SOCKET"));
|
||||
res.sse_interval = SseInterval::from_env_var_or_die(env_vars.get("SSE_FREQ"));
|
||||
res.ws_interval = WsInterval::from_env_var_or_die(env_vars.get("WS_FREQ"));
|
||||
|
||||
res.log()
|
||||
}
|
||||
|
||||
maybe_update!(maybe_update_env; env: Env);
|
||||
maybe_update!(maybe_update_port; port: u16);
|
||||
// maybe_update!(maybe_update_port; port: Port);
|
||||
maybe_update!(maybe_update_address; address: FlodgattAddr);
|
||||
maybe_update!(maybe_update_unix_socket; Some(unix_socket: Socket));
|
||||
maybe_update!(maybe_update_log_level; log_level: LogLevel);
|
||||
maybe_update!(maybe_update_sse_interval; sse_interval: SseInterval);
|
||||
maybe_update!(maybe_update_ws_interval; ws_interval: WsInterval);
|
||||
// maybe_update!(maybe_update_unix_socket; Some(unix_socket: Socket));
|
||||
// maybe_update!(maybe_update_log_level; log_level: LogLevel);
|
||||
// maybe_update!(maybe_update_sse_int; sse_interval: SseInterval);
|
||||
// maybe_update!(maybe_update_ws_int; ws_interval: WsInterval);
|
||||
|
||||
fn log(self) -> Self {
|
||||
log::warn!("Using deployment configuration:\n {:#?}", &self);
|
||||
|
|
|
@ -1,140 +1,80 @@
|
|||
use crate::err::FromStrOrDie;
|
||||
use std::{
|
||||
fmt, net::IpAddr, ops::Deref, os::unix::net::UnixListener, str::FromStr, time::Duration,
|
||||
};
|
||||
use crate::{derive_from_str_or_die, err::FromStrOrDie, from_env_var};
|
||||
use std::{fmt, net::IpAddr, os::unix::net::UnixListener, str::FromStr, time::Duration};
|
||||
use strum_macros::{EnumString, EnumVariantNames};
|
||||
|
||||
/// The current environment, which controls what file to read other ENV vars from
|
||||
#[derive(EnumString, EnumVariantNames, Debug)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Env {
|
||||
Production,
|
||||
Development,
|
||||
}
|
||||
impl FromStrOrDie<Self> for Env {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("RUST_ENV", format!("one of: {:?}", Self::variants()))
|
||||
}
|
||||
}
|
||||
derive_from_str_or_die!(Env {
|
||||
name: "RUST_ENV",
|
||||
value: format!("one of: {:?}", Self::variants())
|
||||
});
|
||||
|
||||
pub struct FlodgattAddr(pub IpAddr);
|
||||
impl Deref for FlodgattAddr {
|
||||
type Target = IpAddr;
|
||||
fn deref(&self) -> &IpAddr {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl FromStr for FlodgattAddr {
|
||||
type Err = std::net::AddrParseError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
s.parse().map(|num| Self(num))
|
||||
}
|
||||
}
|
||||
impl FromStrOrDie<Self> for FlodgattAddr {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("BIND", "a valid address (e.g., 127.0.0.1)".to_string())
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for FlodgattAddr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let addr = match self.0 {
|
||||
IpAddr::V4(addr) => addr.to_string(),
|
||||
IpAddr::V6(addr) => addr.to_string(),
|
||||
};
|
||||
write!(f, "{}", addr)
|
||||
}
|
||||
// The address to run Flodgatt on
|
||||
from_env_var!(FlodgattAddr {
|
||||
inner: IpAddr::V4("127.0.0.1".parse().expect("hardcoded")); IpAddr,
|
||||
env_var: "BIND",
|
||||
allowed_values: "a valid address (e.g., 127.0.0.1)".to_string(),
|
||||
}
|
||||
inner_from_str(|s| s.parse().ok()));
|
||||
|
||||
/// How verbosely Flodgatt should log messages
|
||||
#[derive(EnumString, EnumVariantNames, Debug)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum LogLevel {
|
||||
pub enum LogLevelInner {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
impl FromStrOrDie<Self> for LogLevel {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("RUST_LOG", format!("one of: {:?}", Self::variants()))
|
||||
}
|
||||
from_env_var!(LogLevel {
|
||||
inner: LogLevelInner::Warn; LogLevelInner,
|
||||
env_var: "RUST_LOG",
|
||||
allowed_values: format!("one of {:?}", LogLevelInner::variants()),
|
||||
}
|
||||
inner_from_str(|s| LogLevelInner::from_str(s).ok()));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Socket(pub UnixListener);
|
||||
impl Deref for Socket {
|
||||
type Target = UnixListener;
|
||||
fn deref(&self) -> &UnixListener {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl FromStr for Socket {
|
||||
type Err = std::io::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
UnixListener::bind(s).map(|socket| (Self(socket)))
|
||||
}
|
||||
}
|
||||
impl FromStrOrDie<Self> for Socket {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("SOCKET", "a valid Unix Socket".to_string())
|
||||
}
|
||||
// A Unix Socket to use in place of a local address
|
||||
from_env_var!(Socket{
|
||||
inner: None; Option<UnixListener>,
|
||||
env_var: "SOCKET",
|
||||
allowed_values: "a valid Unix Socket".to_string(),
|
||||
}
|
||||
inner_from_str(|s| match UnixListener::bind(s).ok() {
|
||||
Some(socket) => Some(Some(socket)),
|
||||
None => None,
|
||||
}));
|
||||
|
||||
/// The time between replies sent via WebSocket
|
||||
pub struct WsInterval(pub Duration);
|
||||
impl Deref for WsInterval {
|
||||
type Target = Duration;
|
||||
fn deref(&self) -> &Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl FromStr for WsInterval {
|
||||
type Err = std::num::ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
s.parse().map(|num| Self(Duration::from_millis(num)))
|
||||
}
|
||||
}
|
||||
impl FromStrOrDie<Self> for WsInterval {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("WS_FREQ", "a number of milliseconds".to_string())
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for WsInterval {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
// The time between replies sent via WebSocket
|
||||
from_env_var!(WsInterval {
|
||||
inner: Duration::from_millis(100); Duration,
|
||||
env_var: "WS_FREQ",
|
||||
allowed_values: "a number of milliseconds".to_string(),
|
||||
}
|
||||
inner_from_str(|s| s.parse().map(|num| Duration::from_millis(num)).ok()));
|
||||
|
||||
/// The time between replies sent via Server Sent Events
|
||||
pub struct SseInterval(pub Duration);
|
||||
impl Deref for SseInterval {
|
||||
type Target = Duration;
|
||||
fn deref(&self) -> &Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl FromStr for SseInterval {
|
||||
type Err = std::num::ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
s.parse().map(|num| Self(Duration::from_millis(num)))
|
||||
}
|
||||
}
|
||||
impl FromStrOrDie<Self> for SseInterval {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("SSE_FREQ", "a number of milliseconds".to_string())
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for SseInterval {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
// The time between replies sent via Server Sent Events
|
||||
from_env_var!(SseInterval {
|
||||
inner: Duration::from_millis(100); Duration,
|
||||
env_var: "SSE_FREQ",
|
||||
allowed_values: "a number of milliseconds".to_string(),
|
||||
}
|
||||
inner_from_str(|s| s.parse().map(|num| Duration::from_millis(num)).ok()));
|
||||
|
||||
impl FromStrOrDie<Self> for u16 {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
("PORT", "a number".to_string())
|
||||
}
|
||||
// The port to run Flodgatt on
|
||||
from_env_var!(Port2 {
|
||||
inner: 4000; u16,
|
||||
env_var: "PORT",
|
||||
allowed_values: "a number".to_string(),
|
||||
}
|
||||
inner_from_str(|s| s.parse().ok()));
|
||||
|
||||
/// Permissions for Cross Origin Resource Sharing (CORS)
|
||||
pub struct Cors<'a> {
|
||||
pub allowed_headers: Vec<&'a str>,
|
||||
pub allowed_methods: Vec<&'a str>,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
//! Configuration defaults. All settings with the prefix of `DEFAULT_` can be overridden
|
||||
//! by an environmental variable of the same name without that prefix (either by setting
|
||||
//! the variable at runtime or in the `.env` file)
|
||||
mod deployment_cfg;
|
||||
mod deployment_cfg_types;
|
||||
mod postgres_cfg;
|
||||
|
@ -9,11 +6,6 @@ pub use self::{
|
|||
deployment_cfg::DeploymentConfig, postgres_cfg::PostgresConfig, redis_cfg::RedisConfig,
|
||||
};
|
||||
|
||||
// **NOTE**: Polling Redis is much more time consuming than polling the `Receiver`
|
||||
// (on the order of 10ms rather than 50μs). Thus, changing this setting
|
||||
// would be a good place to start for performance improvements at the cost
|
||||
// of delaying all updates.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! maybe_update {
|
||||
($name:ident; $item: tt:$type:ty) => (
|
||||
|
@ -30,3 +22,94 @@ macro_rules! maybe_update {
|
|||
None => Self { ..self }
|
||||
}
|
||||
})}
|
||||
#[macro_export]
|
||||
macro_rules! derive_deref {
|
||||
($name:ident: $type:ty) => {
|
||||
impl std::ops::Deref for $name {
|
||||
type Target = $type;
|
||||
fn deref(&self) -> &$type {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! derive_oneline_debug {
|
||||
($item:ident) => {
|
||||
impl std::fmt::Debug for $item {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! derive_from_str_or_die {
|
||||
($item:ident {name: $name:expr,
|
||||
value: $value:expr}) => {
|
||||
impl FromStrOrDie<Self> for $item {
|
||||
fn name_and_values() -> (&'static str, String) {
|
||||
($name, $value)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! from_env_var {
|
||||
($name:ident {
|
||||
inner: $inner:expr; $type:ty,
|
||||
env_var: $env_var:tt,
|
||||
allowed_values: $allowed_values:expr,
|
||||
}
|
||||
inner_from_str(|$arg:ident| $body:expr)
|
||||
) => {
|
||||
pub struct $name {
|
||||
pub inner: $type,
|
||||
pub env_var: String,
|
||||
pub allowed_values: String,
|
||||
}
|
||||
impl std::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for $name {
|
||||
type Target = $type;
|
||||
fn deref(&self) -> &$type {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl $name {
|
||||
fn inner_from_str($arg: &str) -> Option<$type> {
|
||||
$body
|
||||
}
|
||||
fn update_inner(&mut self, inner: $type) -> &Self {
|
||||
self.inner = inner;
|
||||
self
|
||||
}
|
||||
pub fn default() -> Self {
|
||||
$name {
|
||||
inner: $inner,
|
||||
env_var: $env_var.to_string(),
|
||||
allowed_values: $allowed_values,
|
||||
}
|
||||
}
|
||||
pub fn from_env_var_or_die(env: Option<&String>) -> Self {
|
||||
let mut res = Self::default();
|
||||
if let Some(value) = env {
|
||||
res.update_inner(Self::inner_from_str(value).unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
"\"{}\" is not a valid value for {}. {} must be {}",
|
||||
value, res.env_var, res.env_var, res.allowed_values
|
||||
);
|
||||
std::process::exit(1);
|
||||
}));
|
||||
res
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@ pub struct RedisConfig {
|
|||
pub host: String,
|
||||
pub db: Option<String>,
|
||||
pub namespace: Option<String>,
|
||||
// **NOTE**: Polling Redis is much more time consuming than polling the `Receiver`
|
||||
// (on the order of 1ms rather than 50μs). Thus, changing this setting
|
||||
// would be a good place to start for performance improvements at the cost
|
||||
// of delaying all updates.
|
||||
pub polling_interval: Duration,
|
||||
}
|
||||
impl Default for RedisConfig {
|
||||
|
|
|
@ -79,9 +79,9 @@ fn main() {
|
|||
.allow_methods(cfg.cors.allowed_methods)
|
||||
.allow_headers(cfg.cors.allowed_headers);
|
||||
|
||||
let server_addr = net::SocketAddr::new(*cfg.address, cfg.port);
|
||||
let server_addr = net::SocketAddr::new(*cfg.address, cfg.port.inner);
|
||||
|
||||
if let Some(_socket) = cfg.unix_socket {
|
||||
if let Some(_socket) = cfg.unix_socket.inner.as_ref() {
|
||||
dbg_and_die!("Unix socket support not yet implemented");
|
||||
} else {
|
||||
warp::serve(websocket_routes.or(sse_routes).with(cors)).run(server_addr);
|
||||
|
|
Loading…
Reference in New Issue