use super::models::*;
use crate::error::AppError;
use lmrc_hetzner::{HetznerClient, HetznerConfig};
pub struct HetznerService {
client: HetznerClient,
}
impl HetznerService {
pub fn new(api_token: String) -> Result<Self, AppError> {
let config = HetznerConfig::new(api_token);
let client = HetznerClient::new(config);
Ok(Self { client })
}
pub async fn list_servers(&self) -> Result<ServersListResponse, AppError> {
let servers = self.client
.list_servers()
.await
.map_err(|e| AppError::External(format!("Hetzner API error: {}", e)))?;
let server_responses: Vec<ServerResponse> = servers
.iter()
.map(|s| ServerResponse {
id: s.id,
name: s.name.clone(),
status: s.status.clone(),
server_type: s.server_type.name.clone(),
public_ip: s.public_net.ipv4.as_ref().map(|ip| ip.ip.clone()),
private_ip: s.private_net.first().map(|net| net.ip.clone()),
created_at: s.created,
datacenter: s.datacenter.name.clone(),
})
.collect();
Ok(ServersListResponse {
total: server_responses.len(),
servers: server_responses,
})
}
pub async fn list_networks(&self) -> Result<NetworksListResponse, AppError> {
let networks = self.client
.list_networks()
.await
.map_err(|e| AppError::External(format!("Hetzner API error: {}", e)))?;
let network_responses: Vec<NetworkResponse> = networks
.iter()
.map(|n| NetworkResponse {
id: n.id,
name: n.name.clone(),
ip_range: n.ip_range.clone(),
servers: n.servers.clone(),
subnets: n.subnets.iter().map(|s| SubnetResponse {
ip_range: s.ip_range.clone(),
network_zone: s.network_zone.clone(),
gateway: s.gateway.clone(),
}).collect(),
created_at: n.created,
})
.collect();
Ok(NetworksListResponse {
total: network_responses.len(),
networks: network_responses,
})
}
pub async fn list_load_balancers(&self) -> Result<LoadBalancersListResponse, AppError> {
let load_balancers = self.client
.list_load_balancers()
.await
.map_err(|e| AppError::External(format!("Hetzner API error: {}", e)))?;
let lb_responses: Vec<LoadBalancerResponse> = load_balancers
.iter()
.map(|lb| LoadBalancerResponse {
id: lb.id,
name: lb.name.clone(),
public_ip: lb.public_net.ipv4.ip.clone(),
algorithm: lb.algorithm.clone(),
targets: vec![], health_status: "unknown".to_string(),
created_at: lb.created,
})
.collect();
Ok(LoadBalancersListResponse {
total: lb_responses.len(),
load_balancers: lb_responses,
})
}
pub async fn list_firewalls(&self) -> Result<FirewallsListResponse, AppError> {
let firewalls = self.client
.list_firewalls()
.await
.map_err(|e| AppError::External(format!("Hetzner API error: {}", e)))?;
let firewall_responses: Vec<FirewallResponse> = firewalls
.iter()
.map(|fw| FirewallResponse {
id: fw.id,
name: fw.name.clone(),
rules_count: fw.rules.len(),
applied_to: fw.applied_to.iter().map(|a| FirewallApplicationResponse {
server_id: a.server,
server_name: None, }).collect(),
created_at: fw.created,
})
.collect();
Ok(FirewallsListResponse {
total: firewall_responses.len(),
firewalls: firewall_responses,
})
}
}