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 chrono_tz::{Tz, UTC};
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
use crate::{get_host_time_zone_or_utc, Error};
|
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 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)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct PartialClientConfig {
|
pub struct PartialClientConfig {
|
||||||
time_zone: Option<Tz>,
|
pub time_zone: Option<Tz>,
|
||||||
storage: Option<PartialClientStorageConfig>,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
use std::path::PathBuf;
|
|
||||||
const EMPTY_CONFIG_TOML: &str = r#""#;
|
const EMPTY_CONFIG_TOML: &str = r#""#;
|
||||||
static EMPTY_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
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"
|
const LOCAL_STORAGE_CONFIG_TOML: &str = r#"time_zone = "UTC"
|
||||||
|
storage = "local"
|
||||||
[storage.local]
|
|
||||||
database_path = "."
|
|
||||||
"#;
|
"#;
|
||||||
static LOCAL_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
static LOCAL_STORAGE_CONFIG_STRUCT: OnceCell<PartialClientConfig> = OnceCell::const_new();
|
||||||
|
|
||||||
|
@ -65,11 +110,7 @@ database_path = "."
|
||||||
LOCAL_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
LOCAL_STORAGE_CONFIG_STRUCT.get_or_init(|| async {
|
||||||
PartialClientConfig{
|
PartialClientConfig{
|
||||||
time_zone: Some(UTC),
|
time_zone: Some(UTC),
|
||||||
storage: Some(PartialClientStorageConfig::Local(
|
storage: Some(ClientStorageConfig::Local),
|
||||||
PartialClientLocalStorageConfig {
|
|
||||||
database_path: Some(PathBuf::from_str(".").unwrap()),
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}).await
|
}).await
|
||||||
}
|
}
|
||||||
|
@ -83,5 +124,35 @@ database_path = "."
|
||||||
async fn serialize_local_storage_client_config() {
|
async fn serialize_local_storage_client_config() {
|
||||||
assert_eq!(LOCAL_STORAGE_CONFIG_TOML, toml::to_string(get_local_storage_client_config_struct().await).unwrap());
|
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;
|
mod remote;
|
||||||
|
|
||||||
pub use local::{
|
pub use remote::ClientRemoteStorageConfig;
|
||||||
ClientLocalStorageConfig,
|
|
||||||
PartialClientLocalStorageConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use remote::{
|
|
||||||
ClientRemoteStorageConfig,
|
|
||||||
PartialClientRemoteStorageConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
Deserialize,
|
Deserialize,
|
||||||
Serialize
|
Serialize
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ClientStorageConfig {
|
pub enum ClientStorageConfig {
|
||||||
Local(ClientLocalStorageConfig),
|
Local,
|
||||||
Remote(ClientRemoteStorageConfig),
|
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
|
net::IpAddr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
|
||||||
pub struct ClientRemoteStorageConfig {
|
pub struct ClientRemoteStorageConfig {
|
||||||
pub endpoint: String,
|
pub endpoint: String,
|
||||||
pub access_key: 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 client;
|
||||||
|
mod database;
|
||||||
mod error;
|
mod error;
|
||||||
|
#[cfg(feature="server")]
|
||||||
mod server;
|
mod server;
|
||||||
mod user;
|
|
||||||
|
#[cfg(feature="client")]
|
||||||
|
pub use client::{
|
||||||
|
ClientConfig,
|
||||||
|
CLIENT_CONFIG,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use database::{
|
||||||
|
DatabaseConfig,
|
||||||
|
PartialDatabaseConfig,
|
||||||
|
};
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
||||||
|
#[cfg(feature="server")]
|
||||||
pub use server::{
|
pub use server::{
|
||||||
ServerConfig,
|
ServerConfig,
|
||||||
PartialServerConfig,
|
PartialServerConfig,
|
||||||
SERVER_CONFIG,
|
SERVER_CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use client::{
|
|
||||||
ClientConfig,
|
|
||||||
PartialClientConfig,
|
|
||||||
};
|
|
||||||
|
|
||||||
use chrono_tz::{Tz, UTC};
|
use chrono_tz::{Tz, UTC};
|
||||||
|
|
||||||
fn get_host_time_zone_or_utc() -> Tz {
|
fn get_host_time_zone_or_utc() -> Tz {
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
use chrono_tz::{Tz, UTC};
|
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 serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
|
default::Default,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
net::IpAddr
|
net::IpAddr,
|
||||||
};
|
};
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
pub static SERVER_CONFIG: OnceServerConfig = OnceServerConfig::const_new();
|
pub static SERVER_CONFIG: OnceServerConfig = OnceServerConfig::const_new();
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
pub listen_ips: Vec<IpAddr>,
|
pub listen_ips: Vec<IpAddr>,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
pub database_url: String,
|
|
||||||
pub time_zone: Tz,
|
pub time_zone: Tz,
|
||||||
|
pub database: DatabaseConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerConfig {
|
impl ServerConfig {
|
||||||
|
@ -27,7 +33,7 @@ impl TryFrom<PartialServerConfig> for ServerConfig {
|
||||||
Ok(ServerConfig{
|
Ok(ServerConfig{
|
||||||
listen_ips: p.listen_ips.ok_or(Error::MissingConfig("listen_ips".to_string()))?,
|
listen_ips: p.listen_ips.ok_or(Error::MissingConfig("listen_ips".to_string()))?,
|
||||||
port: p.port.ok_or(Error::MissingConfig("port".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()))?,
|
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 struct PartialServerConfig {
|
||||||
pub listen_ips: Option<Vec<IpAddr>>,
|
pub listen_ips: Option<Vec<IpAddr>>,
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
pub database_url: Option<String>,
|
pub database: Option<PartialDatabaseConfig>,
|
||||||
pub time_zone: Option<Tz>,
|
pub time_zone: Option<Tz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,21 +77,11 @@ impl PartialServerConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for 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 {
|
fn default() -> Self {
|
||||||
PartialServerConfig {
|
PartialServerConfig {
|
||||||
listen_ips: Some(vec!["127.0.0.1".parse().unwrap(), "::1".parse().unwrap()]),
|
listen_ips: Some(vec!["127.0.0.1".parse().unwrap(), "::1".parse().unwrap()]),
|
||||||
port: Some(3000),
|
port: Some(3000),
|
||||||
database_url: None,
|
database: None,
|
||||||
time_zone: Some(get_host_time_zone_or_utc())
|
time_zone: Some(get_host_time_zone_or_utc())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,17 +91,36 @@ impl FromStr for PartialServerConfig {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
/// #Examples
|
/// #Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use dpts_config::PartialServerConfig;
|
/// use dpts_config::{
|
||||||
/// let config: PartialServerConfig = r#"
|
/// PartialServerConfig,
|
||||||
|
/// PartialDatabaseConfig,
|
||||||
|
/// };
|
||||||
|
/// use std::{
|
||||||
|
/// default::Default,
|
||||||
|
/// net::IpAddr
|
||||||
|
/// };
|
||||||
|
/// let config_from_str: PartialServerConfig = r#"
|
||||||
/// listen_ips = ["0.0.0.0"]
|
/// listen_ips = ["0.0.0.0"]
|
||||||
/// port = 8000
|
/// port = 8000
|
||||||
/// database_url = "sqlite::memory:"
|
|
||||||
/// time_zone = "Asia/Tokyo"
|
/// time_zone = "Asia/Tokyo"
|
||||||
|
///
|
||||||
|
/// [database]
|
||||||
|
/// url = "sqlite::memory:"
|
||||||
|
/// sqlx_logging = true
|
||||||
/// "#.parse().unwrap();
|
/// "#.parse().unwrap();
|
||||||
/// assert_eq!(config.listen_ips, Some(vec!["0.0.0.0".parse().unwrap()]));
|
///
|
||||||
/// assert_eq!(config.port, Some(8000));
|
/// let config: PartialServerConfig = PartialServerConfig{
|
||||||
/// assert_eq!(config.database_url, Some("sqlite::memory:".to_string()));
|
/// listen_ips : Some(vec!["0.0.0.0".parse().unwrap()]),
|
||||||
/// assert_eq!(config.time_zone, Some("Asia/Tokyo".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> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
|
Loading…
Add table
Reference in a new issue