mod error;
mod watch;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::Add;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum ServiceState {
Stateful,
Stateless,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ServiceKey {
pub id: Option<u32>,
pub name: String,
pub ns: Option<String>,
}
impl ServiceKey {
pub fn new(name: String, ns: Option<String>) -> Self {
assert_ne!(name, "");
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 {
None
} else {
Some(v2[0].to_string())
},
})
}
fn ns(&self) -> String {
self.ns
.clone()
.and_then(|s| Some(s.add("-service")))
.unwrap_or("service".to_string())
}
}
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 ttl: i64,
pub ip: String,
pub port: u16,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MetaKey {
pub name: String,
pub ns: Option<String>,
}
impl MetaKey {
pub fn new(name: String, ns: Option<String>) -> Self {
assert_ne!(name, "");
MetaKey { name, ns }
}
pub fn path(&self) -> String {
self.path_fn(|mk| format!("/{}/{}", mk.ns(), mk.name))
}
pub fn path_fn(&self, f: fn(MetaKey) -> String) -> String {
let mk = self.clone();
f(mk)
}
pub fn root_path(&self) -> String {
self.root_fn(|mk| format!("/{}/", mk.ns()))
}
pub fn root_fn(&self, f: fn(MetaKey) -> String) -> String {
f(self.clone())
}
pub fn parse(value: &str) -> Result<MetaKey, ()> {
let v: Vec<&str> = value.trim().trim_start_matches('/').split('/').collect();
if v.len() != 2 {
return Err(());
}
let v2: Vec<&str> = v[0].split('-').collect();
Ok(MetaKey {
name: v[1].to_string(),
ns: if v2.len() == 1 {
None
} else {
Some(v2[0].to_string())
},
})
}
fn ns(&self) -> String {
self.ns
.as_ref()
.and_then(|s| Some(s.clone().add("-meta")))
.unwrap_or("meta".to_string())
}
}
impl TryFrom<String> for MetaKey {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
MetaKey::parse(&value).map_err(|_| value)
}
}
impl<'a> TryFrom<&'a str> for MetaKey {
type Error = &'a str;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
MetaKey::parse(value).map_err(|_| value)
}
}
impl<'a> TryFrom<&'a [u8]> for MetaKey {
type Error = &'a [u8];
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
let v = std::str::from_utf8(value).map_err(|_| value)?;
MetaKey::parse(v).map_err(|_| value)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Meta {
pub key: MetaKey,
pub state: ServiceState,
pub instances: u32,
pub category: Option<u32>,
}
#[derive(Clone, Debug)]
pub struct Services {
pub services: Vec<Service>,
}
impl Services {
pub fn new() -> Services {
Services { services: vec![] }
}
}
#[derive(Copy, Clone, Debug)]
pub enum ServiceStatus {
Registered = 0,
Unregistered = 1,
}
impl From<u32> for ServiceStatus {
fn from(value: u32) -> Self {
match value {
0 => ServiceStatus::Registered,
1 => ServiceStatus::Unregistered,
_ => panic!("invalid value:{} for ServiceStatus", value),
}
}
}
pub trait DetectMeta {
fn register(&mut self) -> impl Future<Output = Result<(), Box<dyn Error + 'static>>>;
fn fetch(&mut self) -> impl Future<Output = Result<Option<Meta>, Box<dyn Error + 'static>>>;
fn fetch_all(&mut self) -> impl Future<Output = Result<Vec<Meta>, Box<dyn Error + 'static>>>;
fn watch(
&mut self,
) -> impl Future<Output = Result<WatchRx<MetaEvent>, Box<dyn Error + 'static>>>;
fn watch_all(
&mut self,
) -> impl Future<Output = Result<WatchRx<MetaEvent>, Box<dyn Error + 'static>>>;
}
pub trait Detector {
fn service(&self) -> &Service;
fn id(&self) -> Option<u32> {
self.service().key.id()
}
fn ttl(&self) -> i64 {
self.service().ttl
}
fn status(&self) -> ServiceStatus;
fn registered(&self) -> bool {
match self.status() {
ServiceStatus::Registered => true,
_ => false,
}
}
fn unregistered(&self) -> bool {
match self.status() {
ServiceStatus::Unregistered => true,
_ => false,
}
}
fn register(&mut self) -> impl Future<Output = Result<(), Box<dyn Error + 'static>>>;
fn fetch(&mut self) -> impl Future<Output = Result<Services, Box<dyn Error + 'static>>>;
fn fetch_all(
&mut self,
) -> impl Future<Output = Result<HashMap<String, Services>, Box<dyn Error + 'static>>>;
fn watch(
&mut self,
) -> impl Future<Output = Result<WatchRx<ServiceEvent>, Box<dyn Error + 'static>>>;
fn watch_all(&mut self) -> impl Future<Output = Result<WatchRx<ServiceEvent>, Box<dyn Error>>>;
fn oneself(&mut self) -> Option<OneselfRx>;
}
pub fn meta_with_only_key(key: MetaKey) -> Meta {
Meta {
key,
state: ServiceState::Stateless,
instances: 0,
category: None,
}
}
pub fn service_with_only_key(key: ServiceKey) -> Service {
Service {
key,
ttl: 0,
ip: String::new(),
port: 0,
}
}
pub use error::*;
pub use serde;
pub use watch::*;