use crate::Meta;
use serde::{Deserialize, Serialize};
use std::ops::Add;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ServiceKey {
pub id: Option<u32>,
pub name: String,
pub ns: String,
}
impl ServiceKey {
pub fn new<S1: Into<String>, S2: Into<String>>(name: S1, ns: S2) -> Self {
let name = name.into();
assert_ne!(name.len(), 0);
let ns = ns.into();
ServiceKey { id: None, name, ns }
}
pub fn id(&self) -> Option<u32> {
self.id
}
pub fn has_id(&self) -> bool {
self.id.is_some()
}
pub fn path(&self) -> Option<String> {
let id = self.id?;
Some(self.path_with_id(id))
}
pub fn path_with_id(&self, id: u32) -> String {
self.path_fn(id, |sk| {
format!("/{}/{}/{}", sk.ns(), sk.name, sk.id.unwrap())
})
}
pub fn path_fn(&self, id: u32, f: fn(ServiceKey) -> String) -> String {
let mut sk = self.clone();
sk.id = Some(id);
f(sk)
}
pub fn parent_path(&self) -> String {
self.parent_path_fn(|sk| format!("/{}/{}/", sk.ns(), sk.name))
}
pub fn parent_path_fn(&self, f: fn(ServiceKey) -> String) -> String {
f(self.clone())
}
pub fn root_path(&self) -> String {
self.root_fn(|sk| format!("/{}/", sk.ns()))
}
pub fn root_fn(&self, f: fn(ServiceKey) -> String) -> String {
f(self.clone())
}
pub fn parse(value: &str) -> Result<ServiceKey, ()> {
let v: Vec<&str> = value.trim().trim_start_matches('/').split('/').collect();
if v.len() != 3 {
return Err(());
}
let id = v[2].parse::<u32>().map_err(|_| ())?;
let v2: Vec<&str> = v[0].split('-').collect();
Ok(ServiceKey {
id: Some(id),
name: v[1].to_string(),
ns: if v2.len() == 1 {
String::new()
} else {
v2[0].to_string()
},
})
}
fn ns(&self) -> String {
if self.ns.is_empty() {
"service".to_string()
} else {
self.ns.clone().add("-service")
}
}
}
impl TryFrom<String> for ServiceKey {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
ServiceKey::parse(&value).map_err(|_| value)
}
}
impl<'a> TryFrom<&'a str> for ServiceKey {
type Error = &'a str;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
ServiceKey::parse(value).map_err(|_| value)
}
}
impl<'a> TryFrom<&'a [u8]> for ServiceKey {
type Error = &'a [u8];
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
let v = std::str::from_utf8(value).map_err(|_| value)?;
ServiceKey::parse(v).map_err(|_| value)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Service {
pub key: ServiceKey,
pub meta: Option<Meta>,
pub ttl: Option<i64>,
pub ip: Option<String>,
pub port: Option<u16>,
pub extend: Option<String>,
#[serde(skip)]
pub revision: Option<i64>,
}
impl Service {
pub fn from_key(key: ServiceKey) -> Self {
Self {
key,
meta: None,
ttl: None,
ip: None,
port: None,
extend: None,
revision: None,
}
}
pub fn address(&self) -> String {
if self.ip.is_none() {
return String::new();
} else if self.port.is_none() {
return self.ip.as_ref().unwrap().clone();
} else {
format!(
"{}:{}",
self.ip.as_ref().unwrap(),
self.port.as_ref().unwrap()
)
}
}
pub fn ttl(mut self, ttl: Option<i64>) -> Self {
self.ttl = ttl;
self
}
pub fn ip<S: Into<String>>(mut self, ip: Option<S>) -> Self {
self.ip = ip.map(|ip| ip.into());
self
}
pub fn port(mut self, port: Option<u16>) -> Self {
self.port = port;
self
}
pub fn extend<T: Into<String>>(mut self, extend: Option<T>) -> Self {
self.extend = extend.map(|s| s.into());
self
}
}
#[derive(Clone, Debug)]
pub struct Services {
pub services: Vec<Service>,
}
impl Services {
pub fn new() -> Services {
Services { services: vec![] }
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ServiceStatus {
Registered = 0,
Unregistered = 1,
}
impl ServiceStatus {
pub fn registered(&self) -> bool {
match self {
ServiceStatus::Registered => true,
ServiceStatus::Unregistered => false,
}
}
pub fn unregistered(&self) -> bool {
!self.registered()
}
}
impl From<u32> for ServiceStatus {
fn from(value: u32) -> Self {
match value {
0 => ServiceStatus::Registered,
1 => ServiceStatus::Unregistered,
_ => panic!("invalid value:{} for ServiceStatus", value),
}
}
}