use prettytable::{Table, row}; use rhai::{Array, CustomType, TypeBuilder}; use serde::{Deserialize, Deserializer}; use serde_json::Value; use std::fmt; #[derive(Debug, Deserialize, Clone)] pub struct ServerWrapper { pub server: Server, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Server { pub server_ip: Option, pub server_ipv6_net: Option, pub server_number: i32, pub server_name: String, pub product: String, pub dc: String, pub traffic: String, pub status: String, pub cancelled: bool, pub paid_until: String, pub ip: Option>, pub subnet: Option>, pub reset: Option, pub rescue: Option, pub vnc: Option, pub windows: Option, pub plesk: Option, pub cpanel: Option, pub wol: Option, pub hot_swap: Option, pub linked_storagebox: Option, } impl Server { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Server") .with_get("server_ip", |s: &mut Server| { s.server_ip.clone().unwrap_or_default() }) .with_get("server_ipv6_net", |s: &mut Server| { s.server_ipv6_net.clone().unwrap_or_default() }) .with_get("server_number", |s: &mut Server| s.server_number) .with_get("server_name", |s: &mut Server| s.server_name.clone()) .with_get("product", |s: &mut Server| s.product.clone()) .with_get("dc", |s: &mut Server| s.dc.clone()) .with_get("traffic", |s: &mut Server| s.traffic.clone()) .with_get("status", |s: &mut Server| s.status.clone()) .with_get("cancelled", |s: &mut Server| s.cancelled) .with_get("paid_until", |s: &mut Server| s.paid_until.clone()) .with_get("ip", |s: &mut Server| s.ip.clone().unwrap_or_default()) .with_get("subnet", |s: &mut Server| s.subnet.clone()) .with_get("reset", |s: &mut Server| s.reset.clone()) .with_get("rescue", |s: &mut Server| s.rescue.clone()) .with_get("vnc", |s: &mut Server| s.vnc.clone()) .with_get("windows", |s: &mut Server| s.windows.clone()) .with_get("plesk", |s: &mut Server| s.plesk.clone()) .with_get("cpanel", |s: &mut Server| s.cpanel.clone()) .with_get("wol", |s: &mut Server| s.wol.clone()) .with_get("hot_swap", |s: &mut Server| s.hot_swap.clone()) .with_get("linked_storagebox", |s: &mut Server| { s.linked_storagebox.clone() }) // when doing `print(server) in Rhai script, this will execute` .on_print(|s: &mut Server| s.to_string()) // also add the pretty_print function for convience .with_fn("pretty_print", |s: &mut Server| s.to_string()); } } // Server should always be printed as a table, hence implement the Display trait to render the table impl fmt::Display for Server { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Server Name", self.server_name.clone()]); table.add_row(row![ "Server IP", self.server_ip.as_deref().unwrap_or("N/A") ]); table.add_row(row![ "IPv6 Network", self.server_ipv6_net.as_deref().unwrap_or("N/A") ]); table.add_row(row!["Product", self.product.clone()]); table.add_row(row!["Datacenter", self.dc.clone()]); table.add_row(row!["Traffic", self.traffic.clone()]); table.add_row(row!["Status", self.status.clone()]); table.add_row(row!["Cancelled", self.cancelled.to_string()]); table.add_row(row!["Paid Until", self.paid_until.clone()]); table.add_row(row!["IP Addresses", self.ip.as_deref().unwrap_or_default().join(", ")]); table.add_row(row!["Reset", self.reset.unwrap_or(false).to_string()]); table.add_row(row!["VNC", self.vnc.unwrap_or(false).to_string()]); table.add_row(row!["Windows", self.windows.is_some().to_string()]); table.add_row(row!["Plesk", self.plesk.is_some().to_string()]); table.add_row(row!["cPanel", self.cpanel.is_some().to_string()]); table.add_row(row!["WOL", self.wol.unwrap_or(false).to_string()]); table.add_row(row!["Hot Swap", self.hot_swap.unwrap_or(false).to_string()]); table.add_row(row![ "Linked Storagebox", self.linked_storagebox .map_or("N/A".to_string(), |id| id.to_string()) ]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Subnet { pub ip: String, pub mask: String, } impl Subnet { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Subnet") .with_get("ip", |s: &mut Subnet| s.ip.clone()) .with_get("mask", |s: &mut Subnet| s.mask.clone()) .on_print(|s: &mut Subnet| s.to_string()) .with_fn("pretty_print", |s: &mut Subnet| s.to_string()); } } impl fmt::Display for Subnet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IP: {}, Mask: {}", self.ip, self.mask) } } #[derive(Deserialize)] pub struct SshKeyWrapper { pub key: SshKey, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct SshKey { pub name: String, pub fingerprint: String, #[serde(rename = "type")] pub key_type: String, pub size: i32, pub data: String, pub created_at: String, } impl SshKey { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("SshKey") .with_get("name", |s: &mut SshKey| s.name.clone()) .with_get("fingerprint", |s: &mut SshKey| s.fingerprint.clone()) .with_get("key_type", |s: &mut SshKey| s.key_type.clone()) .with_get("size", |s: &mut SshKey| s.size) .with_get("data", |s: &mut SshKey| s.data.clone()) .with_get("created_at", |s: &mut SshKey| s.created_at.clone()) .on_print(|s: &mut SshKey| s.to_string()) .with_fn("pretty_print", |s: &mut SshKey| s.to_string()); } } impl fmt::Display for SshKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Name", "Fingerprint", "Type", "Size", "Created At"]); table.add_row(row![ self.name.clone(), self.fingerprint.clone(), self.key_type.clone(), self.size.to_string(), self.created_at.clone() ]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] pub struct BootWrapper { pub boot: Boot, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Boot { pub rescue: Rescue, pub linux: Linux, pub vnc: Vnc, pub windows: Option, pub plesk: Option, pub cpanel: Option, } impl Boot { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Boot") .with_get("rescue", |b: &mut Boot| b.rescue.clone()) .with_get("linux", |b: &mut Boot| b.linux.clone()) .with_get("vnc", |b: &mut Boot| b.vnc.clone()) .with_get("windows", |b: &mut Boot| b.windows.clone()) .with_get("plesk", |b: &mut Boot| b.plesk.clone()) .with_get("cpanel", |b: &mut Boot| b.cpanel.clone()) .on_print(|b: &mut Boot| b.to_string()) .with_fn("pretty_print", |b: &mut Boot| b.to_string()); } } impl fmt::Display for Boot { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Configuration", "Details"]); table.add_row(row!["Rescue", self.rescue.to_string()]); table.add_row(row!["Linux", self.linux.to_string()]); table.add_row(row!["VNC", self.vnc.to_string()]); if let Some(windows) = &self.windows { table.add_row(row!["Windows", windows.to_string()]); } if let Some(plesk) = &self.plesk { table.add_row(row!["Plesk", plesk.to_string()]); } if let Some(cpanel) = &self.cpanel { table.add_row(row!["cPanel", cpanel.to_string()]); } write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] pub enum Os { Single(String), Multiple(Vec), } impl Os { pub fn to_vec(&self) -> Vec { match self { Os::Single(s) => vec![s.clone()], Os::Multiple(v) => v.clone(), } } } #[derive(Deserialize)] pub struct RescueWrapped { pub rescue: Rescue, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Rescue { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, pub os: Os, pub active: bool, pub password: Option, #[serde(rename = "authorized_key")] pub authorized_keys: Vec, pub host_key: Vec, } impl Rescue { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Rescue") .with_get("server_ip", |r: &mut Rescue| r.server_ip.clone()) .with_get("server_ipv6_net", |r: &mut Rescue| { r.server_ipv6_net.clone() }) .with_get("server_number", |r: &mut Rescue| r.server_number) .with_get("os", |r: &mut Rescue| r.os.to_vec()) .with_get("active", |r: &mut Rescue| r.active) .with_get("password", |r: &mut Rescue| r.password.clone()) .with_get("authorized_keys", |r: &mut Rescue| { r.authorized_keys .iter() .map(|k| rhai::Dynamic::from(k.key.clone())) .collect::() }) .with_get("host_key", |r: &mut Rescue| r.host_key.clone()) .on_print(|r: &mut Rescue| r.to_string()) .with_fn("pretty_print", |r: &mut Rescue| r.to_string()); } } impl fmt::Display for Rescue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["Server IP", self.server_ip]); table.add_row(row!["Server IPv6 Net", self.server_ipv6_net]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["OS", self.os.to_vec().join(", ")]); table.add_row(row!["Active", self.active.to_string()]); table.add_row(row!["Password", self.password.as_deref().unwrap_or("N/A")]); let authorized_keys: Vec = self .authorized_keys .iter() .filter_map(|key| key.key.fingerprint.clone()) .collect(); table.add_row(row!["Authorized Keys", authorized_keys.join("\n")]); let host_keys: Vec = self .host_key .iter() .filter_map(|key| key.fingerprint.clone()) .collect(); table.add_row(row!["Host Keys", host_keys.join("\n")]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Linux { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, pub active: bool, pub password: Option, #[serde(rename = "authorized_key")] pub authorized_keys: Vec, pub host_key: Vec, } impl Linux { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Linux") .with_get("server_ip", |l: &mut Linux| l.server_ip.clone()) .with_get("server_ipv6_net", |l: &mut Linux| l.server_ipv6_net.clone()) .with_get("server_number", |l: &mut Linux| l.server_number) .with_get("dist", |l: &mut Linux| l.dist.clone()) .with_get("lang", |l: &mut Linux| l.lang.clone()) .with_get("active", |l: &mut Linux| l.active) .with_get("password", |l: &mut Linux| l.password.clone()) .with_get("authorized_keys", |l: &mut Linux| { l.authorized_keys .iter() .map(|k| rhai::Dynamic::from(k.key.clone())) .collect::() }) .with_get("host_key", |l: &mut Linux| l.host_key.clone()) .on_print(|l: &mut Linux| l.to_string()) .with_fn("pretty_print", |l: &mut Linux| l.to_string()); } } impl fmt::Display for Linux { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["Server IP", self.server_ip]); table.add_row(row!["Server IPv6 Net", self.server_ipv6_net]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Distribution", self.dist.join(", ")]); table.add_row(row!["Language", self.lang.join(", ")]); table.add_row(row!["Active", self.active.to_string()]); table.add_row(row!["Password", self.password.as_deref().unwrap_or("N/A")]); let authorized_keys: Vec = self .authorized_keys .iter() .filter_map(|key| key.key.fingerprint.clone()) .collect(); table.add_row(row!["Authorized Keys", authorized_keys.join("\n")]); let host_keys: Vec = self .host_key .iter() .filter_map(|key| key.fingerprint.clone()) .collect(); table.add_row(row!["Host Keys", host_keys.join("\n")]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Vnc { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, pub active: bool, pub password: Option, } impl Vnc { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Vnc") .with_get("server_ip", |v: &mut Vnc| v.server_ip.clone()) .with_get("server_ipv6_net", |v: &mut Vnc| v.server_ipv6_net.clone()) .with_get("server_number", |v: &mut Vnc| v.server_number) .with_get("dist", |v: &mut Vnc| v.dist.clone()) .with_get("lang", |v: &mut Vnc| v.lang.clone()) .with_get("active", |v: &mut Vnc| v.active) .with_get("password", |v: &mut Vnc| v.password.clone()) .on_print(|v: &mut Vnc| v.to_string()) .with_fn("pretty_print", |v: &mut Vnc| v.to_string()); } } impl fmt::Display for Vnc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Dist: {}, Lang: {}, Active: {}", self.dist.join(", "), self.lang.join(", "), self.active ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Windows { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, #[serde(deserialize_with = "option_string_or_seq_string")] pub dist: Option>, #[serde(deserialize_with = "option_string_or_seq_string")] pub lang: Option>, pub active: bool, pub password: Option, } impl Windows { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Windows") .with_get("server_ip", |w: &mut Windows| w.server_ip.clone()) .with_get("server_ipv6_net", |w: &mut Windows| { w.server_ipv6_net.clone() }) .with_get("server_number", |w: &mut Windows| w.server_number) .with_get("dist", |w: &mut Windows| w.dist.clone()) .with_get("lang", |w: &mut Windows| w.lang.clone()) .with_get("active", |w: &mut Windows| w.active) .with_get("password", |w: &mut Windows| w.password.clone()) .on_print(|w: &mut Windows| w.to_string()) .with_fn("pretty_print", |w: &mut Windows| w.to_string()); } } impl fmt::Display for Windows { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Dist: {}, Lang: {}, Active: {}", self.dist.as_deref().unwrap_or_default().join(", "), self.lang.as_deref().unwrap_or_default().join(", "), self.active ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Plesk { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, pub active: bool, pub password: Option, pub hostname: Option, } impl Plesk { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Plesk") .with_get("server_ip", |p: &mut Plesk| p.server_ip.clone()) .with_get("server_ipv6_net", |p: &mut Plesk| p.server_ipv6_net.clone()) .with_get("server_number", |p: &mut Plesk| p.server_number) .with_get("dist", |p: &mut Plesk| p.dist.clone()) .with_get("lang", |p: &mut Plesk| p.lang.clone()) .with_get("active", |p: &mut Plesk| p.active) .with_get("password", |p: &mut Plesk| p.password.clone()) .with_get("hostname", |p: &mut Plesk| p.hostname.clone()) .on_print(|p: &mut Plesk| p.to_string()) .with_fn("pretty_print", |p: &mut Plesk| p.to_string()); } } impl fmt::Display for Plesk { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Dist: {}, Lang: {}, Active: {}, Hostname: {}", self.dist.join(", "), self.lang.join(", "), self.active, self.hostname.as_deref().unwrap_or("N/A") ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Cpanel { pub server_ip: String, pub server_ipv6_net: String, pub server_number: i32, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, pub active: bool, pub password: Option, pub hostname: Option, } impl Cpanel { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Cpanel") .with_get("server_ip", |c: &mut Cpanel| c.server_ip.clone()) .with_get("server_ipv6_net", |c: &mut Cpanel| { c.server_ipv6_net.clone() }) .with_get("server_number", |c: &mut Cpanel| c.server_number) .with_get("dist", |c: &mut Cpanel| c.dist.clone()) .with_get("lang", |c: &mut Cpanel| c.lang.clone()) .with_get("active", |c: &mut Cpanel| c.active) .with_get("password", |c: &mut Cpanel| c.password.clone()) .with_get("hostname", |c: &mut Cpanel| c.hostname.clone()) .on_print(|c: &mut Cpanel| c.to_string()) .with_fn("pretty_print", |c: &mut Cpanel| c.to_string()); } } impl fmt::Display for Cpanel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Dist: {}, Lang: {}, Active: {}, Hostname: {}", self.dist.join(", "), self.lang.join(", "), self.active, self.hostname.as_deref().unwrap_or("N/A") ) } } #[derive(Debug, Deserialize, Clone)] pub struct CancellationWrapper { pub cancellation: Cancellation, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Cancellation { pub server_ip: String, pub server_ipv6_net: Option, pub server_number: i32, pub server_name: String, pub earliest_cancellation_date: String, pub cancelled: bool, pub reservation_possible: bool, pub reserved: bool, pub cancellation_date: Option, pub cancellation_reason: Vec, } impl Cancellation { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Cancellation") .with_get("server_ip", |c: &mut Cancellation| c.server_ip.clone()) .with_get("server_ipv6_net", |c: &mut Cancellation| { c.server_ipv6_net.clone() }) .with_get("server_number", |c: &mut Cancellation| c.server_number) .with_get("server_name", |c: &mut Cancellation| c.server_name.clone()) .with_get("earliest_cancellation_date", |c: &mut Cancellation| { c.earliest_cancellation_date.clone() }) .with_get("cancelled", |c: &mut Cancellation| c.cancelled) .with_get("reservation_possible", |c: &mut Cancellation| { c.reservation_possible }) .with_get("reserved", |c: &mut Cancellation| c.reserved) .with_get("cancellation_date", |c: &mut Cancellation| { c.cancellation_date.clone() }) .with_get("cancellation_reason", |c: &mut Cancellation| { c.cancellation_reason.clone() }) .on_print(|c: &mut Cancellation| c.to_string()) .with_fn("pretty_print", |c: &mut Cancellation| c.to_string()); } } impl fmt::Display for Cancellation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["Server IP", self.server_ip.clone()]); table.add_row(row![ "Server IPv6 Net", self.server_ipv6_net.as_deref().unwrap_or("N/A").to_string() ]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Server Name", self.server_name.clone()]); table.add_row(row![ "Earliest Cancellation Date", self.earliest_cancellation_date.clone() ]); table.add_row(row!["Cancelled", self.cancelled.to_string()]); table.add_row(row![ "Reservation Possible", self.reservation_possible.to_string() ]); table.add_row(row!["Reserved", self.reserved.to_string()]); table.add_row(row![ "Cancellation Date", self.cancellation_date .as_deref() .unwrap_or("N/A") .to_string() ]); table.add_row(row![ "Cancellation Reason", self.cancellation_reason.join(", ") ]); write!(f, "{}", table) } } #[derive(Debug, Deserialize)] pub struct ApiError { #[allow(dead_code)] pub status: u16, #[allow(dead_code)] pub message: String, } impl From for ApiError { fn from(value: reqwest::blocking::Response) -> Self { ApiError { status: value.status().into(), message: value .text() .unwrap_or("The API call returned an error.".to_string()), } } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Price { pub net: String, pub gross: String, pub hourly_net: String, pub hourly_gross: String, } impl Price { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Price") .with_get("net", |p: &mut Price| p.net.clone()) .with_get("gross", |p: &mut Price| p.gross.clone()) .with_get("hourly_net", |p: &mut Price| p.hourly_net.clone()) .with_get("hourly_gross", |p: &mut Price| p.hourly_gross.clone()) .on_print(|p: &mut Price| p.to_string()) .with_fn("pretty_print", |p: &mut Price| p.to_string()); } } impl fmt::Display for Price { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Net: {}, Gross: {}, Hourly Net: {}, Hourly Gross: {}", self.net, self.gross, self.hourly_net, self.hourly_gross ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct PriceSetup { pub net: String, pub gross: String, } impl PriceSetup { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("PriceSetup") .with_get("net", |p: &mut PriceSetup| p.net.clone()) .with_get("gross", |p: &mut PriceSetup| p.gross.clone()) .on_print(|p: &mut PriceSetup| p.to_string()) .with_fn("pretty_print", |p: &mut PriceSetup| p.to_string()); } } impl fmt::Display for PriceSetup { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Net: {}, Gross: {}", self.net, self.gross) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct ProductPrice { pub location: String, pub price: Price, pub price_setup: PriceSetup, } impl ProductPrice { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("ProductPrice") .with_get("location", |p: &mut ProductPrice| p.location.clone()) .with_get("price", |p: &mut ProductPrice| p.price.clone()) .with_get("price_setup", |p: &mut ProductPrice| p.price_setup.clone()) .on_print(|p: &mut ProductPrice| p.to_string()) .with_fn("pretty_print", |p: &mut ProductPrice| p.to_string()); } } impl fmt::Display for ProductPrice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Location: {}, Price: ({}), Price Setup: ({})", self.location, self.price, self.price_setup ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct OrderableAddon { pub id: String, pub name: String, pub min: i32, pub max: i32, pub prices: Vec, } impl OrderableAddon { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("OrderableAddon") .with_get("id", |o: &mut OrderableAddon| o.id.clone()) .with_get("name", |o: &mut OrderableAddon| o.name.clone()) .with_get("min", |o: &mut OrderableAddon| o.min) .with_get("max", |o: &mut OrderableAddon| o.max) .with_get("prices", |o: &mut OrderableAddon| o.prices.clone()) .on_print(|o: &mut OrderableAddon| o.to_string()) .with_fn("pretty_print", |o: &mut OrderableAddon| o.to_string()); } } impl fmt::Display for OrderableAddon { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.clone()]); table.add_row(row!["Name", self.name.clone()]); table.add_row(row!["Min", self.min.to_string()]); table.add_row(row!["Max", self.max.to_string()]); table.add_row(row!["Prices", format!("{:?}", self.prices)]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] pub struct ServerAddonProductWrapper { pub product: ServerAddonProduct, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct ServerAddonProduct { pub id: String, pub name: String, #[serde(rename = "type")] pub product_type: String, pub price: ProductPrice, } impl ServerAddonProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("ServerAddonProduct") .with_get("id", |p: &mut ServerAddonProduct| p.id.clone()) .with_get("name", |p: &mut ServerAddonProduct| p.name.clone()) .with_get("product_type", |p: &mut ServerAddonProduct| { p.product_type.clone() }) .with_get("price", |p: &mut ServerAddonProduct| p.price.clone()) .on_print(|p: &mut ServerAddonProduct| p.to_string()) .with_fn("pretty_print", |p: &mut ServerAddonProduct| p.to_string()); } } impl fmt::Display for ServerAddonProduct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.clone()]); table.add_row(row!["Name", self.name.clone()]); table.add_row(row!["Type", self.product_type.clone()]); table.add_row(row!["Price", self.price.to_string()]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] pub struct ServerAddonTransactionWrapper { pub transaction: ServerAddonTransaction, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct ServerAddonTransaction { pub id: String, pub date: String, pub status: String, pub server_number: i32, pub product: ServerAddonTransactionProduct, pub resources: Vec, } impl ServerAddonTransaction { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("ServerAddonTransaction") .with_get("id", |t: &mut ServerAddonTransaction| t.id.clone()) .with_get("date", |t: &mut ServerAddonTransaction| t.date.clone()) .with_get("status", |t: &mut ServerAddonTransaction| t.status.clone()) .with_get("server_number", |t: &mut ServerAddonTransaction| { t.server_number }) .with_get("product", |t: &mut ServerAddonTransaction| { t.product.clone() }) .with_get("resources", |t: &mut ServerAddonTransaction| { t.resources.clone() }) .on_print(|t: &mut ServerAddonTransaction| t.to_string()) .with_fn("pretty_print", |t: &mut ServerAddonTransaction| { t.to_string() }); } } impl fmt::Display for ServerAddonTransaction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.clone()]); table.add_row(row!["Date", self.date.clone()]); table.add_row(row!["Status", self.status.clone()]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Product ID", self.product.id.clone()]); table.add_row(row!["Product Name", self.product.name.clone()]); table.add_row(row!["Product Price", self.product.price.to_string()]); let mut resources_table = Table::new(); resources_table.add_row(row![b => "Type", "ID"]); for resource in &self.resources { resources_table.add_row(row![resource.resource_type, resource.id]); } table.add_row(row!["Resources", resources_table]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct ServerAddonTransactionProduct { pub id: String, pub name: String, pub price: ProductPrice, } impl ServerAddonTransactionProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("ServerAddonTransactionProduct") .with_get("id", |p: &mut ServerAddonTransactionProduct| p.id.clone()) .with_get("name", |p: &mut ServerAddonTransactionProduct| { p.name.clone() }) .with_get("price", |p: &mut ServerAddonTransactionProduct| { p.price.clone() }) .on_print(|p: &mut ServerAddonTransactionProduct| p.to_string()) .with_fn("pretty_print", |p: &mut ServerAddonTransactionProduct| { p.to_string() }); } } impl fmt::Display for ServerAddonTransactionProduct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "ID: {}, Name: {}, Price: ({})", self.id, self.name, self.price ) } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct ServerAddonResource { #[serde(rename = "type")] pub resource_type: String, pub id: String, } impl ServerAddonResource { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("ServerAddonResource") .with_get("resource_type", |r: &mut ServerAddonResource| { r.resource_type.clone() }) .with_get("id", |r: &mut ServerAddonResource| r.id.clone()) .on_print(|r: &mut ServerAddonResource| r.to_string()) .with_fn("pretty_print", |r: &mut ServerAddonResource| { r.to_string() }); } } impl fmt::Display for ServerAddonResource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Type: {}, ID: {}", self.resource_type, self.id) } } #[derive(Debug, Deserialize, Clone)] pub struct OrderServerProductWrapper { pub product: OrderServerProduct, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct OrderServerProduct { pub id: String, pub name: String, #[serde(deserialize_with = "string_or_seq_string")] pub description: Vec, pub traffic: String, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde( rename = "@deprecated arch", default, deserialize_with = "option_string_or_seq_string" )] #[deprecated(note = "use `dist` instead")] pub arch: Option>, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, #[serde(deserialize_with = "string_or_seq_string")] pub location: Vec, pub prices: Vec, pub orderable_addons: Vec, } impl OrderServerProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("OrderServerProduct") .with_get("id", |o: &mut OrderServerProduct| o.id.clone()) .with_get("name", |o: &mut OrderServerProduct| o.name.clone()) .with_get("description", |o: &mut OrderServerProduct| { o.description.clone() }) .with_get("traffic", |o: &mut OrderServerProduct| o.traffic.clone()) .with_get("dist", |o: &mut OrderServerProduct| o.dist.clone()) .with_get("arch", |o: &mut OrderServerProduct| o.dist.clone()) .with_get("lang", |o: &mut OrderServerProduct| o.lang.clone()) .with_get("location", |o: &mut OrderServerProduct| o.location.clone()) .with_get("prices", |o: &mut OrderServerProduct| o.prices.clone()) .with_get("orderable_addons", |o: &mut OrderServerProduct| { o.orderable_addons.clone() }) .on_print(|o: &mut OrderServerProduct| o.to_string()) .with_fn("pretty_print", |o: &mut OrderServerProduct| o.to_string()); } } impl fmt::Display for OrderServerProduct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.clone()]); table.add_row(row!["Name", self.name.clone()]); table.add_row(row!["Description", self.description.join(", ")]); table.add_row(row!["Traffic", self.traffic.clone()]); table.add_row(row!["Distributions", self.dist.join(", ")]); table.add_row(row![ "Architectures", self.dist.join(", ") ]); table.add_row(row!["Languages", self.lang.join(", ")]); table.add_row(row!["Locations", self.location.join(", ")]); let mut prices_table = Table::new(); prices_table.add_row(row![b => "Location", "Net", "Gross", "Hourly Net", "Hourly Gross", "Setup Net", "Setup Gross"]); for price in &self.prices { prices_table.add_row(row![ price.location, price.price.net, price.price.gross, price.price.hourly_net, price.price.hourly_gross, price.price_setup.net, price.price_setup.gross ]); } table.add_row(row!["Prices", prices_table]); let mut addons_table = Table::new(); addons_table.add_row(row![b => "ID", "Name", "Min", "Max", "Prices"]); for addon in &self.orderable_addons { let mut addon_prices_table = Table::new(); addon_prices_table.add_row(row![b => "Location", "Net", "Gross", "Hourly Net", "Hourly Gross", "Setup Net", "Setup Gross"]); for price in &addon.prices { addon_prices_table.add_row(row![ price.location, price.price.net, price.price.gross, price.price.hourly_net, price.price.hourly_gross, price.price_setup.net, price.price_setup.gross ]); } addons_table.add_row(row![ addon.id, addon.name, addon.min, addon.max, addon_prices_table ]); } table.add_row(row!["Orderable Addons", addons_table]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] pub struct TransactionWrapper { pub transaction: Transaction, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct Transaction { pub id: String, pub date: String, pub status: String, pub server_number: Option, pub server_ip: Option, pub authorized_key: Vec, pub host_key: Vec, pub comment: Option, pub product: TransactionProduct, pub addons: Vec, } #[derive(Debug, Deserialize, Clone)] pub struct AuthorizedKeyWrapper { pub key: AuthorizedKey, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct AuthorizedKey { pub name: Option, pub fingerprint: Option, #[serde(rename = "type")] pub key_type: Option, pub size: Option, } impl From for AuthorizedKey { fn from(key: SshKey) -> Self { Self { name: Some(key.name), fingerprint: Some(key.fingerprint), key_type: Some(key.key_type), size: Some(key.size), } } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct TransactionProduct { pub id: String, pub name: String, pub description: Vec, pub traffic: String, pub dist: String, #[serde(rename = "@deprecated arch")] pub arch: String, pub lang: String, pub location: String, } impl Transaction { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("Transaction") .with_get("id", |t: &mut Transaction| t.id.clone()) .with_get("date", |t: &mut Transaction| t.date.clone()) .with_get("status", |t: &mut Transaction| t.status.clone()) .with_get("server_number", |t: &mut Transaction| t.server_number) .with_get("server_ip", |t: &mut Transaction| t.server_ip.clone()) .with_get("authorized_key", |t: &mut Transaction| { t.authorized_key.clone() }) .with_get("host_key", |t: &mut Transaction| t.host_key.clone()) .with_get("comment", |t: &mut Transaction| t.comment.clone()) .with_get("product", |t: &mut Transaction| t.product.clone()) .with_get("addons", |t: &mut Transaction| t.addons.clone()); } } impl AuthorizedKey { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("AuthorizedKey") .with_get("name", |k: &mut AuthorizedKey| k.name.clone()) .with_get("fingerprint", |k: &mut AuthorizedKey| k.fingerprint.clone()) .with_get("key_type", |k: &mut AuthorizedKey| k.key_type.clone()) .with_get("size", |k: &mut AuthorizedKey| k.size); } } impl TransactionProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("TransactionProduct") .with_get("id", |p: &mut TransactionProduct| p.id.clone()) .with_get("name", |p: &mut TransactionProduct| p.name.clone()) .with_get("description", |p: &mut TransactionProduct| { p.description.clone() }) .with_get("traffic", |p: &mut TransactionProduct| p.traffic.clone()) .with_get("dist", |p: &mut TransactionProduct| p.dist.clone()) .with_get("arch", |p: &mut TransactionProduct| p.arch.clone()) .with_get("lang", |p: &mut TransactionProduct| p.lang.clone()) .with_get("location", |p: &mut TransactionProduct| p.location.clone()); } } #[derive(Debug, Deserialize, Clone)] pub struct HostKeyWrapper { pub key: HostKey, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct HostKey { pub fingerprint: Option, #[serde(rename = "type")] pub key_type: Option, pub size: Option, } #[derive(Debug, Deserialize, Clone)] pub struct RescueKey { pub key: HostKey, } impl HostKey { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("HostKey") .with_get("fingerprint", |k: &mut HostKey| k.fingerprint.clone()) .with_get("key_type", |k: &mut HostKey| k.key_type.clone()) .with_get("size", |k: &mut HostKey| k.size); } } #[derive(Debug, Deserialize, Clone)] pub struct AuctionServerProductWrapper { pub product: AuctionServerProduct, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct AuctionServerProduct { pub id: i32, pub name: String, #[serde(deserialize_with = "string_or_seq_string")] pub description: Vec, pub traffic: String, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, #[serde( rename = "@deprecated arch", default, deserialize_with = "option_string_or_seq_string" )] #[deprecated(note = "use `dist` instead")] pub arch: Option>, #[serde(deserialize_with = "string_or_seq_string")] pub lang: Vec, pub cpu: String, pub cpu_benchmark: i32, pub memory_size: i32, pub hdd_size: i32, pub hdd_text: String, pub hdd_count: i32, pub datacenter: String, pub network_speed: String, pub price: String, pub price_hourly: Option, pub price_setup: String, #[serde(rename = "price_vat")] pub price_with_vat: String, #[serde(rename = "price_hourly_vat")] pub price_hourly_with_vat: Option, #[serde(rename = "price_setup_vat")] pub price_setup_with_vat: String, pub fixed_price: bool, pub next_reduce: i32, pub next_reduce_date: String, pub orderable_addons: Vec, } impl AuctionServerProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("AuctionServerProduct") .with_get("id", |p: &mut AuctionServerProduct| p.id) .with_get("name", |p: &mut AuctionServerProduct| p.name.clone()) .with_get("description", |p: &mut AuctionServerProduct| { p.description.clone() }) .with_get("traffic", |p: &mut AuctionServerProduct| p.traffic.clone()) .with_get("dist", |p: &mut AuctionServerProduct| p.dist.clone()) .with_get("arch", |p: &mut AuctionServerProduct| p.dist.clone()) .with_get("lang", |p: &mut AuctionServerProduct| p.lang.clone()) .with_get("cpu", |p: &mut AuctionServerProduct| p.cpu.clone()) .with_get("cpu_benchmark", |p: &mut AuctionServerProduct| { p.cpu_benchmark }) .with_get("memory_size", |p: &mut AuctionServerProduct| p.memory_size) .with_get("hdd_size", |p: &mut AuctionServerProduct| p.hdd_size) .with_get("hdd_text", |p: &mut AuctionServerProduct| { p.hdd_text.clone() }) .with_get("hdd_count", |p: &mut AuctionServerProduct| p.hdd_count) .with_get("datacenter", |p: &mut AuctionServerProduct| { p.datacenter.clone() }) .with_get("network_speed", |p: &mut AuctionServerProduct| { p.network_speed.clone() }) .with_get("price", |p: &mut AuctionServerProduct| p.price.clone()) .with_get("price_hourly", |p: &mut AuctionServerProduct| { p.price_hourly.clone() }) .with_get("price_setup", |p: &mut AuctionServerProduct| { p.price_setup.clone() }) .with_get("price_with_vat", |p: &mut AuctionServerProduct| { p.price_with_vat.clone() }) .with_get("price_hourly_with_vat", |p: &mut AuctionServerProduct| { p.price_hourly_with_vat.clone() }) .with_get("price_setup_with_vat", |p: &mut AuctionServerProduct| { p.price_setup_with_vat.clone() }) .with_get("fixed_price", |p: &mut AuctionServerProduct| p.fixed_price) .with_get("next_reduce", |p: &mut AuctionServerProduct| p.next_reduce) .with_get("next_reduce_date", |p: &mut AuctionServerProduct| { p.next_reduce_date.clone() }) .with_get("orderable_addons", |p: &mut AuctionServerProduct| { p.orderable_addons.clone() }) .on_print(|p: &mut AuctionServerProduct| p.to_string()) .with_fn("pretty_print", |p: &mut AuctionServerProduct| p.to_string()); } } impl fmt::Display for AuctionServerProduct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.to_string()]); table.add_row(row!["Name", self.name.clone()]); table.add_row(row!["Description", self.description.join(", ")]); table.add_row(row!["Traffic", self.traffic.clone()]); table.add_row(row!["Distributions", self.dist.join(", ")]); table.add_row(row![ "Architectures", self.dist.join(", ") ]); table.add_row(row!["Languages", self.lang.join(", ")]); table.add_row(row!["CPU", self.cpu.clone()]); table.add_row(row!["CPU Benchmark", self.cpu_benchmark.to_string()]); table.add_row(row!["Memory Size (GB)", self.memory_size.to_string()]); table.add_row(row!["HDD Size (GB)", self.hdd_size.to_string()]); table.add_row(row!["HDD Text", self.hdd_text.clone()]); table.add_row(row!["HDD Count", self.hdd_count.to_string()]); table.add_row(row!["Datacenter", self.datacenter.clone()]); table.add_row(row!["Network Speed", self.network_speed.clone()]); table.add_row(row!["Price (Net)", self.price.clone()]); table.add_row(row![ "Price (Hourly Net)", self.price_hourly.as_deref().unwrap_or("N/A").to_string() ]); table.add_row(row!["Price (Setup Net)", self.price_setup.clone()]); table.add_row(row!["Price (VAT)", self.price_with_vat.clone()]); table.add_row(row![ "Price (Hourly VAT)", self.price_hourly_with_vat .as_deref() .unwrap_or("N/A") .to_string() ]); table.add_row(row!["Price (Setup VAT)", self.price_setup_with_vat.clone()]); table.add_row(row!["Fixed Price", self.fixed_price.to_string()]); table.add_row(row!["Next Reduce (seconds)", self.next_reduce.to_string()]); table.add_row(row!["Next Reduce Date", self.next_reduce_date.clone()]); let mut addons_table = Table::new(); addons_table.add_row(row![b => "ID", "Name", "Min", "Max", "Prices"]); for addon in &self.orderable_addons { let mut addon_prices_table = Table::new(); addon_prices_table.add_row(row![b => "Location", "Net", "Gross", "Hourly Net", "Hourly Gross", "Setup Net", "Setup Gross"]); for price in &addon.prices { addon_prices_table.add_row(row![ price.location, price.price.net, price.price.gross, price.price.hourly_net, price.price.hourly_gross, price.price_setup.net, price.price_setup.gross ]); } addons_table.add_row(row![ addon.id, addon.name, addon.min, addon.max, addon_prices_table ]); } table.add_row(row!["Orderable Addons", addons_table]); write!(f, "{}", table) } } #[derive(Debug, Deserialize, Clone)] pub struct AuctionTransactionWrapper { pub transaction: AuctionTransaction, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct AuctionTransaction { pub id: String, pub date: String, pub status: String, pub server_number: Option, pub server_ip: Option, pub authorized_key: Vec, pub host_key: Vec, pub comment: Option, pub product: AuctionTransactionProduct, pub addons: Vec, } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct AuctionTransactionProduct { pub id: i32, pub name: String, pub description: Vec, pub traffic: String, pub dist: String, #[serde(rename = "@deprecated arch")] pub arch: Option, pub lang: String, pub cpu: String, pub cpu_benchmark: i32, pub memory_size: i32, pub hdd_size: i32, pub hdd_text: String, pub hdd_count: i32, pub datacenter: String, pub network_speed: String, pub fixed_price: Option, pub next_reduce: Option, pub next_reduce_date: Option, } impl AuctionTransaction { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("AuctionTransaction") .with_get("id", |t: &mut AuctionTransaction| t.id.clone()) .with_get("date", |t: &mut AuctionTransaction| t.date.clone()) .with_get("status", |t: &mut AuctionTransaction| t.status.clone()) .with_get("server_number", |t: &mut AuctionTransaction| { t.server_number }) .with_get("server_ip", |t: &mut AuctionTransaction| { t.server_ip.clone() }) .with_get("authorized_key", |t: &mut AuctionTransaction| { t.authorized_key.clone() }) .with_get("host_key", |t: &mut AuctionTransaction| t.host_key.clone()) .with_get("comment", |t: &mut AuctionTransaction| t.comment.clone()) .with_get("product", |t: &mut AuctionTransaction| t.product.clone()) .with_get("addons", |t: &mut AuctionTransaction| t.addons.clone()) .on_print(|t: &mut AuctionTransaction| t.to_string()) .with_fn("pretty_print", |t: &mut AuctionTransaction| t.to_string()); } } impl fmt::Display for AuctionTransaction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); table.add_row(row!["Property", "Value"]); table.add_row(row!["ID", self.id.clone()]); table.add_row(row!["Date", self.date.clone()]); table.add_row(row!["Status", self.status.clone()]); table.add_row(row![ "Server Number", self.server_number .map_or("N/A".to_string(), |id| id.to_string()) ]); table.add_row(row![ "Server IP", self.server_ip.as_deref().unwrap_or("N/A").to_string() ]); table.add_row(row![ "Comment", self.comment.as_deref().unwrap_or("N/A").to_string() ]); table.add_row(row!["Product ID", self.product.id.to_string()]); table.add_row(row!["Product Name", self.product.name.clone()]); table.add_row(row![ "Product Description", self.product.description.join(", ") ]); table.add_row(row!["Product Traffic", self.product.traffic.clone()]); table.add_row(row!["Product Distributions", self.product.dist.clone()]); table.add_row(row![ "Product Architectures", &self.product.dist ]); table.add_row(row!["Product Languages", self.product.lang.clone()]); table.add_row(row!["Product CPU", self.product.cpu.clone()]); table.add_row(row![ "Product CPU Benchmark", self.product.cpu_benchmark.to_string() ]); table.add_row(row![ "Product Memory Size (GB)", self.product.memory_size.to_string() ]); table.add_row(row![ "Product HDD Size (GB)", self.product.hdd_size.to_string() ]); table.add_row(row!["Product HDD Text", self.product.hdd_text.clone()]); table.add_row(row![ "Product HDD Count", self.product.hdd_count.to_string() ]); table.add_row(row!["Product Datacenter", self.product.datacenter.clone()]); table.add_row(row![ "Product Network Speed", self.product.network_speed.clone() ]); table.add_row(row![ "Product Fixed Price", self.product.fixed_price.unwrap_or_default().to_string() ]); table.add_row(row![ "Product Next Reduce (seconds)", self.product .next_reduce .map_or("N/A".to_string(), |r| r.to_string()) ]); table.add_row(row![ "Product Next Reduce Date", self.product.next_reduce_date.as_deref().unwrap_or("N/A") ]); table.add_row(row!["Addons", self.addons.join(", ")]); let mut authorized_keys_table = Table::new(); authorized_keys_table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]); for key in &self.authorized_key { authorized_keys_table.add_row(row![ key.key.name.as_deref().unwrap_or("N/A"), key.key.fingerprint.as_deref().unwrap_or("N/A"), key.key.key_type.as_deref().unwrap_or("N/A"), key.key.size.map_or("N/A".to_string(), |s| s.to_string()) ]); } table.add_row(row!["Authorized Keys", authorized_keys_table]); let mut host_keys_table = Table::new(); host_keys_table.add_row(row![b => "Fingerprint", "Type", "Size"]); for key in &self.host_key { host_keys_table.add_row(row![ key.key.fingerprint.as_deref().unwrap_or("N/A"), key.key.key_type.as_deref().unwrap_or("N/A"), key.key.size.map_or("N/A".to_string(), |s| s.to_string()) ]); } table.add_row(row!["Host Keys", host_keys_table]); write!(f, "{}", table) } } impl AuctionTransactionProduct { fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("AuctionTransactionProduct") .with_get("id", |p: &mut AuctionTransactionProduct| p.id) .with_get("name", |p: &mut AuctionTransactionProduct| p.name.clone()) .with_get("description", |p: &mut AuctionTransactionProduct| { p.description.clone() }) .with_get("traffic", |p: &mut AuctionTransactionProduct| { p.traffic.clone() }) .with_get("dist", |p: &mut AuctionTransactionProduct| p.dist.clone()) .with_get("arch", |p: &mut AuctionTransactionProduct| { p.dist.clone() }) .with_get("lang", |p: &mut AuctionTransactionProduct| p.lang.clone()) .with_get("cpu", |p: &mut AuctionTransactionProduct| p.cpu.clone()) .with_get("cpu_benchmark", |p: &mut AuctionTransactionProduct| { p.cpu_benchmark }) .with_get("memory_size", |p: &mut AuctionTransactionProduct| { p.memory_size }) .with_get("hdd_size", |p: &mut AuctionTransactionProduct| p.hdd_size) .with_get("hdd_text", |p: &mut AuctionTransactionProduct| { p.hdd_text.clone() }) .with_get("hdd_count", |p: &mut AuctionTransactionProduct| p.hdd_count) .with_get("datacenter", |p: &mut AuctionTransactionProduct| { p.datacenter.clone() }) .with_get("network_speed", |p: &mut AuctionTransactionProduct| { p.network_speed.clone() }) .with_get("fixed_price", |p: &mut AuctionTransactionProduct| { p.fixed_price.unwrap_or_default() }) .with_get("next_reduce", |p: &mut AuctionTransactionProduct| { p.next_reduce.unwrap_or_default() }) .with_get("next_reduce_date", |p: &mut AuctionTransactionProduct| { p.next_reduce_date.clone().unwrap_or_default() }); } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct OrderServerBuilder { pub product_id: String, pub authorized_keys: Option>, pub dist: Option, pub location: Option, pub lang: Option, pub comment: Option, pub addons: Option>, pub test: Option, } impl OrderServerBuilder { pub fn new(product_id: &str) -> Self { Self { product_id: product_id.to_string(), authorized_keys: None, dist: None, location: None, lang: None, comment: None, addons: None, test: Some(true), } } pub fn with_authorized_keys(mut self, keys: Array) -> Self { let authorized_keys: Vec = if keys.is_empty() { vec![] } else if keys[0].is::() { keys.into_iter() .map(|k| k.cast::().fingerprint) .collect() } else { keys.into_iter().map(|k| k.into_string().unwrap()).collect() }; self.authorized_keys = Some(authorized_keys); self } pub fn with_dist(mut self, dist: &str) -> Self { self.dist = Some(dist.to_string()); self } pub fn with_location(mut self, location: &str) -> Self { self.location = Some(location.to_string()); self } pub fn with_lang(mut self, lang: &str) -> Self { self.lang = Some(lang.to_string()); self } pub fn with_comment(mut self, comment: &str) -> Self { self.comment = Some(comment.to_string()); self } pub fn with_addons(mut self, addons: Array) -> Self { let addon_list: Vec = addons .into_iter() .map(|a| a.into_string().unwrap()) .collect(); self.addons = Some(addon_list); self } pub fn with_test(mut self, test: bool) -> Self { self.test = Some(test); self } fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("OrderServerBuilder") .with_fn("new_server_builder", Self::new) .with_fn("with_authorized_keys", Self::with_authorized_keys) .with_fn("with_dist", Self::with_dist) .with_fn("with_location", Self::with_location) .with_fn("with_lang", Self::with_lang) .with_fn("with_comment", Self::with_comment) .with_fn("with_addons", Self::with_addons) .with_fn("with_test", Self::with_test) .with_get("product_id", |b: &mut OrderServerBuilder| b.product_id.clone()) .with_get("dist", |b: &mut OrderServerBuilder| b.dist.clone()) .with_get("location", |b: &mut OrderServerBuilder| b.location.clone()) .with_get("authorized_keys", |b: &mut OrderServerBuilder| { b.authorized_keys.clone() }) .with_get("addons", |b: &mut OrderServerBuilder| b.addons.clone()) .with_get("test", |b: &mut OrderServerBuilder| b.test.clone()); } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct OrderAuctionServerBuilder { pub product_id: i64, pub authorized_keys: Option>, pub dist: Option, pub lang: Option, pub comment: Option, pub addon: Option>, pub test: Option, } impl OrderAuctionServerBuilder { pub fn new(product_id: i64) -> Self { Self { product_id, authorized_keys: None, dist: None, lang: None, comment: None, addon: None, // by default test is enabled test: Some(true), } } pub fn with_authorized_keys(mut self, keys: Array) -> Self { let authorized_keys: Vec = if keys.is_empty() { vec![] } else if keys[0].is::() { keys.into_iter() .map(|k| k.cast::().fingerprint) .collect() } else { keys.into_iter().map(|k| k.into_string().unwrap()).collect() }; self.authorized_keys = Some(authorized_keys); self } pub fn with_dist(mut self, dist: &str) -> Self { self.dist = Some(dist.to_string()); self } pub fn with_lang(mut self, lang: &str) -> Self { self.lang = Some(lang.to_string()); self } pub fn with_comment(mut self, comment: &str) -> Self { self.comment = Some(comment.to_string()); self } pub fn with_addon(mut self, addon: Array) -> Self { let addons = addon .into_iter() .map(|a| a.into_string().unwrap()) .collect(); self.addon = Some(addons); self } pub fn with_test(mut self, test: bool) -> Self { self.test = Some(test); self } fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("OrderAuctionServerBuilder") .with_fn("new_auction_server_builder", Self::new) .with_fn("with_authorized_keys", Self::with_authorized_keys) .with_fn("with_dist", Self::with_dist) .with_fn("with_lang", Self::with_lang) .with_fn("with_comment", Self::with_comment) .with_fn("with_addon", Self::with_addon) .with_fn("with_test", Self::with_test) .with_get("authorized_keys", |b: &mut OrderAuctionServerBuilder| { b.authorized_keys.clone() }) .with_get("dist", |b: &mut OrderAuctionServerBuilder| b.dist.clone()) .with_get("lang", |b: &mut OrderAuctionServerBuilder| b.lang.clone()) .with_get("comment", |b: &mut OrderAuctionServerBuilder| { b.comment.clone().unwrap_or("".to_string()) }) .with_get("addon", |b: &mut OrderAuctionServerBuilder| b.addon.clone()) .with_get("test", |b: &mut OrderAuctionServerBuilder| b.test.clone()); } } #[derive(Debug, Deserialize, Clone, CustomType)] #[rhai_type(extra = Self::build_rhai_type)] pub struct OrderServerAddonBuilder { pub server_number: i64, pub product_id: String, pub reason: Option, pub gateway: Option, pub test: Option, } impl OrderServerAddonBuilder { pub fn new(server_number: i64, product_id: &str) -> Self { Self { server_number, product_id: product_id.to_string(), reason: None, gateway: None, test: Some(true), // by default test is enabled } } pub fn with_reason(mut self, reason: &str) -> Self { self.reason = Some(reason.to_string()); self } pub fn with_gateway(mut self, gateway: &str) -> Self { self.gateway = Some(gateway.to_string()); self } pub fn with_test(mut self, test: bool) -> Self { self.test = Some(test); self } fn build_rhai_type(builder: &mut TypeBuilder) { builder .with_name("OrderServerAddonBuilder") .with_fn("new_server_addon_builder", Self::new) .with_fn("with_reason", Self::with_reason) .with_fn("with_gateway", Self::with_gateway) .with_fn("with_test", Self::with_test) .with_get("server_number", |b: &mut OrderServerAddonBuilder| { b.server_number }) .with_get("product_id", |b: &mut OrderServerAddonBuilder| { b.product_id.clone() }) .with_get("reason", |b: &mut OrderServerAddonBuilder| b.reason.clone()) .with_get("gateway", |b: &mut OrderServerAddonBuilder| { b.gateway.clone() }) .with_get("test", |b: &mut OrderServerAddonBuilder| b.test.clone()); } } fn string_or_seq_string<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let value = Value::deserialize(deserializer)?; match value { Value::String(s) => Ok(vec![s]), Value::Array(a) => a .into_iter() .map(|v| { v.as_str() .map(ToString::to_string) .ok_or(serde::de::Error::custom("expected string")) }) .collect(), _ => Err(serde::de::Error::custom( "expected string or array of strings", )), } } fn option_string_or_seq_string<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { let value = Value::deserialize(deserializer)?; match value { Value::Null => Ok(None), Value::String(s) => Ok(Some(vec![s])), Value::Array(a) => Ok(Some( a.into_iter() .map(|v| { v.as_str() .map(ToString::to_string) .ok_or(serde::de::Error::custom("expected string")) }) .collect::, _>>()?, )), _ => Err(serde::de::Error::custom( "expected string or array of strings", )), } }