1use std::{mem::size_of, time::Duration};
2
3use serde::{Serialize, Serializer};
4pub use transip::configuration_from_environment;
5use transip::{Configuration, api::email::MailForwardInsert};
6pub use transip::{Error, Result};
7use transip_command::{
8 DnsCommand, DomainCommand, EmailBoxCommand, EmailForwardCommand, InvoiceCommand, OnError,
9 ProductCommand, VpsCommand,
10};
11
12pub 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<()>;
28}
29
30impl<T: Serialize> Report for Result<T> {
31 fn report(self, s: impl Serializer) -> Result<()> {
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> {
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(&mut self, command: &DnsCommand, s: impl Serializer) -> Result<()> {
53 use transip::api::dns::{DnsApi, DnsEntry};
54 match command {
55 DnsCommand::AcmeValidationDelete { domain } => self
56 .inner
57 .dns_entry_delete_all(domain, DnsEntry::is_acme_challenge)
58 .report(s),
59 DnsCommand::List { domain } => self.inner.dns_entry_list(domain).report(s),
60 DnsCommand::Delete(dns_entry) => {
61 let entry = DnsEntry {
62 name: dns_entry.name.clone(),
63 expire: dns_entry.ttl,
64 entry_type: format!("{:?}", dns_entry.r#type),
65 content: dns_entry.content.clone(),
66 };
67 self.inner
68 .dns_entry_delete(&dns_entry.domain, entry)
69 .report(s)
70 }
71 DnsCommand::Insert(dns_entry) => {
72 let entry = DnsEntry {
73 name: dns_entry.name.clone(),
74 expire: dns_entry.ttl,
75 entry_type: format!("{:?}", dns_entry.r#type),
76 content: dns_entry.content.clone(),
77 };
78 self.inner
79 .dns_entry_insert(&dns_entry.domain, entry)
80 .report(s)
81 }
82 DnsCommand::AcmeValidationSet { domain, challenge } => self
83 .inner
84 .dns_entry_delete_all(domain, DnsEntry::is_acme_challenge)
85 .and_then(|_| {
86 self.inner
87 .dns_entry_insert(domain, DnsEntry::new_acme_challenge(60, challenge))
88 })
89 .report(s),
90 #[cfg(feature = "propagation")]
91 DnsCommand::AcmeValidationCheck { domain, challenge } => {
92 acme_validation_propagation::wait_sync(domain.clone(), challenge.clone())
93 .map_err(|_| Error::AcmeChallege)
94 }
95 }
96 }
97
98 fn execute_domain(&mut self, command: &DomainCommand, s: impl Serializer) -> Result<()> {
99 use transip::api::domain::DomainApi;
100 match command {
101 DomainCommand::Item { domain } => self.inner.domain_item(domain).report(s),
102 DomainCommand::List => self.inner.domain_list().report(s),
103 }
104 }
105
106 fn execute_email_box(&mut self, command: &EmailBoxCommand, s: impl Serializer) -> Result<()> {
107 use transip::api::email::EmailApi;
108 match command {
109 EmailBoxCommand::Item { domain, id } => self.inner.mailbox_item(domain, id).report(s),
110 EmailBoxCommand::List { domain } => self.inner.mailbox_list(domain).report(s),
111 EmailBoxCommand::Delete { domain, id } => self.inner.mailbox_delete(domain, id),
112 EmailBoxCommand::Insert {
113 domain,
114 username,
115 password,
116 mb_size,
117 } => {
118 let mailbox = transip::api::email::MailboxInsert {
119 local_part: username.clone(),
120 max_disk_usage: *mb_size,
121 password: password.clone(),
122 };
123 self.inner.mailbox_insert(domain, mailbox)
124 }
125 }
126 }
127
128 fn execute_email_forward(
129 &mut self,
130 command: &EmailForwardCommand,
131 s: impl Serializer,
132 ) -> Result<()> {
133 use transip::api::email::EmailApi;
134 match command {
135 EmailForwardCommand::Item { domain, id } => {
136 self.inner.mailforward_item(domain, id).report(s)
137 }
138 EmailForwardCommand::List { domain } => self.inner.mailforward_list(domain).report(s),
139 EmailForwardCommand::Insert {
140 domain,
141 local_part,
142 forward_to,
143 } => {
144 let mail_forward = MailForwardInsert {
145 local_part: local_part.clone(),
146 forward_to: forward_to.clone(),
147 };
148 self.inner.mailforward_insert(domain, mail_forward)
149 }
150 EmailForwardCommand::Delete { domain, id } => self.inner.mailforward_delete(domain, id),
151 }
152 }
153
154 fn execute_invoice(&mut self, command: &InvoiceCommand, s: impl Serializer) -> Result<()> {
155 use transip::api::account::AccountApi;
156 match command {
157 InvoiceCommand::Item { number } => self.inner.invoice(number).report(s),
158 InvoiceCommand::Pdf { number } => self.inner.invoice_pdf(number).report(s),
159 InvoiceCommand::List => self.inner.invoice_list().report(s),
160 }
161 }
162
163 fn execute_product(&mut self, command: &ProductCommand, s: impl Serializer) -> Result<()> {
164 use transip::api::general::GeneralApi;
165 match command {
166 ProductCommand::Elements { name } => self.inner.product_elements(name).report(s),
167 ProductCommand::List => self.inner.products().report(s),
168 }
169 }
170
171 fn execute_vps(&mut self, command: &VpsCommand, s: impl Serializer) -> Result<()> {
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(&mut self, command: &SubCommand, s: impl Serializer) -> Result<()> {
185 use transip::api::general::GeneralApi;
186 match command {
187 SubCommand::AvailibilityZones => self.inner.availability_zones().report(s),
188 SubCommand::Comment { text: _ } => Ok(()),
189 SubCommand::Dns(command) => self.execute_dns(command, s),
190 SubCommand::Domain(command) => self.execute_domain(command, s),
191 SubCommand::EmailBox(command) => self.execute_email_box(command, s),
192 SubCommand::EmailForward(command) => self.execute_email_forward(command, s),
193 SubCommand::Invoice(command) => self.execute_invoice(command, s),
194 SubCommand::Onerror { on_error } => {
195 self.onerror = on_error.clone();
196 Ok(())
197 }
198 SubCommand::Ping => self.inner.api_test().report(s),
199 SubCommand::Product(command) => self.execute_product(command, s),
200 SubCommand::Sleep { number_of_seconds } => {
201 std::thread::sleep(Duration::from_secs(*number_of_seconds));
202 Ok(())
203 }
204 SubCommand::Vps(command) => self.execute_vps(command, s),
205 }
207 }
208}