transip_execute/
lib.rs

1use std::{mem::size_of, time::Duration};
2
3use serde::{Serialize, Serializer};
4pub use transip::configuration_from_environment;
5use transip::Configuration;
6pub use transip::Error;
7use transip_command::{
8    DnsCommand, DomainCommand, EmailBoxCommand, EmailForwardCommand, InvoiceCommand, OnError,
9    ProductCommand, VpsCommand,
10};
11
12// reexport TransipCommand
13pub use transip_command::{ErrorKind, SubCommand, TransipCommand};
14
15pub struct Client {
16    inner: transip::Client,
17    onerror: transip_command::OnError,
18}
19
20impl Client {
21    pub fn exit_on_error(&self) -> bool {
22        self.onerror == OnError::Exit
23    }
24}
25
26trait Report {
27    fn report(self, s: impl Serializer) -> Result<(), transip::Error>;
28}
29
30impl<T: Serialize> Report for Result<T, transip::Error> {
31    fn report(self, s: impl Serializer) -> Result<(), transip::Error> {
32        self.map(|result| {
33            if size_of::<T>() > 0 {
34                result.serialize(s).unwrap();
35            }
36        })
37    }
38}
39
40impl TryFrom<Box<dyn Configuration>> for Client {
41    type Error = transip::Error;
42
43    fn try_from(configuration: Box<dyn Configuration>) -> Result<Self, Self::Error> {
44        transip::Client::try_from(configuration).map(|client| Client {
45            inner: client,
46            onerror: OnError::Print,
47        })
48    }
49}
50
51impl Client {
52    fn execute_dns(
53        &mut self,
54        command: &DnsCommand,
55        s: impl Serializer,
56    ) -> Result<(), transip::Error> {
57        use transip::api::dns::{DnsApi, DnsEntry};
58        match command {
59            DnsCommand::AcmeValidationDelete { domain } => self
60                .inner
61                .dns_entry_delete_all(domain, DnsEntry::is_acme_challenge)
62                .report(s),
63            DnsCommand::List { domain } => self.inner.dns_entry_list(domain).report(s),
64            DnsCommand::Delete(dns_entry) => {
65                let entry = DnsEntry {
66                    name: dns_entry.name.clone(),
67                    expire: dns_entry.ttl,
68                    entry_type: format!("{:?}", dns_entry.r#type),
69                    content: dns_entry.content.clone(),
70                };
71                self.inner
72                    .dns_entry_delete(&dns_entry.domain, entry)
73                    .report(s)
74            }
75            DnsCommand::Insert(dns_entry) => {
76                let entry = DnsEntry {
77                    name: dns_entry.name.clone(),
78                    expire: dns_entry.ttl,
79                    entry_type: format!("{:?}", dns_entry.r#type),
80                    content: dns_entry.content.clone(),
81                };
82                self.inner
83                    .dns_entry_insert(&dns_entry.domain, entry)
84                    .report(s)
85            }
86            DnsCommand::AcmeValidationSet { domain, challenge } => self
87                .inner
88                .dns_entry_delete_all(domain, DnsEntry::is_acme_challenge)
89                .and_then(|_| {
90                    self.inner
91                        .dns_entry_insert(domain, DnsEntry::new_acme_challenge(60, challenge))
92                })
93                .report(s),
94            #[cfg(feature = "propagation")]
95            DnsCommand::AcmeValidationCheck { domain, challenge } => {
96                acme_validation_propagation::wait(domain, challenge)
97                    .map_err(|_| Error::AcmeChallege)
98            }
99        }
100    }
101
102    fn execute_domain(
103        &mut self,
104        command: &DomainCommand,
105        s: impl Serializer,
106    ) -> Result<(), transip::Error> {
107        use transip::api::domain::DomainApi;
108        match command {
109            DomainCommand::Item { domain } => self.inner.domain_item(domain).report(s),
110            DomainCommand::List => self.inner.domain_list().report(s),
111        }
112    }
113
114    fn execute_email_box(
115        &mut self,
116        command: &EmailBoxCommand,
117        s: impl Serializer,
118    ) -> Result<(), transip::Error> {
119        use transip::api::email::EmailApi;
120        match command {
121            EmailBoxCommand::Item { domain, id } => self.inner.mailbox_item(domain, id).report(s),
122            EmailBoxCommand::List { domain } => self.inner.mailbox_list(domain).report(s),
123            _ => Ok(()),
124        }
125    }
126
127    fn execute_email_forward(
128        &mut self,
129        command: &EmailForwardCommand,
130        s: impl Serializer,
131    ) -> Result<(), transip::Error> {
132        use transip::api::email::EmailApi;
133        match command {
134            EmailForwardCommand::Item { domain, id } => {
135                self.inner.mailforward_item(domain, id).report(s)
136            }
137            EmailForwardCommand::List { domain } => self.inner.mailforward_list(domain).report(s),
138            _ => Ok(()),
139        }
140    }
141
142    fn execute_invoice(
143        &mut self,
144        command: &InvoiceCommand,
145        s: impl Serializer,
146    ) -> Result<(), transip::Error> {
147        use transip::api::account::AccountApi;
148        match command {
149            InvoiceCommand::Item { number } => self.inner.invoice(number).report(s),
150            InvoiceCommand::Pdf { number } => self.inner.invoice_pdf(number).report(s),
151            InvoiceCommand::List => self.inner.invoice_list().report(s),
152        }
153    }
154
155    fn execute_product(
156        &mut self,
157        command: &ProductCommand,
158        s: impl Serializer,
159    ) -> Result<(), transip::Error> {
160        use transip::api::general::GeneralApi;
161        match command {
162            ProductCommand::Elements { name } => self.inner.product_elements(name).report(s),
163            ProductCommand::List => self.inner.products().report(s),
164        }
165    }
166
167    fn execute_vps(
168        &mut self,
169        command: &VpsCommand,
170        s: impl Serializer,
171    ) -> Result<(), transip::Error> {
172        use transip::api::vps::VpsApi;
173        match command {
174            VpsCommand::Item { name } => self.inner.vps(name).report(s),
175            VpsCommand::Lock { name } => self.inner.vps_set_is_locked(name, true).report(s),
176            VpsCommand::Reset { name } => self.inner.vps_reset(name).report(s),
177            VpsCommand::Start { name } => self.inner.vps_start(name).report(s),
178            VpsCommand::Stop { name } => self.inner.vps_stop(name).report(s),
179            VpsCommand::Unlock { name } => self.inner.vps_set_is_locked(name, false).report(s),
180            VpsCommand::List => self.inner.vps_list().report(s),
181        }
182    }
183
184    pub fn execute(
185        &mut self,
186        command: &SubCommand,
187        s: impl Serializer,
188    ) -> Result<(), transip::Error> {
189        use transip::api::general::GeneralApi;
190        match command {
191            SubCommand::AvailibilityZones => self.inner.availability_zones().report(s),
192            SubCommand::Comment { text: _ } => Ok(()),
193            SubCommand::Dns(command) => self.execute_dns(command, s),
194            SubCommand::Domain(command) => self.execute_domain(command, s),
195            SubCommand::EmailBox(command) => self.execute_email_box(command, s),
196            SubCommand::EmailForward(command) => self.execute_email_forward(command, s),
197            SubCommand::Invoice(command) => self.execute_invoice(command, s),
198            SubCommand::Onerror { on_error } => {
199                self.onerror = on_error.clone();
200                Ok(())
201            }
202            SubCommand::Ping => self.inner.api_test().report(s),
203            SubCommand::Product(command) => self.execute_product(command, s),
204            SubCommand::Sleep { number_of_seconds } => {
205                std::thread::sleep(Duration::from_secs(*number_of_seconds));
206                Ok(())
207            }
208            SubCommand::Vps(command) => self.execute_vps(command, s),
209            // _ => Ok(()),
210        }
211    }
212}