Update config for server and client
This commit is contained in:
parent
bacc24e801
commit
aa7f31b396
8 changed files with 196 additions and 85 deletions
|
@ -8,28 +8,75 @@ use serde::{
|
|||
};
|
||||
|
||||
use chrono_tz::{Tz, UTC};
|
||||
use tokio::sync::OnceCell;
|
||||
use crate::{get_host_time_zone_or_utc, Error};
|
||||
use std::{
|
||||
str::FromStr,
|
||||
net::IpAddr
|
||||
};
|
||||
|
||||
pub static CLIENT_CONFIG: OnceClientConfig = OnceClientConfig::const_new();
|
||||
|
||||
pub struct OnceClientConfig {
|
||||
inner: OnceCell<ClientConfig>,
|
||||
}
|
||||
|
||||
impl OnceClientConfig {
|
||||
const fn const_new() -> Self {
|
||||
Self {
|
||||
inner: OnceCell::const_new(),
|
||||
}
|
||||
}
|
||||
pub fn get(&self) -> Option<&ClientConfig> {
|
||||
self.inner.get()
|
||||
}
|
||||
pub async fn get_or_init<F, T>(&self, f: F) -> &ClientConfig where
|
||||
F: FnOnce() -> T,
|
||||
T: Future<Output = ClientConfig>
|
||||
{
|
||||
self.inner.get_or_init(f).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct ClientConfig {
|
||||
|
||||
pub time_zone: Tz,
|
||||
pub storage: ClientStorageConfig,
|
||||
}
|
||||
|
||||
impl TryFrom<&PartialClientConfig> for ClientConfig {
|
||||
type Error = Error;
|
||||
fn try_from(p: &PartialClientConfig) -> Result<ClientConfig, Self::Error> {
|
||||
Ok(ClientConfig{
|
||||
time_zone: p.time_zone.ok_or(Error::MissingConfig("time_zone".to_string()))?,
|
||||
storage: p.clone().storage.ok_or(Error::MissingConfig("storage".to_string()))?,
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PartialClientConfig {
|
||||
time_zone: Option<Tz>,
|
||||
storage: Option<PartialClientStorageConfig>,
|
||||
pub time_zone: Option<Tz>,
|
||||
pub storage: Option<ClientStorageConfig>,
|
||||
}
|
||||
|
||||
impl PartialClientConfig {
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl Default for PartialClientConfig {
|
||||
fn default() -> Self {
|
||||
PartialClientConfig {
|
||||
time_zone: Some(get_host_time_zone_or_utc()),
|
||||
storage: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tokio::sync::OnceCell;
|
||||
use std::path::PathBuf;
|
||||
const EMPTY_CONFIG_TOML: &str = r#""#;
|
||||
static EMPTY_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
|
||||
|
@ -55,9 +102,7 @@ mod tests {
|
|||
}
|
||||
|
||||
const LOCAL_STORAGE_CONFIG_TOML: &str = r#"time_zone = "UTC"
|
||||
|
||||
[storage.local]
|
||||
database_path = "."
|
||||
storage = "local"
|
||||
"#;
|
||||
static LOCAL_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
|
||||
|
@ -65,11 +110,7 @@ database_path = "."
|
|||
LOCAL_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
||||
PartialClientConfig{
|
||||
time_zone: Some(UTC),
|
||||
storage: Some(PartialClientStorageConfig::Local(
|
||||
PartialClientLocalStorageConfig {
|
||||
database_path: Some(PathBuf::from_str(".").unwrap()),
|
||||
}
|
||||
)),
|
||||
storage: Some(ClientStorageConfig::Local),
|
||||
}
|
||||
}).await
|
||||
}
|
||||
|
@ -83,5 +124,35 @@ database_path = "."
|
|||
async fn serialize_local_storage_client_config() {
|
||||
assert_eq!(LOCAL_STORAGE_CONFIG_TOML, toml::to_string(get_local_storage_client_config_struct().await).unwrap());
|
||||
}
|
||||
|
||||
const REMOTE_STORAGE_CONFIG_TOML: &str = r#"time_zone = "UTC"
|
||||
|
||||
[storage.remote]
|
||||
endpoint = "https://example.com"
|
||||
access_key = "test"
|
||||
"#;
|
||||
static REMOTE_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||
|
||||
async fn get_remote_storage_client_config_struct() -> &'static PartialClientConfig {
|
||||
REMOTE_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
||||
PartialClientConfig{
|
||||
time_zone: Some(UTC),
|
||||
storage: Some(ClientStorageConfig::Remote(ClientRemoteStorageConfig {
|
||||
endpoint: "https://example.com".to_string(),
|
||||
access_key: "test".to_string(),
|
||||
})),
|
||||
}
|
||||
}).await
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn deserialize_remote_storage_client_config() {
|
||||
let config: PartialClientConfig = toml::from_str(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||
assert_eq!(&config, get_remote_storage_client_config_struct().await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn serialize_remote_storage_client_config() {
|
||||
assert_eq!(REMOTE_STORAGE_CONFIG_TOML, toml::to_string(get_remote_storage_client_config_struct().await).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
mod local;
|
||||
mod remote;
|
||||
|
||||
pub use local::{
|
||||
ClientLocalStorageConfig,
|
||||
PartialClientLocalStorageConfig,
|
||||
};
|
||||
|
||||
pub use remote::{
|
||||
ClientRemoteStorageConfig,
|
||||
PartialClientRemoteStorageConfig,
|
||||
};
|
||||
pub use remote::ClientRemoteStorageConfig;
|
||||
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ClientStorageConfig {
|
||||
Local(ClientLocalStorageConfig),
|
||||
Local,
|
||||
Remote(ClientRemoteStorageConfig),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PartialClientStorageConfig {
|
||||
Local(PartialClientLocalStorageConfig),
|
||||
Remote(PartialClientRemoteStorageConfig),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize
|
||||
};
|
||||
|
||||
pub struct ClientLocalStorageConfig {
|
||||
pub database_path: PathBuf
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PartialClientLocalStorageConfig {
|
||||
pub database_path: Option<PathBuf>,
|
||||
}
|
||||
|
|
@ -10,13 +10,9 @@ use std::{
|
|||
net::IpAddr
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
||||
pub struct ClientRemoteStorageConfig {
|
||||
pub endpoint: String,
|
||||
pub access_key: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PartialClientRemoteStorageConfig {
|
||||
pub endpoint: Option<String>,
|
||||
pub access_key: Option<String>,
|
||||
}
|
45
dpts-config/src/database.rs
Normal file
45
dpts-config/src/database.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub struct DatabaseConfig {
|
||||
pub url: String,
|
||||
pub max_connections: Option<u32>,
|
||||
pub min_connections: Option<u32>,
|
||||
pub connect_timeout: Option<Duration>,
|
||||
pub acquire_timeout: Option<Duration>,
|
||||
pub idle_timeout: Option<Duration>,
|
||||
pub max_lifetime: Option<Duration>,
|
||||
pub sqlx_logging: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<PartialDatabaseConfig> for DatabaseConfig{
|
||||
type Error = Error;
|
||||
fn try_from(p: PartialDatabaseConfig) -> Result<DatabaseConfig, Self::Error> {
|
||||
Ok(DatabaseConfig{
|
||||
url: p.url.ok_or(Error::MissingConfig("url".to_string()))?,
|
||||
max_connections: p.max_connections,
|
||||
min_connections: p.min_connections,
|
||||
connect_timeout: p.connect_timeout,
|
||||
acquire_timeout: p.acquire_timeout,
|
||||
idle_timeout: p.idle_timeout,
|
||||
max_lifetime: p.max_lifetime,
|
||||
sqlx_logging: p.sqlx_logging.ok_or(Error::MissingConfig("sqlx_logging".to_string()))?
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct PartialDatabaseConfig {
|
||||
pub url: Option<String>,
|
||||
pub max_connections: Option<u32>,
|
||||
pub min_connections: Option<u32>,
|
||||
pub connect_timeout: Option<Duration>,
|
||||
pub acquire_timeout: Option<Duration>,
|
||||
pub idle_timeout: Option<Duration>,
|
||||
pub max_lifetime: Option<Duration>,
|
||||
pub sqlx_logging: Option<bool>
|
||||
}
|
||||
|
|
@ -1,20 +1,30 @@
|
|||
#[cfg(feature="client")]
|
||||
mod client;
|
||||
mod database;
|
||||
mod error;
|
||||
#[cfg(feature="server")]
|
||||
mod server;
|
||||
mod user;
|
||||
|
||||
#[cfg(feature="client")]
|
||||
pub use client::{
|
||||
ClientConfig,
|
||||
CLIENT_CONFIG,
|
||||
};
|
||||
|
||||
pub use database::{
|
||||
DatabaseConfig,
|
||||
PartialDatabaseConfig,
|
||||
};
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
#[cfg(feature="server")]
|
||||
pub use server::{
|
||||
ServerConfig,
|
||||
PartialServerConfig,
|
||||
SERVER_CONFIG,
|
||||
};
|
||||
|
||||
pub use client::{
|
||||
ClientConfig,
|
||||
PartialClientConfig,
|
||||
};
|
||||
|
||||
use chrono_tz::{Tz, UTC};
|
||||
|
||||
fn get_host_time_zone_or_utc() -> Tz {
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
use chrono_tz::{Tz, UTC};
|
||||
use crate::{get_host_time_zone_or_utc, Error};
|
||||
use crate::{
|
||||
get_host_time_zone_or_utc,
|
||||
DatabaseConfig,
|
||||
PartialDatabaseConfig,
|
||||
Error
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
default::Default,
|
||||
str::FromStr,
|
||||
net::IpAddr
|
||||
net::IpAddr,
|
||||
};
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
pub static SERVER_CONFIG: OnceServerConfig = OnceServerConfig::const_new();
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub struct ServerConfig {
|
||||
pub listen_ips: Vec<IpAddr>,
|
||||
pub port: u16,
|
||||
pub database_url: String,
|
||||
pub time_zone: Tz,
|
||||
pub database: DatabaseConfig
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
|
@ -27,7 +33,7 @@ impl TryFrom<PartialServerConfig> for ServerConfig {
|
|||
Ok(ServerConfig{
|
||||
listen_ips: p.listen_ips.ok_or(Error::MissingConfig("listen_ips".to_string()))?,
|
||||
port: p.port.ok_or(Error::MissingConfig("port".to_string()))?,
|
||||
database_url: p.database_url.ok_or(Error::MissingConfig("database_url".to_string()))?,
|
||||
database: p.database.ok_or(Error::MissingConfig("database.*".to_string()))?.try_into()?,
|
||||
time_zone: p.time_zone.ok_or(Error::MissingConfig("time_zone".to_string()))?,
|
||||
})
|
||||
}
|
||||
|
@ -54,12 +60,12 @@ impl OnceServerConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
|
||||
pub struct PartialServerConfig {
|
||||
pub listen_ips: Option<Vec<IpAddr>>,
|
||||
pub port: Option<u16>,
|
||||
pub database_url: Option<String>,
|
||||
pub database: Option<PartialDatabaseConfig>,
|
||||
pub time_zone: Option<Tz>,
|
||||
}
|
||||
|
||||
|
@ -71,21 +77,11 @@ impl PartialServerConfig {
|
|||
}
|
||||
|
||||
impl Default for PartialServerConfig {
|
||||
/// #Examples
|
||||
/// ```
|
||||
/// use dpts_config::PartialServerConfig;
|
||||
/// let config = PartialServerConfig::default();
|
||||
/// assert_eq!(config.listen_ips, Some(vec!["127.0.0.1".parse().unwrap(), "::1".parse().unwrap()]));
|
||||
/// assert_eq!(config.port, Some(3000));
|
||||
/// assert_eq!(config.database_url, None);
|
||||
/// assert_eq!(config.time_zone, Some(iana_time_zone::get_timezone().unwrap().parse().unwrap()))
|
||||
/// ```
|
||||
///
|
||||
fn default() -> Self {
|
||||
PartialServerConfig {
|
||||
listen_ips: Some(vec!["127.0.0.1".parse().unwrap(), "::1".parse().unwrap()]),
|
||||
port: Some(3000),
|
||||
database_url: None,
|
||||
database: None,
|
||||
time_zone: Some(get_host_time_zone_or_utc())
|
||||
}
|
||||
}
|
||||
|
@ -95,17 +91,36 @@ impl FromStr for PartialServerConfig {
|
|||
type Err = Error;
|
||||
/// #Examples
|
||||
/// ```
|
||||
/// use dpts_config::PartialServerConfig;
|
||||
/// let config: PartialServerConfig = r#"
|
||||
/// use dpts_config::{
|
||||
/// PartialServerConfig,
|
||||
/// PartialDatabaseConfig,
|
||||
/// };
|
||||
/// use std::{
|
||||
/// default::Default,
|
||||
/// net::IpAddr
|
||||
/// };
|
||||
/// let config_from_str: PartialServerConfig = r#"
|
||||
/// listen_ips = ["0.0.0.0"]
|
||||
/// port = 8000
|
||||
/// database_url = "sqlite::memory:"
|
||||
/// time_zone = "Asia/Tokyo"
|
||||
///
|
||||
/// [database]
|
||||
/// url = "sqlite::memory:"
|
||||
/// sqlx_logging = true
|
||||
/// "#.parse().unwrap();
|
||||
/// assert_eq!(config.listen_ips, Some(vec!["0.0.0.0".parse().unwrap()]));
|
||||
/// assert_eq!(config.port, Some(8000));
|
||||
/// assert_eq!(config.database_url, Some("sqlite::memory:".to_string()));
|
||||
/// assert_eq!(config.time_zone, Some("Asia/Tokyo".parse().unwrap()))
|
||||
///
|
||||
/// let config: PartialServerConfig = PartialServerConfig{
|
||||
/// listen_ips : Some(vec!["0.0.0.0".parse().unwrap()]),
|
||||
/// port: Some(8000),
|
||||
/// time_zone: Some(chrono_tz::Asia::Tokyo),
|
||||
/// database: Some(PartialDatabaseConfig {
|
||||
/// url: Some("sqlite::memory:".to_string()),
|
||||
/// sqlx_logging: Some(true),
|
||||
/// ..Default::default()
|
||||
/// }),
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(config_from_str, config);
|
||||
/// ```
|
||||
///
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
|
Loading…
Add table
Reference in a new issue