purple_ssh/providers/
mod.rs1pub mod config;
2mod digitalocean;
3mod hetzner;
4mod linode;
5pub mod sync;
6mod vultr;
7
8use thiserror::Error;
9
10#[derive(Debug, Clone)]
12#[allow(dead_code)]
13pub struct ProviderHost {
14 pub server_id: String,
16 pub name: String,
18 pub ip: String,
20 pub tags: Vec<String>,
22}
23
24#[derive(Debug, Error)]
26pub enum ProviderError {
27 #[error("HTTP error: {0}")]
28 Http(String),
29 #[error("Failed to parse response: {0}")]
30 Parse(String),
31 #[error("Authentication failed. Check your API token.")]
32 AuthFailed,
33 #[error("Rate limited. Try again in a moment.")]
34 RateLimited,
35}
36
37pub trait Provider {
39 fn name(&self) -> &str;
41 fn short_label(&self) -> &str;
43 fn fetch_hosts(&self, token: &str) -> Result<Vec<ProviderHost>, ProviderError>;
45}
46
47pub const PROVIDER_NAMES: &[&str] = &["digitalocean", "vultr", "linode", "hetzner"];
49
50pub fn get_provider(name: &str) -> Option<Box<dyn Provider>> {
52 match name {
53 "digitalocean" => Some(Box::new(digitalocean::DigitalOcean)),
54 "vultr" => Some(Box::new(vultr::Vultr)),
55 "linode" => Some(Box::new(linode::Linode)),
56 "hetzner" => Some(Box::new(hetzner::Hetzner)),
57 _ => None,
58 }
59}
60
61fn map_ureq_error(err: ureq::Error) -> ProviderError {
63 match err {
64 ureq::Error::Status(401, _) | ureq::Error::Status(403, _) => ProviderError::AuthFailed,
65 ureq::Error::Status(429, _) => ProviderError::RateLimited,
66 ureq::Error::Status(code, _) => ProviderError::Http(format!("HTTP {}", code)),
67 ureq::Error::Transport(t) => ProviderError::Http(t.to_string()),
68 }
69}