mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
feat: inline domain health checks and improve address UX
- addPublicDomain returns DNS query + port check results (AddPublicDomainRes) so frontend skips separate API calls after adding a domain - addPrivateDomain returns check_dns result for the gateway - Support multiple ports per domain in validation modal (deduplicated) - Run port checks concurrently via futures::future::join_all - Add note to add-domain dialog showing other interfaces on same host - Add addXForwardedHeaders to knownProtocols in SDK Host.ts - Add plugin filter kind, pluginId filter, matchesAny, and docs to getServiceInterface.ts - Add PassthroughInfo type and passthroughs field to NetworkInfo - Pluralize "port forwarding rules" in i18n dictionaries
This commit is contained in:
@@ -174,11 +174,11 @@ async fn set_name(
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
struct CheckPortParams {
|
||||
pub struct CheckPortParams {
|
||||
#[arg(help = "help.arg.port")]
|
||||
port: u16,
|
||||
pub port: u16,
|
||||
#[arg(help = "help.arg.gateway-id")]
|
||||
gateway: GatewayId,
|
||||
pub gateway: GatewayId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS)]
|
||||
@@ -200,7 +200,7 @@ pub struct IfconfigPortRes {
|
||||
pub reachable: bool,
|
||||
}
|
||||
|
||||
async fn check_port(
|
||||
pub async fn check_port(
|
||||
ctx: RpcContext,
|
||||
CheckPortParams { port, gateway }: CheckPortParams,
|
||||
) -> Result<CheckPortRes, Error> {
|
||||
@@ -276,12 +276,12 @@ async fn check_port(
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
struct CheckDnsParams {
|
||||
pub struct CheckDnsParams {
|
||||
#[arg(help = "help.arg.gateway-id")]
|
||||
gateway: GatewayId,
|
||||
pub gateway: GatewayId,
|
||||
}
|
||||
|
||||
async fn check_dns(
|
||||
pub async fn check_dns(
|
||||
ctx: RpcContext,
|
||||
CheckDnsParams { gateway }: CheckDnsParams,
|
||||
) -> Result<bool, Error> {
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::DatabaseModel;
|
||||
use crate::hostname::ServerHostname;
|
||||
use crate::net::acme::AcmeProvider;
|
||||
use crate::net::gateway::{CheckDnsParams, CheckPortParams, CheckPortRes, check_dns, check_port};
|
||||
use crate::net::host::{HostApiKind, all_hosts};
|
||||
use crate::prelude::*;
|
||||
use crate::util::serde::{HandlerExtSerde, display_serializable};
|
||||
@@ -170,6 +171,15 @@ pub struct AddPublicDomainParams {
|
||||
pub gateway: GatewayId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct AddPublicDomainRes {
|
||||
#[ts(type = "string | null")]
|
||||
pub dns: Option<Ipv4Addr>,
|
||||
pub port: Vec<CheckPortRes>,
|
||||
}
|
||||
|
||||
pub async fn add_public_domain<Kind: HostApiKind>(
|
||||
ctx: RpcContext,
|
||||
AddPublicDomainParams {
|
||||
@@ -178,8 +188,9 @@ pub async fn add_public_domain<Kind: HostApiKind>(
|
||||
gateway,
|
||||
}: AddPublicDomainParams,
|
||||
inheritance: Kind::Inheritance,
|
||||
) -> Result<Option<Ipv4Addr>, Error> {
|
||||
ctx.db
|
||||
) -> Result<AddPublicDomainRes, Error> {
|
||||
let ports = ctx
|
||||
.db
|
||||
.mutate(|db| {
|
||||
if let Some(acme) = &acme {
|
||||
if !db
|
||||
@@ -195,21 +206,62 @@ pub async fn add_public_domain<Kind: HostApiKind>(
|
||||
|
||||
Kind::host_for(&inheritance, db)?
|
||||
.as_public_domains_mut()
|
||||
.insert(&fqdn, &PublicDomainConfig { acme, gateway })?;
|
||||
.insert(
|
||||
&fqdn,
|
||||
&PublicDomainConfig {
|
||||
acme,
|
||||
gateway: gateway.clone(),
|
||||
},
|
||||
)?;
|
||||
handle_duplicates(db)?;
|
||||
let hostname = ServerHostname::load(db.as_public().as_server_info())?;
|
||||
let gateways = db.as_public().as_server_info().as_network().as_gateways().de()?;
|
||||
let ports = db.as_private().as_available_ports().de()?;
|
||||
Kind::host_for(&inheritance, db)?.update_addresses(&hostname, &gateways, &ports)
|
||||
let gateways = db
|
||||
.as_public()
|
||||
.as_server_info()
|
||||
.as_network()
|
||||
.as_gateways()
|
||||
.de()?;
|
||||
let available_ports = db.as_private().as_available_ports().de()?;
|
||||
let host = Kind::host_for(&inheritance, db)?;
|
||||
host.update_addresses(&hostname, &gateways, &available_ports)?;
|
||||
let bindings = host.as_bindings().de()?;
|
||||
let ports: BTreeSet<u16> = bindings
|
||||
.values()
|
||||
.flat_map(|b| &b.addresses.available)
|
||||
.filter(|a| a.public && a.hostname == fqdn)
|
||||
.filter_map(|a| a.port)
|
||||
.collect();
|
||||
Ok(ports)
|
||||
})
|
||||
.await
|
||||
.result?;
|
||||
|
||||
tokio::task::spawn_blocking(|| {
|
||||
crate::net::dns::query_dns(ctx, crate::net::dns::QueryDnsParams { fqdn })
|
||||
let ctx2 = ctx.clone();
|
||||
let fqdn2 = fqdn.clone();
|
||||
|
||||
let (dns_result, port_results) = tokio::join!(
|
||||
async {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
crate::net::dns::query_dns(ctx2, crate::net::dns::QueryDnsParams { fqdn: fqdn2 })
|
||||
})
|
||||
.await
|
||||
.with_kind(ErrorKind::Unknown)?
|
||||
},
|
||||
futures::future::join_all(ports.into_iter().map(|port| {
|
||||
check_port(
|
||||
ctx.clone(),
|
||||
CheckPortParams {
|
||||
port,
|
||||
gateway: gateway.clone(),
|
||||
},
|
||||
)
|
||||
}))
|
||||
);
|
||||
|
||||
Ok(AddPublicDomainRes {
|
||||
dns: dns_result?,
|
||||
port: port_results.into_iter().collect::<Result<Vec<_>, _>>()?,
|
||||
})
|
||||
.await
|
||||
.with_kind(ErrorKind::Unknown)?
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Parser, TS)]
|
||||
@@ -257,13 +309,13 @@ pub async fn add_private_domain<Kind: HostApiKind>(
|
||||
ctx: RpcContext,
|
||||
AddPrivateDomainParams { fqdn, gateway }: AddPrivateDomainParams,
|
||||
inheritance: Kind::Inheritance,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<bool, Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
Kind::host_for(&inheritance, db)?
|
||||
.as_private_domains_mut()
|
||||
.upsert(&fqdn, || Ok(BTreeSet::new()))?
|
||||
.mutate(|d| Ok(d.insert(gateway)))?;
|
||||
.mutate(|d| Ok(d.insert(gateway.clone())))?;
|
||||
handle_duplicates(db)?;
|
||||
let hostname = ServerHostname::load(db.as_public().as_server_info())?;
|
||||
let gateways = db
|
||||
@@ -278,7 +330,7 @@ pub async fn add_private_domain<Kind: HostApiKind>(
|
||||
.await
|
||||
.result?;
|
||||
|
||||
Ok(())
|
||||
check_dns(ctx, CheckDnsParams { gateway }).await
|
||||
}
|
||||
|
||||
pub async fn remove_private_domain<Kind: HostApiKind>(
|
||||
|
||||
Reference in New Issue
Block a user