feat: Use url::Host
instead of IpOrUrl
Signed-off-by: Awiteb <a@4rs.nl>
This commit is contained in:
parent
1c273d746b
commit
daef92207e
6 changed files with 59 additions and 86 deletions
|
@ -36,11 +36,7 @@ use crate::nonce::NonceCache;
|
|||
pub(crate) fn postgres_url(db_config: &Postgres) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
db_config.user,
|
||||
db_config.password,
|
||||
db_config.host.as_str(),
|
||||
db_config.port,
|
||||
db_config.name
|
||||
db_config.user, db_config.password, db_config.host, db_config.port, db_config.name
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ use std::{net::IpAddr, path::PathBuf};
|
|||
use clap::Parser;
|
||||
use oxidetalis_core::types::Size;
|
||||
|
||||
use crate::{types::OpenApiViewer, IpOrUrl};
|
||||
use crate::types::{Host, OpenApiViewer};
|
||||
|
||||
/// Header message, used in the help message
|
||||
const HEADER: &str = r#"Copyright (C) 2024 Awiteb <a@4rs.nl>, OxideTalis Contributors
|
||||
|
@ -74,7 +74,7 @@ pub struct CliArgs {
|
|||
pub register_enable: Option<bool>,
|
||||
/// Hostname or IP address of the PostgreSQL database.
|
||||
#[clap(long, env = "OXIDETALIS_DB_HOST")]
|
||||
pub postgres_host: Option<IpOrUrl>,
|
||||
pub postgres_host: Option<Host>,
|
||||
/// Port number of the PostgreSQL database.
|
||||
#[clap(long, env = "OXIDETALIS_DB_PORT")]
|
||||
pub postgres_port: Option<u16>,
|
||||
|
|
|
@ -81,7 +81,6 @@ pub(crate) mod openapi {
|
|||
|
||||
/// Postgres default configs
|
||||
pub(crate) mod postgres {
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn user() -> String {
|
||||
"oxidetalis".to_owned()
|
||||
|
@ -89,8 +88,9 @@ pub(crate) mod postgres {
|
|||
pub fn password() -> String {
|
||||
"oxidetalis".to_owned()
|
||||
}
|
||||
pub fn host() -> crate::IpOrUrl {
|
||||
crate::IpOrUrl::from_str("localhost").expect("Is a valid localhost")
|
||||
pub const fn host() -> crate::Host {
|
||||
#[allow(clippy::absolute_paths)]
|
||||
crate::Host(url::Host::Ipv4(std::net::Ipv4Addr::new(127, 0, 0, 1)))
|
||||
}
|
||||
pub fn name() -> String {
|
||||
"oxidetalis_db".to_owned()
|
||||
|
|
|
@ -95,7 +95,8 @@ pub struct Postgres {
|
|||
pub password: String,
|
||||
/// Database host
|
||||
#[derivative(Default(value = "defaults::postgres::host()"))]
|
||||
pub host: IpOrUrl,
|
||||
#[serde(with = "serde_with::host")]
|
||||
pub host: Host,
|
||||
/// Database port
|
||||
#[derivative(Default(value = "defaults::postgres::port()"))]
|
||||
pub port: u16,
|
||||
|
|
|
@ -21,34 +21,10 @@
|
|||
|
||||
//! Serialize and deserialize some oxidetalis configurations
|
||||
|
||||
use serde::{de::Error as DeError, Deserialize, Deserializer};
|
||||
|
||||
/// Serialize and deserialze the string of IpOrUrl struct
|
||||
pub(crate) mod ip_or_url {
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serializer};
|
||||
|
||||
use crate::IpOrUrl;
|
||||
|
||||
pub fn serialize<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(value)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(de: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(IpOrUrl::from_str(&String::deserialize(de)?)
|
||||
.map_err(DeError::custom)?
|
||||
.as_str()
|
||||
.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_url_path<'de, D>(de: D) -> Result<String, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
@ -61,3 +37,24 @@ where
|
|||
}
|
||||
Ok(url_path)
|
||||
}
|
||||
|
||||
pub mod host {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
use crate::Host;
|
||||
|
||||
pub fn deserialize<'de, D>(de: D) -> Result<Host, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Host::from_str(&String::deserialize(de)?)
|
||||
.map_err(|_| DeError::custom("Invalid host name, invalid IPv4, IPv6 or domain name"))
|
||||
}
|
||||
|
||||
pub fn serialize<S>(host: &Host, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&host.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
//! Oxidetalis config types
|
||||
|
||||
use std::{net::IpAddr, str::FromStr};
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use salvo_oapi::{rapidoc::RapiDoc, redoc::ReDoc, scalar::Scalar, swagger_ui::SwaggerUi};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -41,6 +41,33 @@ pub enum OpenApiViewer {
|
|||
SwaggerUi,
|
||||
}
|
||||
|
||||
/// Host type, a wrapper around `url::Host`
|
||||
///
|
||||
/// Because `url::Host` does not implement `FromStr`, we need to wrap it
|
||||
/// in a newtype to implement `FromStr` for it.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Host(pub url::Host);
|
||||
|
||||
impl FromStr for Host {
|
||||
type Err = url::ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// It appears that @SimonSapin prefers not to use the `FromStr` trait.
|
||||
// Instead, he is implementing `parse` without utilizing `FromStr`.
|
||||
//
|
||||
// - <https://github.com/servo/rust-url/pull/18#issuecomment-53467026>
|
||||
// - <https://github.com/servo/rust-url/pull/107#issuecomment-100611345>
|
||||
// - <https://github.com/servo/rust-url/issues/286#issuecomment-284193315>
|
||||
Ok(Self(url::Host::parse(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Host {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenApiViewer {
|
||||
/// Create a router for the viewer
|
||||
pub fn into_router(&self, config: &crate::Config) -> salvo_core::Router {
|
||||
|
@ -76,51 +103,3 @@ impl OpenApiViewer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type hold url or ip (used for database host)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IpOrUrl(#[serde(with = "crate::serde_with::ip_or_url")] String);
|
||||
|
||||
impl Default for IpOrUrl {
|
||||
fn default() -> Self {
|
||||
IpOrUrl("localhost".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl IpOrUrl {
|
||||
/// Returns &str ip or url
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for IpOrUrl {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(IpOrUrl(
|
||||
if let Ok(res) = IpAddr::from_str(s).map(|i| i.to_string()) {
|
||||
res
|
||||
} else {
|
||||
validate_domain(s)?
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_domain(domain: &str) -> Result<String, String> {
|
||||
if domain != "localhost" {
|
||||
let subs = domain.split('.');
|
||||
for sub in subs {
|
||||
let length = sub.chars().count();
|
||||
if !sub.chars().all(|c| c.is_alphanumeric() || c == '-')
|
||||
|| sub.starts_with('-')
|
||||
|| sub.ends_with('-')
|
||||
|| (length > 0 && length <= 64)
|
||||
{
|
||||
return Err("Invalid domain name".to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(domain.to_owned())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue