From 69d989da8138550b393f80df1150f5e05174cf14 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Tue, 25 Jan 2022 02:23:51 +0530 Subject: [PATCH 01/22] Basic Framework Structure --- .gitignore | 1 + Cargo.lock | 7 ++ Cargo.toml | 8 ++ src/bin/entrypoint.rs | 1 + src/lib.rs | 1 + src/registry/action_catalog.rs | 68 ++++++++++++++++ src/registry/action_endpoint.rs | 48 ++++++++++++ src/registry/endpoint_list.rs | 132 ++++++++++++++++++++++++++++++++ src/registry/event_endpoint.rs | 27 +++++++ src/registry/mod.rs | 86 +++++++++++++++++++++ 10 files changed, 379 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/bin/entrypoint.rs create mode 100644 src/lib.rs create mode 100644 src/registry/action_catalog.rs create mode 100644 src/registry/action_endpoint.rs create mode 100644 src/registry/endpoint_list.rs create mode 100644 src/registry/event_endpoint.rs create mode 100644 src/registry/mod.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a580b33 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "molecular-rust" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4784b09 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "molecular-rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/bin/entrypoint.rs b/src/bin/entrypoint.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/src/bin/entrypoint.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..97ac64f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod registry; \ No newline at end of file diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs new file mode 100644 index 0000000..139a823 --- /dev/null +++ b/src/registry/action_catalog.rs @@ -0,0 +1,68 @@ +use std::{collections::HashMap}; + +use super::*; + +pub struct ActionCatalog { + registry: Arc, + broker: Arc, + strategy: Strategy, + logger: Arc, + actions: HashMap, +} + +impl ActionCatalog { + fn new(registry: Arc, broker: Arc, strategy: Strategy) -> Self { + let logger = registry.logger(); + let logger = Arc::clone(logger); + + Self { + registry, + strategy, + broker, + logger, + actions: HashMap::new(), + } + } + fn add(&mut self, node: Arc, service: Arc, action: Action) { + let list = self.actions.get_mut(&action.name); + match list { + Some(list) => list.add(node, service, action), + None => { + let name = action.name.clone(); + let mut list = EndpointList::new( + Arc::clone(&self.registry), + Arc::clone(&self.broker), + name, + None, + ); + let name = action.name.clone(); + list.add(node, service, action); + self.actions.insert(name, list); + } + } + } + fn get(&self, action_name: &String) -> Option<&EndpointList> { + self.actions.get(action_name) + } + fn is_available(&self, action_name: &String) -> bool { + match self.actions.get(action_name) { + Some(el) => el.has_available(), + None => false, + } + } + fn remove_by_service(&mut self, service: &ServiceItem) { + self.actions.iter_mut().for_each(|item| { + let (key, el) = item; + el.remove_by_service(service); + }); + } + fn remove(&mut self, action_name: &String, node_id: &String) { + let list = self.actions.get_mut(action_name); + if let Some(el) = list { + el.remove_by_node_id(node_id); + } + } + fn list(&self) { + todo!() + } +} diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs new file mode 100644 index 0000000..5effefc --- /dev/null +++ b/src/registry/action_endpoint.rs @@ -0,0 +1,48 @@ +use super::*; + +#[derive(Clone)] +pub struct ActionEndpoint { + endpoint: Endpoint, + action: Action, + name: String, +} +impl ActionEndpoint { + pub fn new( + registry: Arc, + broker: Arc, + node: Arc, + service: Arc, + action: Action, + ) -> Self { + let endpoint = Endpoint::new(registry, broker, node, service); + let name = format!("{}:{}", endpoint.id, action.name); + ActionEndpoint { + action, + endpoint, + name, + } + } + + pub fn is_available(&self) -> bool { + self.endpoint.state + } + pub fn is_local(&self) -> bool { + self.endpoint.local + } + pub fn update(&mut self, action: Action) { + self.action = action + } + pub fn node(&self) -> &Node { + &self.endpoint.node + } + + pub fn service(&self) -> &ServiceItem { + &self.endpoint.service + } + pub fn name(&self) -> &String { + &self.name + } + pub fn id(&self) -> &String { + &self.endpoint.id + } +} diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs new file mode 100644 index 0000000..f6e1176 --- /dev/null +++ b/src/registry/endpoint_list.rs @@ -0,0 +1,132 @@ +use std::sync::Arc; + +use super::*; +use action_endpoint::ActionEndpoint; + +pub struct EndpointList { + registry: Arc, + broker: Arc, + name: String, + group: Option, + internal: bool, + endpoints: Vec, + local_endpoints: Vec, +} + +impl EndpointList { + pub fn new( + registry: Arc, + broker: Arc, + name: String, + group: Option, + ) -> Self { + let internal = name.starts_with("$"); + let endpoints = Vec::new(); + let local_endpoints = Vec::new(); + + Self { + registry, + broker, + name, + group, + endpoints, + local_endpoints, + internal, + } + } + + pub fn add(&mut self, node: Arc, service: Arc, data: Action) { + let entry = self + .endpoints + .iter_mut() + .find(|x| x.node() == &*node && x.service().name == service.name); + + match entry { + Some(found) => { + found.update(data); + return; + } + None => {} + } + let ep = ActionEndpoint::new( + Arc::clone(&self.registry), + Arc::clone(&self.broker), + Arc::clone(&node), + Arc::clone(&service), + data, + ); + + self.endpoints.push(ep.clone()); + if ep.is_local() { + self.local_endpoints.push(ep) + } + } + fn get_first(&self) -> Option<&ActionEndpoint> { + self.endpoints.get(0) + } + + fn select(&self) -> &ActionEndpoint { + todo!() + } + + fn next(&self) -> &ActionEndpoint { + todo!() + } + fn next_local(&self) -> &ActionEndpoint { + todo!() + } + + pub fn has_available(&self) -> bool { + for ep in self.endpoints.iter() { + if ep.is_available() { + return true; + } + } + return false; + } + fn has_local(&self) -> bool { + self.local_endpoints.len() > 0 + } + + fn update_local_endpoints(&mut self) { + let mut local: Vec = Vec::new(); + for ep in &self.endpoints { + if ep.is_local() { + let e = ep.clone(); + local.push(e); + } + } + std::mem::swap(&mut local, &mut self.local_endpoints); + drop(local); + } + + fn count(&self) -> usize { + self.endpoints.len() + } + fn get_endpoint_by_node_id(&self, node_id: &String) -> Option<&ActionEndpoint> { + self.endpoints + .iter() + .find(|e| e.id() == node_id && e.is_available()) + } + fn has_node_id(&self, node_id: &String) -> bool { + match self.endpoints.iter().find(|e| e.id() == node_id) { + Some(_) => true, + None => false, + } + } + pub fn remove_by_service(&mut self, service: &ServiceItem) { + self.endpoints.retain(|ep| { + let delete = ep.service() == service; + !delete + }); + self.update_local_endpoints(); + } + + pub fn remove_by_node_id(&mut self, node_id: &String) { + self.endpoints.retain(|ep| { + let delete = ep.id() == node_id; + !delete + }); + self.update_local_endpoints(); + } +} diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs new file mode 100644 index 0000000..0618e0a --- /dev/null +++ b/src/registry/event_endpoint.rs @@ -0,0 +1,27 @@ +// use super::{Broker, Endpoint, Node, Registry, ServiceItem, Event}; + +// pub struct EventEndpoint { +// endpoint: Endpoint, +// event: Event, +// } +// impl EventEndpoint { +// fn new( +// registry: , +// broker: Broker, +// node: Node, +// service: ServiceItem, +// event: Event, +// ) -> Self { +// let endpoint = Endpoint::new(registry, broker, node, service); + +// Self { event, endpoint } +// } + +// fn is_available(&self) -> bool { +// self.endpoint.state +// } + +// fn update(&mut self, event: Event) { +// self.event = event +// } +// } diff --git a/src/registry/mod.rs b/src/registry/mod.rs new file mode 100644 index 0000000..ac9f226 --- /dev/null +++ b/src/registry/mod.rs @@ -0,0 +1,86 @@ +pub mod action_catalog; +pub mod action_endpoint; +pub mod endpoint_list; +pub mod event_endpoint; +pub use std::sync::Arc; + +pub use action_endpoint::ActionEndpoint; +pub use endpoint_list::EndpointList; +// pub use event_endpoint::EventEndpoint; + +pub struct Logger {} +pub struct Broker { + node_id: String, +} +pub struct Registry { + logger: Arc, +} +impl Registry { + pub fn logger(&self) -> &Arc { + &self.logger + } +} +#[derive(PartialEq, Eq)] +pub struct Node { + id: String, +} +#[derive(PartialEq, Eq)] +pub struct ServiceItem { + name: String, +} + +trait FnType {} + +#[derive(Clone)] +pub struct Action { + name: String, +} +impl FnType for Action {} +struct Event {} +impl FnType for Event {} +pub struct Strategy {} + +trait EndpointTrait { + fn node(&self) -> Node; + fn service(&self) -> ServiceItem; + fn update(&mut self, data: F) + where + F: FnType; +} + +#[derive(Clone)] +struct Endpoint { + registry: Arc, + broker: Arc, + node: Arc, + service: Arc, + state: bool, + id: String, + local: bool, +} + +impl Endpoint { + fn new( + registry: Arc, + broker: Arc, + node: Arc, + service: Arc, + ) -> Self { + let local = node.id == broker.node_id; + let id = node.id.clone(); + Self { + registry, + broker, + node, + service, + state: true, + id: id, + local, + } + } +} + +enum EndpointType { + Action, + Event, +} From 77dd2d6ad66171f11581f0c34f5b3a38d596dfd6 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Wed, 26 Jan 2022 02:44:50 +0530 Subject: [PATCH 02/22] node and node catalog implemented --- Cargo.lock | 86 +++++++++++++++++++++++ Cargo.toml | 1 + src/registry/action_catalog.rs | 10 +-- src/registry/action_endpoint.rs | 7 +- src/registry/endpoint_list.rs | 6 +- src/registry/mod.rs | 16 +++-- src/registry/node.rs | 117 ++++++++++++++++++++++++++++++++ src/registry/node_catalog.rs | 108 +++++++++++++++++++++++++++++ 8 files changed, 331 insertions(+), 20 deletions(-) create mode 100644 src/registry/node.rs create mode 100644 src/registry/node_catalog.rs diff --git a/Cargo.lock b/Cargo.lock index a580b33..53e1b5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,92 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "libc" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" + [[package]] name = "molecular-rust" version = "0.1.0" +dependencies = [ + "chrono", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 4784b09..42b3536 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chrono = "0.4.19" \ No newline at end of file diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index 139a823..b28802a 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -1,8 +1,8 @@ -use std::{collections::HashMap}; +use std::collections::HashMap; use super::*; -pub struct ActionCatalog { +struct ActionCatalog { registry: Arc, broker: Arc, strategy: Strategy, @@ -41,10 +41,10 @@ impl ActionCatalog { } } } - fn get(&self, action_name: &String) -> Option<&EndpointList> { + fn get(&self, action_name: &str) -> Option<&EndpointList> { self.actions.get(action_name) } - fn is_available(&self, action_name: &String) -> bool { + fn is_available(&self, action_name: &str) -> bool { match self.actions.get(action_name) { Some(el) => el.has_available(), None => false, @@ -56,7 +56,7 @@ impl ActionCatalog { el.remove_by_service(service); }); } - fn remove(&mut self, action_name: &String, node_id: &String) { + fn remove(&mut self, action_name: &str, node_id: &str) { let list = self.actions.get_mut(action_name); if let Some(el) = list { el.remove_by_node_id(node_id); diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 5effefc..99faf0e 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -4,7 +4,7 @@ use super::*; pub struct ActionEndpoint { endpoint: Endpoint, action: Action, - name: String, + pub name: String, } impl ActionEndpoint { pub fn new( @@ -39,10 +39,7 @@ impl ActionEndpoint { pub fn service(&self) -> &ServiceItem { &self.endpoint.service } - pub fn name(&self) -> &String { - &self.name - } - pub fn id(&self) -> &String { + pub fn id(&self) -> &str { &self.endpoint.id } } diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index f6e1176..69dbab6 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -103,12 +103,12 @@ impl EndpointList { fn count(&self) -> usize { self.endpoints.len() } - fn get_endpoint_by_node_id(&self, node_id: &String) -> Option<&ActionEndpoint> { + fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&ActionEndpoint> { self.endpoints .iter() .find(|e| e.id() == node_id && e.is_available()) } - fn has_node_id(&self, node_id: &String) -> bool { + fn has_node_id(&self, node_id: &str) -> bool { match self.endpoints.iter().find(|e| e.id() == node_id) { Some(_) => true, None => false, @@ -122,7 +122,7 @@ impl EndpointList { self.update_local_endpoints(); } - pub fn remove_by_node_id(&mut self, node_id: &String) { + pub fn remove_by_node_id(&mut self, node_id: &str) { self.endpoints.retain(|ep| { let delete = ep.id() == node_id; !delete diff --git a/src/registry/mod.rs b/src/registry/mod.rs index ac9f226..b83128f 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -2,15 +2,20 @@ pub mod action_catalog; pub mod action_endpoint; pub mod endpoint_list; pub mod event_endpoint; +pub mod node; +pub mod node_catalog; pub use std::sync::Arc; pub use action_endpoint::ActionEndpoint; pub use endpoint_list::EndpointList; +pub use node::{Client, Node}; // pub use event_endpoint::EventEndpoint; pub struct Logger {} pub struct Broker { node_id: String, + instance_id: String, + moleculer_version: String, } pub struct Registry { logger: Arc, @@ -20,11 +25,8 @@ impl Registry { &self.logger } } -#[derive(PartialEq, Eq)] -pub struct Node { - id: String, -} -#[derive(PartialEq, Eq)] + +#[derive(PartialEq, Eq, Clone)] pub struct ServiceItem { name: String, } @@ -66,8 +68,8 @@ impl Endpoint { node: Arc, service: Arc, ) -> Self { - let local = node.id == broker.node_id; - let id = node.id.clone(); + let local = node.id() == broker.node_id; + let id = node.id().to_string(); Self { registry, broker, diff --git a/src/registry/node.rs b/src/registry/node.rs new file mode 100644 index 0000000..cba01c5 --- /dev/null +++ b/src/registry/node.rs @@ -0,0 +1,117 @@ +use std::net::IpAddr; + +use chrono::Duration; + +use super::ServiceItem; + +#[derive(PartialEq, Eq, Clone)] +pub struct Node { + id: String, + instance_id: Option, + available: bool, + local: bool, + last_heartbeat_time: Duration, + /* feields that need to be added later. + config + + metadata + */ + client: Option, + ip_list: Vec, + port: Option, + hostname: Option, + udp_address: Option, + /* + raw_info + cpu + cpuseq + */ + services: Vec, + pub seq: usize, + offline_since: Option, +} + +impl Node { + pub fn new(id: String) -> Self { + Self { + id: id, + instance_id: None, + available: true, + local: false, + client: None, + /* + change this later with actual process uptime. + */ + last_heartbeat_time: Duration::seconds(1), + ip_list: Vec::new(), + port: None, + hostname: None, + udp_address: None, + services: Vec::new(), + seq: 0, + offline_since: None, + } + } + pub fn update(&mut self) { + todo!() + } + pub fn update_local_info(&mut self) { + todo!() + } + pub fn hearbeat(&mut self) { + if !self.available { + self.available = true; + self.offline_since = None; + } + todo!() + } + pub fn disconnect(&mut self) { + if self.available { + self.seq = self.seq.saturating_add(1); + /* update this with process uptime + self.offline_since = + */ + } + self.available = false; + } + pub fn id(&self) -> &str { + &self.id + } + pub fn available(&self) -> bool { + self.available + } + pub fn services_len(&self) -> usize { + self.services.len() + } + pub fn set_local(mut self, value: bool) -> Self { + self.local = value; + self + } + pub fn set_ip_list(mut self, ip_list: Vec) -> Self { + self.ip_list = ip_list; + self + } + pub fn set_instance_id(mut self, instance_id: String) -> Self { + self.instance_id = Some(instance_id); + self + } + pub fn set_hostname(mut self, hostname: String) -> Self { + self.hostname = Some(hostname); + self + } + pub fn set_client(mut self, client: Client) -> Self { + self.client = Some(client); + self + } + pub fn set_seq(mut self, seq: usize) -> Self { + self.seq = seq; + self + } +} +#[derive(PartialEq, Eq, Clone)] + +pub struct Client { + pub(crate) client_type: String, + pub(crate) version: String, + pub(crate) lang_version: String, +} diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs new file mode 100644 index 0000000..fa3700e --- /dev/null +++ b/src/registry/node_catalog.rs @@ -0,0 +1,108 @@ +use std::{collections::HashMap, net::IpAddr, sync::Arc}; + +use super::{node, Broker, Client, Logger, Node, Registry}; + +pub struct NodeCatalog { + registry: Arc, + broker: Arc, + logger: Arc, + nodes: HashMap, + local_node: Option, +} +impl NodeCatalog { + pub fn new(registry: Arc, broker: Arc) -> Self { + let logger = registry.logger(); + let logger = Arc::clone(logger); + Self { + broker, + logger, + registry, + nodes: HashMap::new(), + local_node: None, + } + } + ///Create a local node + fn create_local_node(&mut self) -> Node { + let client = Client { + client_type: "rust".to_string(), + lang_version: "1.56.1".to_string(), + version: self.broker.moleculer_version.clone(), + }; + let node = Node::new(self.broker.node_id.clone()) + .set_local(true) + .set_ip_list(get_ip_list()) + .set_instance_id(self.broker.instance_id.clone()) + .set_hostname(get_hostname()) + .set_seq(1) + .set_client(client); + + self.nodes.insert(node.id().to_string(), node.clone()); + self.local_node = Some(node.clone()); + return node; + todo!() + /* + node.metadata = self.broker.metadata.clone() + */ + } + pub fn add(&mut self, id: &str, node: Node) { + self.nodes.insert(id.to_string(), node); + } + pub fn had_node(&self, id: &str) -> bool { + match self.nodes.get(id) { + Some(_) => true, + None => false, + } + } + pub fn get_node(&self, id: &str) -> Option<&Node> { + self.nodes.get(id) + } + pub fn get_node_mut(&mut self, id: &str) -> Option<&mut Node> { + self.nodes.get_mut(id) + } + pub fn delete(&mut self, id: &str) -> Option { + self.nodes.remove(id) + } + pub fn count(&self) -> usize { + self.nodes.len() + } + pub fn online_count(&self) -> usize { + let mut count: usize = 0; + self.nodes.iter().for_each(|node_item| { + let (_, node) = node_item; + if node.available() { + count = count.saturating_add(1); + } + }); + count + } + pub fn process_node_info(&self) { + todo!() + } + pub fn disconnect(&mut self) { + todo!() + } + + pub fn list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { + let mut nodes = Vec::new(); + self.nodes.iter().for_each(|node_item| { + let (_, node) = node_item; + if only_available && !node.available() { + return; + } + if with_services && node.services_len() <= 0 { + return; + } + nodes.push(node); + }); + nodes + } + pub fn nodes_vec(&self) -> Vec<&Node> { + self.nodes.values().collect() + } +} +fn get_ip_list() -> Vec { + todo!() +} +fn get_hostname() -> String { + todo!() +} From 3b30a7cad8077f13b267fda4d5d35fb40b3a6355 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Wed, 26 Jan 2022 05:17:03 +0530 Subject: [PATCH 03/22] service item and service item catalog --- src/registry/action_catalog.rs | 2 +- src/registry/action_endpoint.rs | 5 ++- src/registry/endpoint_list.rs | 7 ++- src/registry/mod.rs | 33 ++++++++++---- src/registry/node.rs | 11 ++--- src/registry/node_catalog.rs | 45 +++++++++++++------ src/registry/service_catalog.rs | 79 +++++++++++++++++++++++++++++++++ src/registry/service_item.rs | 54 ++++++++++++++++++++++ 8 files changed, 199 insertions(+), 37 deletions(-) create mode 100644 src/registry/service_catalog.rs create mode 100644 src/registry/service_item.rs diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index b28802a..d4b17ab 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -7,7 +7,7 @@ struct ActionCatalog { broker: Arc, strategy: Strategy, logger: Arc, - actions: HashMap, + actions: ActionsMap, } impl ActionCatalog { diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 99faf0e..adc9195 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Clone)] +#[derive(PartialEq, Eq, Clone)] pub struct ActionEndpoint { endpoint: Endpoint, action: Action, @@ -42,4 +42,7 @@ impl ActionEndpoint { pub fn id(&self) -> &str { &self.endpoint.id } + pub fn service_name(&self) -> &str { + &self.endpoint.service.name + } } diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index 69dbab6..cf5c743 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -1,12 +1,11 @@ use std::sync::Arc; use super::*; -use action_endpoint::ActionEndpoint; - +#[derive(PartialEq, Eq, Clone)] pub struct EndpointList { registry: Arc, broker: Arc, - name: String, + pub name: String, group: Option, internal: bool, endpoints: Vec, @@ -39,7 +38,7 @@ impl EndpointList { let entry = self .endpoints .iter_mut() - .find(|x| x.node() == &*node && x.service().name == service.name); + .find(|x| x.node() == &*node && x.service_name() == service.name); match entry { Some(found) => { diff --git a/src/registry/mod.rs b/src/registry/mod.rs index b83128f..f10bd53 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -4,19 +4,29 @@ pub mod endpoint_list; pub mod event_endpoint; pub mod node; pub mod node_catalog; +pub mod service_catalog; +pub mod service_item; +use std::collections::HashMap; pub use std::sync::Arc; pub use action_endpoint::ActionEndpoint; pub use endpoint_list::EndpointList; pub use node::{Client, Node}; +use service_item::ServiceItem; // pub use event_endpoint::EventEndpoint; +type ActionsMap = HashMap; + +#[derive(PartialEq, Eq)] pub struct Logger {} +#[derive(PartialEq, Eq)] pub struct Broker { node_id: String, instance_id: String, moleculer_version: String, } + +#[derive(PartialEq, Eq)] pub struct Registry { logger: Arc, } @@ -26,14 +36,9 @@ impl Registry { } } -#[derive(PartialEq, Eq, Clone)] -pub struct ServiceItem { - name: String, -} - trait FnType {} -#[derive(Clone)] +#[derive(PartialEq, Eq, Clone)] pub struct Action { name: String, } @@ -50,7 +55,7 @@ trait EndpointTrait { F: FnType; } -#[derive(Clone)] +#[derive(PartialEq, Eq, Clone)] struct Endpoint { registry: Arc, broker: Arc, @@ -68,8 +73,8 @@ impl Endpoint { node: Arc, service: Arc, ) -> Self { - let local = node.id() == broker.node_id; - let id = node.id().to_string(); + let local = node.id == broker.node_id; + let id = node.id.to_string(); Self { registry, broker, @@ -86,3 +91,13 @@ enum EndpointType { Action, Event, } + +pub struct Service { + name: String, + full_name: String, + version: String, + /* + settings , + metadata + */ +} diff --git a/src/registry/node.rs b/src/registry/node.rs index cba01c5..e7868c9 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -6,9 +6,9 @@ use super::ServiceItem; #[derive(PartialEq, Eq, Clone)] pub struct Node { - id: String, + pub id: String, instance_id: Option, - available: bool, + pub available: bool, local: bool, last_heartbeat_time: Duration, /* feields that need to be added later. @@ -74,12 +74,7 @@ impl Node { } self.available = false; } - pub fn id(&self) -> &str { - &self.id - } - pub fn available(&self) -> bool { - self.available - } + pub fn services_len(&self) -> usize { self.services.len() } diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index fa3700e..962ba18 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -36,7 +36,7 @@ impl NodeCatalog { .set_seq(1) .set_client(client); - self.nodes.insert(node.id().to_string(), node.clone()); + self.nodes.insert(node.id.to_string(), node.clone()); self.local_node = Some(node.clone()); return node; todo!() @@ -69,7 +69,7 @@ impl NodeCatalog { let mut count: usize = 0; self.nodes.iter().for_each(|node_item| { let (_, node) = node_item; - if node.available() { + if node.available { count = count.saturating_add(1); } }); @@ -83,22 +83,39 @@ impl NodeCatalog { } pub fn list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { - let mut nodes = Vec::new(); - self.nodes.iter().for_each(|node_item| { - let (_, node) = node_item; - if only_available && !node.available() { - return; - } - if with_services && node.services_len() <= 0 { - return; - } - nodes.push(node); - }); - nodes + self.nodes + .values() + .filter(|node| { + if only_available && !node.available { + return false; + } + if with_services && node.services_len() <= 0 { + return false; + } + return true; + }) + .collect() + } + pub fn list_mut(&mut self, only_available: bool, with_services: bool) -> Vec<&mut Node> { + self.nodes + .values_mut() + .filter(|node| { + if only_available && !node.available { + return false; + } + if with_services && node.services_len() <= 0 { + return false; + } + return true; + }) + .collect() } pub fn nodes_vec(&self) -> Vec<&Node> { self.nodes.values().collect() } + pub fn nodes_vec_mut(&mut self) -> Vec<&mut Node> { + self.nodes.values_mut().collect() + } } fn get_ip_list() -> Vec { todo!() diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs new file mode 100644 index 0000000..8847db3 --- /dev/null +++ b/src/registry/service_catalog.rs @@ -0,0 +1,79 @@ +use super::*; + +pub struct ServiceCatalog { + registry: Arc, + broker: Arc, + logger: Arc, + services: Vec, +} + +impl ServiceCatalog { + pub fn new(registry: Arc, broker: Arc) -> Self { + let logger = ®istry.logger; + let logger = Arc::clone(&logger); + Self { + broker, + registry, + logger, + services: Vec::new(), + } + } + ///Add a new service + pub fn add(&mut self, node: Arc, service: Arc, local: bool) { + let service_item = ServiceItem::new(node, service, local); + self.services.push(service_item); + } + ///Check the service exsists + pub fn has(&self, full_name: &str, node_id: Option<&str>) -> bool { + let svc = self + .services + .iter() + .find(|svc| svc.equals(full_name, node_id)); + match svc { + Some(_) => true, + None => false, + } + } + pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&ServiceItem> { + self.services + .iter() + .find(|svc| svc.equals(full_name, node_id)) + } + pub fn get_mut(&mut self, full_name: &str, node_id: Option<&str>) -> Option<&mut ServiceItem> { + self.services + .iter_mut() + .find(|svc| svc.equals(full_name, node_id)) + } + pub fn list(&self) { + todo!() + } + pub fn get_local_node_service(&self) { + todo!() + } + //remove all endpoints by node_id. + pub fn remove_by_node_id(&mut self, node_id: &str) { + let services: Vec<&ServiceItem> = self + .services + .iter() + .filter(|svc| { + if svc.node.id == node_id { + todo!("remove actions and events in registry"); + return false; + } + true + }) + .collect(); + todo!("updat the service") + } + + pub fn remove(&mut self, full_name: &str, node_id: Option<&str>) { + self.services.retain(|svc| { + if svc.equals(full_name, node_id) { + todo!("remove actions and events in registry"); + + return false; + } + return true; + }) + } +} diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs new file mode 100644 index 0000000..b50c9a4 --- /dev/null +++ b/src/registry/service_item.rs @@ -0,0 +1,54 @@ +use super::*; + +#[derive(PartialEq, Eq, Clone)] +pub struct ServiceItem { + pub name: String, + pub node: Arc, + local: bool, + full_name: String, + version: String, + actions: ActionsMap, + /* + eventsmap + metadata + settings + */ +} +impl ServiceItem { + pub fn new(node: Arc, service: Arc, local: bool) -> Self { + Self { + node, + local, + actions: HashMap::new(), + full_name: service.full_name.to_string(), + version: service.version.to_string(), + name: service.name.to_string(), + } + } + pub fn equals(&self, full_name: &str, node_id: Option<&str>) -> bool { + match node_id { + Some(id) => self.node.id == id && self.full_name == full_name, + None => self.full_name == full_name, + } + } + + ///Update service properties + pub fn update(&mut self, service: &Service) { + self.full_name = service.full_name.to_string(); + self.version = service.version.to_string(); + /* + settings + metadata + */ + todo!() + } + ///Add action to service + pub fn add_action(&mut self, action: EndpointList) { + let name = action.name.clone(); + self.actions.insert(name, action); + todo!("Decide if we want an arc of action or make a copy of that actions") + } + pub fn add_event(&mut self, event: EndpointList) { + todo!("Implement the events map") + } +} From 019eeb396bb174a0100113a005e0cbd194a8a0f1 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Wed, 26 Jan 2022 07:24:19 +0530 Subject: [PATCH 04/22] round robin selection strategy --- src/lib.rs | 3 ++- src/strategies/mod.rs | 16 +++++++++++++++ src/strategies/round_robin.rs | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/strategies/mod.rs create mode 100644 src/strategies/round_robin.rs diff --git a/src/lib.rs b/src/lib.rs index 97ac64f..de71c00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ -pub mod registry; \ No newline at end of file +pub mod registry; +pub mod strategies; \ No newline at end of file diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs new file mode 100644 index 0000000..9f2f206 --- /dev/null +++ b/src/strategies/mod.rs @@ -0,0 +1,16 @@ +use std::sync::Arc; + +use crate::registry::{ActionEndpoint, Broker, Registry}; +mod round_robin; + +trait Strategy { + fn new(registry: Arc, broker: Arc, opts: Opts) -> Self; + fn select<'a>( + &mut self, + list: Vec<&'a ActionEndpoint>, + ctx: Option, + ) -> Option<&'a ActionEndpoint>; +} + +struct Context {} +struct Opts {} diff --git a/src/strategies/round_robin.rs b/src/strategies/round_robin.rs new file mode 100644 index 0000000..459579f --- /dev/null +++ b/src/strategies/round_robin.rs @@ -0,0 +1,37 @@ +use super::*; +use std::sync::Arc; + +struct RoundRobinStrategy { + registry: Arc, + broker: Arc, + opts: Opts, + counter: usize, +} + +impl RoundRobinStrategy { + // fn new() -> Self {} +} +impl Strategy for RoundRobinStrategy { + fn new(registry: Arc, broker: Arc, opts: Opts) -> Self { + Self { + broker, + registry, + opts, + counter: 0, + } + } + fn select<'a>( + &mut self, + list: Vec<&'a ActionEndpoint>, + ctx: Option, + ) -> Option<&'a ActionEndpoint> { + if self.counter >= list.len() { + self.counter = 0; + } + self.counter = self.counter.saturating_add(1); + if let Some(ep) = list.get(self.counter) { + return Some(*ep); + } + None + } +} From 40548048b9e01d1c10ea5572ad82d8843e26f190 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Thu, 27 Jan 2022 01:33:56 +0530 Subject: [PATCH 05/22] made endpoint list generic over trait endpoint_trait --- src/registry/action_catalog.rs | 2 +- src/registry/endpoint_list.rs | 29 +++++++++++++++-------------- src/registry/mod.rs | 32 +++++++++++++++++++++++--------- src/registry/service_item.rs | 4 ++-- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index d4b17ab..f9173d8 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -41,7 +41,7 @@ impl ActionCatalog { } } } - fn get(&self, action_name: &str) -> Option<&EndpointList> { + fn get(&self, action_name: &str) -> Option<&EndpointList> { self.actions.get(action_name) } fn is_available(&self, action_name: &str) -> bool { diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index cf5c743..df6f5d4 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -2,17 +2,17 @@ use std::sync::Arc; use super::*; #[derive(PartialEq, Eq, Clone)] -pub struct EndpointList { + pub struct EndpointList { registry: Arc, broker: Arc, - pub name: String, + pub name: String, group: Option, internal: bool, - endpoints: Vec, - local_endpoints: Vec, + endpoints: Vec, + local_endpoints: Vec, } -impl EndpointList { +impl EndpointList { pub fn new( registry: Arc, broker: Arc, @@ -34,11 +34,11 @@ impl EndpointList { } } - pub fn add(&mut self, node: Arc, service: Arc, data: Action) { + pub fn add(&mut self, node: Arc, service: Arc, data:T::Data ) { let entry = self .endpoints .iter_mut() - .find(|x| x.node() == &*node && x.service_name() == service.name); + .find(|x| x.node() == &*node && x.service().name == service.name); match entry { Some(found) => { @@ -47,7 +47,8 @@ impl EndpointList { } None => {} } - let ep = ActionEndpoint::new( + + let ep = T::new( Arc::clone(&self.registry), Arc::clone(&self.broker), Arc::clone(&node), @@ -60,18 +61,18 @@ impl EndpointList { self.local_endpoints.push(ep) } } - fn get_first(&self) -> Option<&ActionEndpoint> { + fn get_first(&self) -> Option<&T> { self.endpoints.get(0) } - fn select(&self) -> &ActionEndpoint { + fn select(&self) -> &T { todo!() } - fn next(&self) -> &ActionEndpoint { + fn next(&self) -> &T { todo!() } - fn next_local(&self) -> &ActionEndpoint { + fn next_local(&self) -> &T { todo!() } @@ -88,7 +89,7 @@ impl EndpointList { } fn update_local_endpoints(&mut self) { - let mut local: Vec = Vec::new(); + let mut local: Vec = Vec::new(); for ep in &self.endpoints { if ep.is_local() { let e = ep.clone(); @@ -102,7 +103,7 @@ impl EndpointList { fn count(&self) -> usize { self.endpoints.len() } - fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&ActionEndpoint> { + fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { self.endpoints .iter() .find(|e| e.id() == node_id && e.is_available()) diff --git a/src/registry/mod.rs b/src/registry/mod.rs index f10bd53..7ff7b48 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -10,12 +10,13 @@ use std::collections::HashMap; pub use std::sync::Arc; pub use action_endpoint::ActionEndpoint; +use event_endpoint::EventEndpoint; pub use endpoint_list::EndpointList; pub use node::{Client, Node}; use service_item::ServiceItem; // pub use event_endpoint::EventEndpoint; -type ActionsMap = HashMap; +type ActionsMap = HashMap>; #[derive(PartialEq, Eq)] pub struct Logger {} @@ -42,17 +43,30 @@ trait FnType {} pub struct Action { name: String, } -impl FnType for Action {} -struct Event {} + +#[derive(PartialEq, Eq,Clone)] +pub struct Event {} impl FnType for Event {} pub struct Strategy {} -trait EndpointTrait { - fn node(&self) -> Node; - fn service(&self) -> ServiceItem; - fn update(&mut self, data: F) - where - F: FnType; +///Endpoint trait for endpoint list +pub trait EndpointTrait { + ///Data is eiter an Action struct or Event structs + type Data; + fn new( + registry: Arc, + broker: Arc, + node: Arc, + service: Arc, + data: Self::Data, + ) -> Self; + fn node(&self) -> &Node; + fn service(&self) -> &ServiceItem; + fn update(&mut self, data: Self::Data); + fn is_local(&self) -> bool; + fn is_available(&self)->bool; + fn id(&self)->&str; + fn service_name(&self)->&str; } #[derive(PartialEq, Eq, Clone)] diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index b50c9a4..5332fcb 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -43,12 +43,12 @@ impl ServiceItem { todo!() } ///Add action to service - pub fn add_action(&mut self, action: EndpointList) { + pub fn add_action(&mut self, action: EndpointList) { let name = action.name.clone(); self.actions.insert(name, action); todo!("Decide if we want an arc of action or make a copy of that actions") } - pub fn add_event(&mut self, event: EndpointList) { + pub fn add_event(&mut self, event: EndpointList) { todo!("Implement the events map") } } From 5068a165c43245ffbaf8fda8ab933da9f0ddfa54 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Thu, 27 Jan 2022 01:34:35 +0530 Subject: [PATCH 06/22] impl endpoint_trait for action_ep & event_ep --- src/registry/action_endpoint.rs | 40 ++++++++++---------- src/registry/event_endpoint.rs | 67 ++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index adc9195..8053907 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -6,43 +6,45 @@ pub struct ActionEndpoint { action: Action, pub name: String, } -impl ActionEndpoint { - pub fn new( + +impl EndpointTrait for ActionEndpoint { + type Data = Action; + fn update(&mut self, data: Self::Data) { + self.action = data; + } + fn new( registry: Arc, broker: Arc, node: Arc, service: Arc, - action: Action, + data: Self::Data, ) -> Self { let endpoint = Endpoint::new(registry, broker, node, service); - let name = format!("{}:{}", endpoint.id, action.name); - ActionEndpoint { - action, + let name = format!("{}:{}", endpoint.id, data.name); + Self { endpoint, name, + action: data, } } - pub fn is_available(&self) -> bool { - self.endpoint.state - } - pub fn is_local(&self) -> bool { - self.endpoint.local - } - pub fn update(&mut self, action: Action) { - self.action = action - } - pub fn node(&self) -> &Node { + fn node(&self) -> &Node { &self.endpoint.node } - pub fn service(&self) -> &ServiceItem { + fn service(&self) -> &ServiceItem { &self.endpoint.service } - pub fn id(&self) -> &str { + fn is_local(&self) -> bool { + self.endpoint.local + } + fn is_available(&self) -> bool { + self.endpoint.state + } + fn id(&self) -> &str { &self.endpoint.id } - pub fn service_name(&self) -> &str { + fn service_name(&self) -> &str { &self.endpoint.service.name } } diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs index 0618e0a..cb4d106 100644 --- a/src/registry/event_endpoint.rs +++ b/src/registry/event_endpoint.rs @@ -1,27 +1,48 @@ -// use super::{Broker, Endpoint, Node, Registry, ServiceItem, Event}; +use super::*; -// pub struct EventEndpoint { -// endpoint: Endpoint, -// event: Event, -// } -// impl EventEndpoint { -// fn new( -// registry: , -// broker: Broker, -// node: Node, -// service: ServiceItem, -// event: Event, -// ) -> Self { -// let endpoint = Endpoint::new(registry, broker, node, service); +#[derive(Clone)] +pub struct EventEndpoint { + endpoint: Endpoint, + event: Event, +} -// Self { event, endpoint } -// } +impl EndpointTrait for EventEndpoint { + type Data = Event; + fn update(&mut self, data: Self::Data) { + self.event = data; + } + fn new( + registry: Arc, + broker: Arc, + node: Arc, + service: Arc, + data: Self::Data, + ) -> Self { + let endpoint = Endpoint::new(registry, broker, node, service); + Self { + endpoint, -// fn is_available(&self) -> bool { -// self.endpoint.state -// } + event: data, + } + } -// fn update(&mut self, event: Event) { -// self.event = event -// } -// } + fn node(&self) -> &Node { + &self.endpoint.node + } + + fn service(&self) -> &ServiceItem { + &self.endpoint.service + } + fn is_local(&self) -> bool { + self.endpoint.local + } + fn is_available(&self) -> bool { + self.endpoint.state + } + fn id(&self) -> &str { + &self.endpoint.id + } + fn service_name(&self) -> &str { + &self.endpoint.service.name + } +} From 003064f190966e0278e6ebabad26945f41c9e1cd Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Thu, 27 Jan 2022 22:43:06 +0530 Subject: [PATCH 07/22] boilerplate for registry --- src/registry/action_catalog.rs | 16 ++-- src/registry/endpoint_list.rs | 2 +- src/registry/mod.rs | 41 ++++++---- src/registry/node.rs | 2 +- src/registry/node_catalog.rs | 5 +- src/registry/registry.rs | 132 ++++++++++++++++++++++++++++++++ src/registry/service_catalog.rs | 7 +- src/strategies/mod.rs | 12 +-- src/strategies/round_robin.rs | 4 +- 9 files changed, 183 insertions(+), 38 deletions(-) create mode 100644 src/registry/registry.rs diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index f9173d8..75ef4a4 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -2,22 +2,22 @@ use std::collections::HashMap; use super::*; -struct ActionCatalog { +#[derive(PartialEq, Eq)] +pub struct ActionCatalog { registry: Arc, broker: Arc, - strategy: Strategy, + logger: Arc, actions: ActionsMap, } impl ActionCatalog { - fn new(registry: Arc, broker: Arc, strategy: Strategy) -> Self { - let logger = registry.logger(); - let logger = Arc::clone(logger); + pub fn new(registry: Arc, broker: Arc) -> Self { + let logger = ®istry.logger; + let logger = Arc::clone(&logger); Self { registry, - strategy, broker, logger, actions: HashMap::new(), @@ -41,7 +41,7 @@ impl ActionCatalog { } } } - fn get(&self, action_name: &str) -> Option<&EndpointList> { + pub fn get(&self, action_name: &str) -> Option<&EndpointList> { self.actions.get(action_name) } fn is_available(&self, action_name: &str) -> bool { @@ -56,7 +56,7 @@ impl ActionCatalog { el.remove_by_service(service); }); } - fn remove(&mut self, action_name: &str, node_id: &str) { + pub fn remove(&mut self, action_name: &str, node_id: &str) { let list = self.actions.get_mut(action_name); if let Some(el) = list { el.remove_by_node_id(node_id); diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index df6f5d4..0129472 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -103,7 +103,7 @@ impl EndpointList { fn count(&self) -> usize { self.endpoints.len() } - fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { + pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { self.endpoints .iter() .find(|e| e.id() == node_id && e.is_available()) diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 7ff7b48..888a93b 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -4,15 +4,22 @@ pub mod endpoint_list; pub mod event_endpoint; pub mod node; pub mod node_catalog; +pub mod registry; pub mod service_catalog; pub mod service_item; + use std::collections::HashMap; -pub use std::sync::Arc; +use std::sync::Arc; +use crate::strategies::Strategy; +use action_catalog::ActionCatalog; pub use action_endpoint::ActionEndpoint; -use event_endpoint::EventEndpoint; pub use endpoint_list::EndpointList; +pub use event_endpoint::EventEndpoint; pub use node::{Client, Node}; +use node_catalog::NodeCatalog; +pub use registry::Registry; +use service_catalog::ServiceCatalog; use service_item::ServiceItem; // pub use event_endpoint::EventEndpoint; @@ -25,29 +32,27 @@ pub struct Broker { node_id: String, instance_id: String, moleculer_version: String, -} - -#[derive(PartialEq, Eq)] -pub struct Registry { logger: Arc, } -impl Registry { - pub fn logger(&self) -> &Arc { - &self.logger - } -} trait FnType {} #[derive(PartialEq, Eq, Clone)] pub struct Action { name: String, + visibility: Visibility, } -#[derive(PartialEq, Eq,Clone)] +#[derive(PartialEq, Eq, Clone)] +enum Visibility { + Published, + Public, + Protected, + Private, +} +#[derive(PartialEq, Eq, Clone)] pub struct Event {} impl FnType for Event {} -pub struct Strategy {} ///Endpoint trait for endpoint list pub trait EndpointTrait { @@ -64,9 +69,9 @@ pub trait EndpointTrait { fn service(&self) -> &ServiceItem; fn update(&mut self, data: Self::Data); fn is_local(&self) -> bool; - fn is_available(&self)->bool; - fn id(&self)->&str; - fn service_name(&self)->&str; + fn is_available(&self) -> bool; + fn id(&self) -> &str; + fn service_name(&self) -> &str; } #[derive(PartialEq, Eq, Clone)] @@ -115,3 +120,7 @@ pub struct Service { metadata */ } +#[derive(PartialEq, Eq)] +pub struct Opts { + strategy: T, +} diff --git a/src/registry/node.rs b/src/registry/node.rs index e7868c9..2bd7fff 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -9,7 +9,7 @@ pub struct Node { pub id: String, instance_id: Option, pub available: bool, - local: bool, + pub local: bool, last_heartbeat_time: Duration, /* feields that need to be added later. config diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index 962ba18..b8998fb 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, net::IpAddr, sync::Arc}; use super::{node, Broker, Client, Logger, Node, Registry}; +#[derive(PartialEq, Eq)] pub struct NodeCatalog { registry: Arc, broker: Arc, @@ -11,8 +12,8 @@ pub struct NodeCatalog { } impl NodeCatalog { pub fn new(registry: Arc, broker: Arc) -> Self { - let logger = registry.logger(); - let logger = Arc::clone(logger); + let logger = ®istry.logger; + let logger = Arc::clone(&logger); Self { broker, logger, diff --git a/src/registry/registry.rs b/src/registry/registry.rs new file mode 100644 index 0000000..f54905b --- /dev/null +++ b/src/registry/registry.rs @@ -0,0 +1,132 @@ +use super::*; +#[derive(PartialEq, Eq)] +pub struct Registry { + pub logger: Arc, + broker: Arc, + nodes: NodeCatalog, + services: ServiceCatalog, + actions: ActionCatalog, + /* + metrics + strategy factor + discoverer + opts + events + */ +} + +impl Registry { + pub fn new(broker: Arc) -> Self { + let logger = &broker.logger; + let logger = Arc::clone(&logger); + todo!() + } + + fn init() { + todo!("initialze discoverer") + } + fn stop() { + todo!("stop discoverre") + } + + fn register_moleculer_metrics(&self) { + todo!("register molecular metrics") + } + fn update_metrics(&self) { + todo!("update metrics") + } + pub fn register_local_service(svc: Service) { + todo!("after service has been done") + } + pub fn register_services() { + todo!("add remote serice support") + } + fn check_action_visibility(action: &Action, node: &Arc) -> bool { + match action.visibility { + Visibility::Published => true, + Visibility::Public => true, + Visibility::Protected => node.local, + _ => false, + } + } + fn register_actions() { + todo!() + } + fn create_private_action_endpoint(action: Action) { + todo!() + } + pub fn has_services(&self, full_name: &str, node_id: Option<&str>) -> bool { + self.services.has(full_name, node_id) + } + pub fn get_action_endpoints(&self, action_name: &str) -> Option<&EndpointList> { + self.actions.get(action_name) + } + pub fn get_action_endpoint_by_node_id( + &self, + action_name: &str, + node_id: &str, + ) -> Option<&EndpointList> { + let list = self.actions.get(action_name); + if let Some(list) = list { + list.get_endpoint_by_node_id(node_id); + } + None + } + fn unregister_service(&mut self, full_name: &str, node_id: Option<&str>) { + let id = match node_id { + Some(node_id) => node_id.to_string(), + None => self.broker.node_id.clone(), + }; + self.services.remove(full_name, &id); + match node_id { + Some(id) => { + if id == self.broker.node_id { + self.regenerate_local_raw_info(true); + } + } + None => self.regenerate_local_raw_info(true), + } + } + fn unregister_service_by_node_id(&mut self, node_id: &str) { + self.services.remove_all_by_node_id(node_id); + } + fn unregiste_action(&mut self, node_id: &str, action_name: &str) { + self.actions.remove(action_name, node_id); + } + + fn register_events() { + todo!() + } + fn unregister_event(&mut self, node_id: &str, event_name: &str) { + todo!() + } + + fn regenerate_local_raw_info(&self, incSeq: bool) { + todo!() + } + + fn get_local_node_info(&self, force: bool) { + todo!() + } + fn get_node_info(&self, node_id: &str) -> Option { + todo!() + } + fn process_node_info(&self) { + todo!() + } + fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { + self.nodes.list(only_available, with_services) + } + fn get_services_list(&self)->Vec<&ServiceItem>{ + todo!() + } + fn get_actions_list(&self)->Vec<&ActionEndpoint>{ + todo!() + } + fn get_event_list(&self)->Vec<&EventEndpoint>{ + todo!() + } + fn get_node_raw_list(&self){ + todo!() + } +} diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 8847db3..9499b7b 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,5 +1,6 @@ use super::*; +#[derive(PartialEq, Eq)] pub struct ServiceCatalog { registry: Arc, broker: Arc, @@ -51,7 +52,7 @@ impl ServiceCatalog { todo!() } //remove all endpoints by node_id. - pub fn remove_by_node_id(&mut self, node_id: &str) { + pub fn remove_all_by_node_id(&mut self, node_id: &str) { let services: Vec<&ServiceItem> = self .services .iter() @@ -66,9 +67,9 @@ impl ServiceCatalog { todo!("updat the service") } - pub fn remove(&mut self, full_name: &str, node_id: Option<&str>) { + pub fn remove(&mut self, full_name: &str, node_id: &str) { self.services.retain(|svc| { - if svc.equals(full_name, node_id) { + if svc.equals(full_name, Some(node_id)) { todo!("remove actions and events in registry"); return false; diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs index 9f2f206..ca52e2c 100644 --- a/src/strategies/mod.rs +++ b/src/strategies/mod.rs @@ -1,10 +1,11 @@ use std::sync::Arc; -use crate::registry::{ActionEndpoint, Broker, Registry}; +use crate::registry::{ActionEndpoint, Broker, Registry , Opts}; mod round_robin; -trait Strategy { - fn new(registry: Arc, broker: Arc, opts: Opts) -> Self; + +pub trait Strategy { + fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self; fn select<'a>( &mut self, list: Vec<&'a ActionEndpoint>, @@ -12,5 +13,6 @@ trait Strategy { ) -> Option<&'a ActionEndpoint>; } -struct Context {} -struct Opts {} +pub struct Context {} + +pub struct StrategyOpts{} \ No newline at end of file diff --git a/src/strategies/round_robin.rs b/src/strategies/round_robin.rs index 459579f..bb7b6c3 100644 --- a/src/strategies/round_robin.rs +++ b/src/strategies/round_robin.rs @@ -4,7 +4,7 @@ use std::sync::Arc; struct RoundRobinStrategy { registry: Arc, broker: Arc, - opts: Opts, + opts: StrategyOpts, counter: usize, } @@ -12,7 +12,7 @@ impl RoundRobinStrategy { // fn new() -> Self {} } impl Strategy for RoundRobinStrategy { - fn new(registry: Arc, broker: Arc, opts: Opts) -> Self { + fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self { Self { broker, registry, From 1e3e5fb376ca847093db79d979e77a7a73828717 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 29 Jan 2022 22:05:19 +0530 Subject: [PATCH 08/22] Service class work start --- src/lib.rs | 3 +- src/registry/mod.rs | 29 ++++++--- src/service.rs | 144 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 src/service.rs diff --git a/src/lib.rs b/src/lib.rs index de71c00..861566c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod registry; -pub mod strategies; \ No newline at end of file +pub mod strategies; +pub mod service; \ No newline at end of file diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 888a93b..73b605c 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -11,6 +11,7 @@ pub mod service_item; use std::collections::HashMap; use std::sync::Arc; +use super::service::Service; use crate::strategies::Strategy; use action_catalog::ActionCatalog; pub use action_endpoint::ActionEndpoint; @@ -39,8 +40,25 @@ trait FnType {} #[derive(PartialEq, Eq, Clone)] pub struct Action { - name: String, + pub name: String, visibility: Visibility, + handler: fn(), + service: Option, +} + +impl Action { + pub fn new(name: String, handler: fn()) -> Self { + Self { + name, + visibility: Visibility::Protected, + handler, + service: None, + } + } + pub fn set_service(mut self , service : Service)->Action{ + self.service = Some(service); + self + } } #[derive(PartialEq, Eq, Clone)] @@ -111,15 +129,6 @@ enum EndpointType { Event, } -pub struct Service { - name: String, - full_name: String, - version: String, - /* - settings , - metadata - */ -} #[derive(PartialEq, Eq)] pub struct Opts { strategy: T, diff --git a/src/service.rs b/src/service.rs new file mode 100644 index 0000000..3e516d7 --- /dev/null +++ b/src/service.rs @@ -0,0 +1,144 @@ +use std::{collections::HashMap, sync::Arc}; + +use chrono::Duration; + +use crate::registry::{Action, Logger, Event}; + +#[derive(PartialEq, Eq, Clone)] +pub struct Service { + pub name: String, + pub full_name: String, + pub version: String, + settings: HashMap, + logger: Arc, + schema: Schema, + original_schema: Option, + metadata: HashMap, + actions : HashMap, + events : HashMap +} +#[derive(PartialEq, Eq, Clone)] +struct Schema { + mixins: Option>, + actions: Option>, + events: Option>, + merged: SchemaMerged, + name: Option, + version: Option, + settings: HashMap, + metadata: Option>, +} + +#[derive(PartialEq, Eq, Clone)] +struct SchemaMixins {} + +#[derive(PartialEq, Eq, Clone)] +struct SchemaActions {} + +#[derive(PartialEq, Eq, Clone)] +struct SchemaEvents {} +#[derive(PartialEq, Eq, Clone)] +enum SchemaMerged { + MergedFn(fn()), + MergedFnVec(Vec), +} + +impl Service { + fn parse_service_schema(&mut self, schema: Schema) { + self.original_schema = Some(schema.clone()); + + match schema.merged { + SchemaMerged::MergedFn(func) => { + + //TODO research about functions + } + SchemaMerged::MergedFnVec(func_vec) => { + for func in func_vec { + //TODO resarch more about functions + } + } + } + + if let None = schema.name { + //TODO throw error if no name available + } + self.name = schema.name.unwrap().clone(); + self.version = match schema.version { + Some(v) => v, + None => "0.0.1".to_string(), + }; + self.settings = schema.settings; + self.metadata = match schema.metadata { + Some(metadata) => metadata, + None => HashMap::new(), + }; + //TODO: + //self.schema = schema; + let version = self.settings.get("$noVersionPrefix"); + + self.full_name = Service::get_versioned_full_name(&self.name, version); + //TODO: get the logger from the broker. + //self.logger = + + + + //TODO:register methods. + + + + + + todo!("add service specification") + + + } + + fn init() { + todo!("call broker to initialise the service and call the init method of service") + } + + fn start() { + todo!("call the broker to start the services and call the start method of services") + } + + fn stop() { + todo!("call the broker to stop the service and call the stop method of service") + } + + fn create_action(&self, action_def: fn(), name: &str) -> Action { + let mut action = Action::new(name.to_string(), action_def); + let name_prefix = self.settings.get("$noServiceNamePrefix"); + if let Some(name_prefix) = name_prefix { + let name_prefix: bool = name_prefix.parse().unwrap(); + if name_prefix { + action.name = format!("{}.{}", self.full_name.to_string(), action.name); + } + } + //TODO add caching settings from settins + //TODO better way to handle this instead of clone. + action = action.set_service(self.clone()); + action + } + + /// create an interal service method. + fn create_method() { + todo!() + } + + ///create an event subscription for broker + fn create_event() { + todo!() + } + + fn wait_for_services(&self, service_names: Vec, timout: Duration, interval: Duration) { + todo!("call broker to wait for services") + } + + fn get_versioned_full_name(name: &str, version: Option<&String>) -> String { + let mut name = name.to_string(); + if let Some(v) = version { + name = format!("{}.{}", v, name); + } + name + } +} From 56533e1d0a02b2c3370af18cd2a77788fb798357 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 29 Jan 2022 23:49:23 +0530 Subject: [PATCH 09/22] broker renamed --- Cargo.lock | 106 ++++++++++++++++++++++++++++++++ Cargo.toml | 4 +- src/broker.rs | 47 ++++++++++++++ src/packet.rs | 0 src/registry/action_catalog.rs | 4 +- src/registry/action_endpoint.rs | 2 +- src/registry/endpoint_list.rs | 4 +- src/registry/event_endpoint.rs | 2 +- src/registry/mod.rs | 8 +-- src/registry/node_catalog.rs | 6 +- src/registry/registry.rs | 4 +- src/registry/service_catalog.rs | 4 +- src/strategies/mod.rs | 4 +- src/strategies/round_robin.rs | 4 +- 14 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 src/broker.rs create mode 100644 src/packet.rs diff --git a/Cargo.lock b/Cargo.lock index 53e1b5c..3609b14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,38 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.19" @@ -21,17 +47,62 @@ dependencies = [ "winapi", ] +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "libc" version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "molecular-rust" version = "0.1.0" dependencies = [ "chrono", + "env_logger", + "log", ] [[package]] @@ -53,6 +124,32 @@ dependencies = [ "autocfg", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "time" version = "0.1.44" @@ -86,6 +183,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 42b3536..30cf703 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "0.4.19" \ No newline at end of file +chrono = "0.4.19" +env_logger = "0.9.0" +log= "0.4.14" \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs new file mode 100644 index 0000000..03ecdce --- /dev/null +++ b/src/broker.rs @@ -0,0 +1,47 @@ +use std::{ + collections::HashMap, + sync::mpsc::{Receiver, Sender}, +}; + +use chrono::{DateTime, Utc}; + +use crate::{Registry, Service}; + +struct ServiceBroker { + reciever: Receiver, + started: bool, + namespace: Option, + metdata: HashMap, + node_id: String, + instance: String, + services: Vec, + /* + local bus + options + logger + metricss + middlewere + cacher + serializer + error generator + validator + tracer + transporter + */ + registry: Option, +} + +impl ServiceBroker { + fn start(&mut self) { + let time = Utc::now(); + self.started = true; + + } + + fn add_local_service(&mut self , service : Service){ + self.services.push(service); + } + +} + +enum ServiceBrokerAction {} diff --git a/src/packet.rs b/src/packet.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index 75ef4a4..a0f5530 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -5,14 +5,14 @@ use super::*; #[derive(PartialEq, Eq)] pub struct ActionCatalog { registry: Arc, - broker: Arc, + broker: Arc, logger: Arc, actions: ActionsMap, } impl ActionCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { + pub fn new(registry: Arc, broker: Arc) -> Self { let logger = ®istry.logger; let logger = Arc::clone(&logger); diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 8053907..da27e2d 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -14,7 +14,7 @@ impl EndpointTrait for ActionEndpoint { } fn new( registry: Arc, - broker: Arc, + broker: Arc, node: Arc, service: Arc, data: Self::Data, diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index 0129472..b9068e8 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -4,7 +4,7 @@ use super::*; #[derive(PartialEq, Eq, Clone)] pub struct EndpointList { registry: Arc, - broker: Arc, + broker: Arc, pub name: String, group: Option, internal: bool, @@ -15,7 +15,7 @@ use super::*; impl EndpointList { pub fn new( registry: Arc, - broker: Arc, + broker: Arc, name: String, group: Option, ) -> Self { diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs index cb4d106..c14702e 100644 --- a/src/registry/event_endpoint.rs +++ b/src/registry/event_endpoint.rs @@ -13,7 +13,7 @@ impl EndpointTrait for EventEndpoint { } fn new( registry: Arc, - broker: Arc, + broker: Arc, node: Arc, service: Arc, data: Self::Data, diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 73b605c..877c129 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -29,7 +29,7 @@ type ActionsMap = HashMap>; #[derive(PartialEq, Eq)] pub struct Logger {} #[derive(PartialEq, Eq)] -pub struct Broker { +pub struct ServiceBroker { node_id: String, instance_id: String, moleculer_version: String, @@ -78,7 +78,7 @@ pub trait EndpointTrait { type Data; fn new( registry: Arc, - broker: Arc, + broker: Arc, node: Arc, service: Arc, data: Self::Data, @@ -95,7 +95,7 @@ pub trait EndpointTrait { #[derive(PartialEq, Eq, Clone)] struct Endpoint { registry: Arc, - broker: Arc, + broker: Arc, node: Arc, service: Arc, state: bool, @@ -106,7 +106,7 @@ struct Endpoint { impl Endpoint { fn new( registry: Arc, - broker: Arc, + broker: Arc, node: Arc, service: Arc, ) -> Self { diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index b8998fb..54974fa 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -1,17 +1,17 @@ use std::{collections::HashMap, net::IpAddr, sync::Arc}; -use super::{node, Broker, Client, Logger, Node, Registry}; +use super::{node, ServiceBroker, Client, Logger, Node, Registry}; #[derive(PartialEq, Eq)] pub struct NodeCatalog { registry: Arc, - broker: Arc, + broker: Arc, logger: Arc, nodes: HashMap, local_node: Option, } impl NodeCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { + pub fn new(registry: Arc, broker: Arc) -> Self { let logger = ®istry.logger; let logger = Arc::clone(&logger); Self { diff --git a/src/registry/registry.rs b/src/registry/registry.rs index f54905b..035b35c 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -2,7 +2,7 @@ use super::*; #[derive(PartialEq, Eq)] pub struct Registry { pub logger: Arc, - broker: Arc, + broker: Arc, nodes: NodeCatalog, services: ServiceCatalog, actions: ActionCatalog, @@ -16,7 +16,7 @@ pub struct Registry { } impl Registry { - pub fn new(broker: Arc) -> Self { + pub fn new(broker: Arc) -> Self { let logger = &broker.logger; let logger = Arc::clone(&logger); todo!() diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 9499b7b..06644e0 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -3,13 +3,13 @@ use super::*; #[derive(PartialEq, Eq)] pub struct ServiceCatalog { registry: Arc, - broker: Arc, + broker: Arc, logger: Arc, services: Vec, } impl ServiceCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { + pub fn new(registry: Arc, broker: Arc) -> Self { let logger = ®istry.logger; let logger = Arc::clone(&logger); Self { diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs index ca52e2c..4b7b873 100644 --- a/src/strategies/mod.rs +++ b/src/strategies/mod.rs @@ -1,11 +1,11 @@ use std::sync::Arc; -use crate::registry::{ActionEndpoint, Broker, Registry , Opts}; +use crate::registry::{ActionEndpoint, ServiceBroker, Registry , Opts}; mod round_robin; pub trait Strategy { - fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self; + fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self; fn select<'a>( &mut self, list: Vec<&'a ActionEndpoint>, diff --git a/src/strategies/round_robin.rs b/src/strategies/round_robin.rs index bb7b6c3..b61ae23 100644 --- a/src/strategies/round_robin.rs +++ b/src/strategies/round_robin.rs @@ -3,7 +3,7 @@ use std::sync::Arc; struct RoundRobinStrategy { registry: Arc, - broker: Arc, + broker: Arc, opts: StrategyOpts, counter: usize, } @@ -12,7 +12,7 @@ impl RoundRobinStrategy { // fn new() -> Self {} } impl Strategy for RoundRobinStrategy { - fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self { + fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self { Self { broker, registry, From 066220dca1690714c1524eda9d6235614358c83d Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sun, 30 Jan 2022 17:23:09 +0530 Subject: [PATCH 10/22] service broker init --- Cargo.lock | 37 +++++++++++++++++++++++ Cargo.toml | 4 ++- src/broker.rs | 64 ++++++++++++++++++++++++++++++++++++---- src/lib.rs | 7 ++++- src/logger.rs | 7 +++++ src/packet.rs | 23 +++++++++++++++ src/registry/registry.rs | 12 ++++---- src/service.rs | 24 +++++---------- 8 files changed, 149 insertions(+), 29 deletions(-) create mode 100644 src/logger.rs diff --git a/Cargo.lock b/Cargo.lock index 3609b14..ef91d5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" + [[package]] name = "atty" version = "0.2.14" @@ -75,6 +81,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "libc" version = "0.2.114" @@ -100,9 +112,11 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" name = "molecular-rust" version = "0.1.0" dependencies = [ + "anyhow", "chrono", "env_logger", "log", + "serde_json", ] [[package]] @@ -141,6 +155,29 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" + +[[package]] +name = "serde_json" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "termcolor" version = "1.1.2" diff --git a/Cargo.toml b/Cargo.toml index 30cf703..f252c4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,6 @@ edition = "2021" [dependencies] chrono = "0.4.19" env_logger = "0.9.0" -log= "0.4.14" \ No newline at end of file +log= "0.4.14" +serde_json = "1.0.0" +anyhow = "1.0.53" \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs index 03ecdce..fa2941d 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,11 +1,14 @@ use std::{ + any, collections::HashMap, sync::mpsc::{Receiver, Sender}, }; +use anyhow::{bail, Error, Result}; + use chrono::{DateTime, Utc}; -use crate::{Registry, Service}; +use crate::{registry::service_item::ServiceItem, service, Registry, Service}; struct ServiceBroker { reciever: Receiver, @@ -28,20 +31,71 @@ struct ServiceBroker { tracer transporter */ - registry: Option, + registry: Registry, } impl ServiceBroker { fn start(&mut self) { let time = Utc::now(); self.started = true; - } - fn add_local_service(&mut self , service : Service){ + fn add_local_service(&mut self, service: Service) { self.services.push(service); } - + fn register_local_service(&mut self, service: ServiceItem) { + self.registry.register_local_service(service); + } + + fn destroy_service(&mut self, name: &str, version: &str) -> Result<()> { + let service_index = self.get_local_service_index(name, version); + if let None = service_index { + bail!( + "no service with the name {} and version {} found", + name, + version + ); + } + let service_index = service_index.unwrap(); + let mut full_name = "".to_string(); + + { + let service = self.services.get_mut(service_index).unwrap(); + full_name = service.full_name.clone(); + service.stop(); + } + { + self.services.remove(service_index); + } + + self.registry + .unregister_service(&full_name, Some(&self.node_id)); + self.services_changed(true); + Ok(()) + } + + fn services_changed(&self, local_service: bool) { + if (self.started && local_service) { + todo!("notifify remote nodes") + } + } + fn get_local_service_index(&self, name: &str, version: &str) -> Option { + self.services.iter().position(|s| { + if s.name == name && s.version == version { + return true; + } + return false; + }) + } } enum ServiceBrokerAction {} + +fn remove_from_list(list: &mut Vec, value: &T) { + list.retain(|t| { + if t == value { + return false; + } + return true; + }); +} diff --git a/src/lib.rs b/src/lib.rs index 861566c..a3c42b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,8 @@ pub mod registry; pub mod strategies; -pub mod service; \ No newline at end of file +pub mod service; +pub mod broker; +pub mod logger; +pub mod packet; +pub use service::Service; +pub use registry::Registry; diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..5ae7983 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,7 @@ +use log::{debug, error, info, log_enabled, Level}; + +trait LoggerTrait { + fn init(); + fn stop(); + fn get_log_handler(); +} diff --git a/src/packet.rs b/src/packet.rs index e69de29..036a771 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -0,0 +1,23 @@ +use core::fmt; + + + + +enum PacketType { + Unknown, + Event, + Request, + Response, + Discover, + Info , + Disconnect , + Heartbeat, + Ping, + Pong, +} + +impl From for String { + fn from(p: PacketType) -> Self { + "as".to_string() + } +} diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 035b35c..6f70b5a 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -35,7 +35,7 @@ impl Registry { fn update_metrics(&self) { todo!("update metrics") } - pub fn register_local_service(svc: Service) { + pub fn register_local_service(&mut self, svc: ServiceItem) { todo!("after service has been done") } pub fn register_services() { @@ -72,7 +72,7 @@ impl Registry { } None } - fn unregister_service(&mut self, full_name: &str, node_id: Option<&str>) { + pub fn unregister_service(&mut self, full_name: &str, node_id: Option<&str>) { let id = match node_id { Some(node_id) => node_id.to_string(), None => self.broker.node_id.clone(), @@ -117,16 +117,16 @@ impl Registry { fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { self.nodes.list(only_available, with_services) } - fn get_services_list(&self)->Vec<&ServiceItem>{ + fn get_services_list(&self) -> Vec<&ServiceItem> { todo!() } - fn get_actions_list(&self)->Vec<&ActionEndpoint>{ + fn get_actions_list(&self) -> Vec<&ActionEndpoint> { todo!() } - fn get_event_list(&self)->Vec<&EventEndpoint>{ + fn get_event_list(&self) -> Vec<&EventEndpoint> { todo!() } - fn get_node_raw_list(&self){ + fn get_node_raw_list(&self) { todo!() } } diff --git a/src/service.rs b/src/service.rs index 3e516d7..ece0895 100644 --- a/src/service.rs +++ b/src/service.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, sync::Arc}; use chrono::Duration; -use crate::registry::{Action, Logger, Event}; +use crate::registry::{Action, Event, Logger}; #[derive(PartialEq, Eq, Clone)] pub struct Service { @@ -14,8 +14,8 @@ pub struct Service { schema: Schema, original_schema: Option, metadata: HashMap, - actions : HashMap, - events : HashMap + actions: HashMap, + events: HashMap, } #[derive(PartialEq, Eq, Clone)] struct Schema { @@ -75,33 +75,25 @@ impl Service { //TODO: //self.schema = schema; let version = self.settings.get("$noVersionPrefix"); - + self.full_name = Service::get_versioned_full_name(&self.name, version); //TODO: get the logger from the broker. - //self.logger = - - + //self.logger = //TODO:register methods. - - - - todo!("add service specification") - - } - fn init() { + pub fn init(&mut self) { todo!("call broker to initialise the service and call the init method of service") } - fn start() { + pub fn start(&mut self) { todo!("call the broker to start the services and call the start method of services") } - fn stop() { + pub fn stop(&mut self) { todo!("call the broker to stop the service and call the stop method of service") } From e3003d1e9cd6854b93bf88bc92f235e629ad5154 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Tue, 1 Feb 2022 10:38:44 +0530 Subject: [PATCH 11/22] removed broker and registry dependecies on catalogs --- Cargo.lock | 16 ++++++++++++++++ Cargo.toml | 3 ++- src/broker.rs | 6 ++++-- src/packet.rs | 9 +++------ src/registry/action_catalog.rs | 19 ++----------------- src/registry/action_endpoint.rs | 10 ++-------- src/registry/endpoint_list.rs | 27 ++++++--------------------- src/registry/event_endpoint.rs | 10 ++-------- src/registry/mod.rs | 23 ++++------------------- src/registry/node_catalog.rs | 21 ++++++++------------- src/registry/registry.rs | 9 +++++++-- src/registry/service_catalog.rs | 10 +--------- src/registry/service_item.rs | 2 +- 13 files changed, 58 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef91d5c..754678a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,7 @@ dependencies = [ "env_logger", "log", "serde_json", + "tokio", ] [[package]] @@ -138,6 +139,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + [[package]] name = "regex" version = "1.5.4" @@ -198,6 +205,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" +dependencies = [ + "pin-project-lite", +] + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index f252c4b..5a05252 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ chrono = "0.4.19" env_logger = "0.9.0" log= "0.4.14" serde_json = "1.0.0" -anyhow = "1.0.53" \ No newline at end of file +anyhow = "1.0.53" +tokio = "1.16.1" \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs index fa2941d..cc0bff4 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -11,7 +11,7 @@ use chrono::{DateTime, Utc}; use crate::{registry::service_item::ServiceItem, service, Registry, Service}; struct ServiceBroker { - reciever: Receiver, + reciever: Receiver, started: bool, namespace: Option, metdata: HashMap, @@ -89,7 +89,9 @@ impl ServiceBroker { } } -enum ServiceBrokerAction {} +enum ServiceBrokerMessage { + +} fn remove_from_list(list: &mut Vec, value: &T) { list.retain(|t| { diff --git a/src/packet.rs b/src/packet.rs index 036a771..a0d7749 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,19 +1,16 @@ use core::fmt; - - - enum PacketType { Unknown, Event, Request, Response, Discover, - Info , - Disconnect , + Info, + Disconnect, Heartbeat, Ping, - Pong, + Pongs, } impl From for String { diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index a0f5530..4b6919c 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -4,22 +4,12 @@ use super::*; #[derive(PartialEq, Eq)] pub struct ActionCatalog { - registry: Arc, - broker: Arc, - - logger: Arc, actions: ActionsMap, } impl ActionCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { - let logger = ®istry.logger; - let logger = Arc::clone(&logger); - + pub fn new() -> Self { Self { - registry, - broker, - logger, actions: HashMap::new(), } } @@ -29,12 +19,7 @@ impl ActionCatalog { Some(list) => list.add(node, service, action), None => { let name = action.name.clone(); - let mut list = EndpointList::new( - Arc::clone(&self.registry), - Arc::clone(&self.broker), - name, - None, - ); + let mut list = EndpointList::new(name, None); let name = action.name.clone(); list.add(node, service, action); self.actions.insert(name, list); diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index da27e2d..1d9cc7a 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -12,14 +12,8 @@ impl EndpointTrait for ActionEndpoint { fn update(&mut self, data: Self::Data) { self.action = data; } - fn new( - registry: Arc, - broker: Arc, - node: Arc, - service: Arc, - data: Self::Data, - ) -> Self { - let endpoint = Endpoint::new(registry, broker, node, service); + fn new(node: Arc, service: Arc, data: Self::Data) -> Self { + let endpoint = Endpoint::new(node, service); let name = format!("{}:{}", endpoint.id, data.name); Self { endpoint, diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index b9068e8..59f61cd 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -2,9 +2,7 @@ use std::sync::Arc; use super::*; #[derive(PartialEq, Eq, Clone)] - pub struct EndpointList { - registry: Arc, - broker: Arc, +pub struct EndpointList { pub name: String, group: Option, internal: bool, @@ -12,20 +10,13 @@ use super::*; local_endpoints: Vec, } -impl EndpointList { - pub fn new( - registry: Arc, - broker: Arc, - name: String, - group: Option, - ) -> Self { +impl EndpointList { + pub fn new(name: String, group: Option) -> Self { let internal = name.starts_with("$"); let endpoints = Vec::new(); let local_endpoints = Vec::new(); Self { - registry, - broker, name, group, endpoints, @@ -34,7 +25,7 @@ impl EndpointList { } } - pub fn add(&mut self, node: Arc, service: Arc, data:T::Data ) { + pub fn add(&mut self, node: Arc, service: Arc, data: T::Data) { let entry = self .endpoints .iter_mut() @@ -48,13 +39,7 @@ impl EndpointList { None => {} } - let ep = T::new( - Arc::clone(&self.registry), - Arc::clone(&self.broker), - Arc::clone(&node), - Arc::clone(&service), - data, - ); + let ep = T::new(Arc::clone(&node), Arc::clone(&service), data); self.endpoints.push(ep.clone()); if ep.is_local() { @@ -103,7 +88,7 @@ impl EndpointList { fn count(&self) -> usize { self.endpoints.len() } - pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { + pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { self.endpoints .iter() .find(|e| e.id() == node_id && e.is_available()) diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs index c14702e..d8cd7d6 100644 --- a/src/registry/event_endpoint.rs +++ b/src/registry/event_endpoint.rs @@ -11,14 +11,8 @@ impl EndpointTrait for EventEndpoint { fn update(&mut self, data: Self::Data) { self.event = data; } - fn new( - registry: Arc, - broker: Arc, - node: Arc, - service: Arc, - data: Self::Data, - ) -> Self { - let endpoint = Endpoint::new(registry, broker, node, service); + fn new(node: Arc, service: Arc, data: Self::Data) -> Self { + let endpoint = Endpoint::new(node, service); Self { endpoint, diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 877c129..e6c8b3f 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -55,7 +55,7 @@ impl Action { service: None, } } - pub fn set_service(mut self , service : Service)->Action{ + pub fn set_service(mut self, service: Service) -> Action { self.service = Some(service); self } @@ -76,13 +76,7 @@ impl FnType for Event {} pub trait EndpointTrait { ///Data is eiter an Action struct or Event structs type Data; - fn new( - registry: Arc, - broker: Arc, - node: Arc, - service: Arc, - data: Self::Data, - ) -> Self; + fn new(node : Arc , service: Arc, data: Self::Data) -> Self; fn node(&self) -> &Node; fn service(&self) -> &ServiceItem; fn update(&mut self, data: Self::Data); @@ -94,8 +88,6 @@ pub trait EndpointTrait { #[derive(PartialEq, Eq, Clone)] struct Endpoint { - registry: Arc, - broker: Arc, node: Arc, service: Arc, state: bool, @@ -104,17 +96,10 @@ struct Endpoint { } impl Endpoint { - fn new( - registry: Arc, - broker: Arc, - node: Arc, - service: Arc, - ) -> Self { - let local = node.id == broker.node_id; + fn new(node: Arc, service: Arc) -> Self { let id = node.id.to_string(); + let local = service.local; Self { - registry, - broker, node, service, state: true, diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index 54974fa..54f01c6 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -4,35 +4,30 @@ use super::{node, ServiceBroker, Client, Logger, Node, Registry}; #[derive(PartialEq, Eq)] pub struct NodeCatalog { - registry: Arc, - broker: Arc, - logger: Arc, + nodes: HashMap, local_node: Option, } impl NodeCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { - let logger = ®istry.logger; - let logger = Arc::clone(&logger); + pub fn new() -> Self { + Self { - broker, - logger, - registry, + nodes: HashMap::new(), local_node: None, } } ///Create a local node - fn create_local_node(&mut self) -> Node { + fn create_local_node(&mut self , version : String , node_id : String , instance_id : String) -> Node { let client = Client { client_type: "rust".to_string(), lang_version: "1.56.1".to_string(), - version: self.broker.moleculer_version.clone(), + version: version }; - let node = Node::new(self.broker.node_id.clone()) + let node = Node::new(node_id) .set_local(true) .set_ip_list(get_ip_list()) - .set_instance_id(self.broker.instance_id.clone()) + .set_instance_id(instance_id) .set_hostname(get_hostname()) .set_seq(1) .set_client(client); diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 6f70b5a..92ee670 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,8 +1,13 @@ +use crate::ServiceBrokerMessage; + use super::*; -#[derive(PartialEq, Eq)] +use tokio::sync::mpsc::{Sender}; + + pub struct Registry { pub logger: Arc, - broker: Arc, + broker_sender: Sender, + broker : Arc, nodes: NodeCatalog, services: ServiceCatalog, actions: ActionCatalog, diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 06644e0..72e9c3b 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -2,20 +2,12 @@ use super::*; #[derive(PartialEq, Eq)] pub struct ServiceCatalog { - registry: Arc, - broker: Arc, - logger: Arc, services: Vec, } impl ServiceCatalog { - pub fn new(registry: Arc, broker: Arc) -> Self { - let logger = ®istry.logger; - let logger = Arc::clone(&logger); + pub fn new() -> Self { Self { - broker, - registry, - logger, services: Vec::new(), } } diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index 5332fcb..216346d 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -4,7 +4,7 @@ use super::*; pub struct ServiceItem { pub name: String, pub node: Arc, - local: bool, + pub local: bool, full_name: String, version: String, actions: ActionsMap, From 64b2b56848161969a48057fb8d3a433925cfe538 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Thu, 3 Feb 2022 23:51:09 +0530 Subject: [PATCH 12/22] registry prototype --- Cargo.lock | 196 ++++++++++++++++++++++++++++++++ Cargo.toml | 4 +- src/broker.rs | 16 ++- src/lib.rs | 2 + src/registry/action_catalog.rs | 37 +++++- src/registry/action_endpoint.rs | 2 +- src/registry/endpoint_list.rs | 6 +- src/registry/mod.rs | 29 +++-- src/registry/node.rs | 8 +- src/registry/node_catalog.rs | 22 ++-- src/registry/registry.rs | 81 +++++++++---- src/registry/service_catalog.rs | 42 +++++-- src/registry/service_item.rs | 4 +- src/service.rs | 9 +- src/strategies/mod.rs | 3 +- 15 files changed, 393 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 754678a..d62240c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cfg-if" version = "1.0.0" @@ -81,18 +93,42 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -108,6 +144,28 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + [[package]] name = "molecular-rust" version = "0.1.0" @@ -115,11 +173,22 @@ dependencies = [ "anyhow", "chrono", "env_logger", + "lazy_static", "log", + "regex", "serde_json", "tokio", ] +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -139,12 +208,80 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pin-project-lite" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -168,6 +305,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.136" @@ -185,6 +328,32 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -211,9 +380,36 @@ version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 5a05252..66202d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,6 @@ env_logger = "0.9.0" log= "0.4.14" serde_json = "1.0.0" anyhow = "1.0.53" -tokio = "1.16.1" \ No newline at end of file +tokio = { version = "1.16.1", features = ["full"] } +regex = "1.5.4" +lazy_static = "1.3.0" \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs index cc0bff4..6950b77 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,23 +1,25 @@ use std::{ any, collections::HashMap, - sync::mpsc::{Receiver, Sender}, + sync::{mpsc::{Receiver, Sender}, Arc}, }; use anyhow::{bail, Error, Result}; use chrono::{DateTime, Utc}; -use crate::{registry::service_item::ServiceItem, service, Registry, Service}; +use crate::{registry::{service_item::ServiceItem, Logger}, service, Registry, Service}; -struct ServiceBroker { +pub struct ServiceBroker { reciever: Receiver, started: bool, namespace: Option, metdata: HashMap, - node_id: String, + pub node_id: String, instance: String, services: Vec, + pub transit : Option, + pub logger : Arc, /* local bus options @@ -34,6 +36,8 @@ struct ServiceBroker { registry: Registry, } +pub struct Transit{} + impl ServiceBroker { fn start(&mut self) { let time = Utc::now(); @@ -43,7 +47,7 @@ impl ServiceBroker { fn add_local_service(&mut self, service: Service) { self.services.push(service); } - fn register_local_service(&mut self, service: ServiceItem) { + fn register_local_service(&mut self, service: Service) { self.registry.register_local_service(service); } @@ -89,7 +93,7 @@ impl ServiceBroker { } } -enum ServiceBrokerMessage { +pub enum ServiceBrokerMessage { } diff --git a/src/lib.rs b/src/lib.rs index a3c42b1..a33a840 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,3 +6,5 @@ pub mod logger; pub mod packet; pub use service::Service; pub use registry::Registry; +pub use broker::ServiceBrokerMessage; +pub use broker::ServiceBroker; \ No newline at end of file diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index 4b6919c..3675d77 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -13,7 +13,7 @@ impl ActionCatalog { actions: HashMap::new(), } } - fn add(&mut self, node: Arc, service: Arc, action: Action) { + pub fn add(&mut self, node: Arc, service: Arc, action: Action) { let list = self.actions.get_mut(&action.name); match list { Some(list) => list.add(node, service, action), @@ -47,7 +47,38 @@ impl ActionCatalog { el.remove_by_node_id(node_id); } } - fn list(&self) { - todo!() + pub fn list(&self, opts: ListOptions) -> Vec<&EndpointList> { + let res: HashMap<&String, &EndpointList> = self + .actions + .iter() + .filter(|item| { + let (name, ep_list) = item; + if opts.skip_internal && get_internal_service_regex_match(&name) { + return false; + } + if opts.only_local && !ep_list.has_local() { + return false; + } + if opts.only_available && !ep_list.has_available() { + return false; + } + if ep_list.count() > 0 { + let ep = ep_list.endpoints.get(0); + if let Some(ep) = ep { + if ep.action.visibility == Visibility::Protected { + return false; + } + } + } + return true; + }) + .collect(); + let res = res + .values() + .map(|ep| { + return ep.to_owned(); + }) + .collect(); + res } } diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 1d9cc7a..948ba8c 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -3,7 +3,7 @@ use super::*; #[derive(PartialEq, Eq, Clone)] pub struct ActionEndpoint { endpoint: Endpoint, - action: Action, + pub action: Action, pub name: String, } diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index 59f61cd..f0d2715 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -6,7 +6,7 @@ pub struct EndpointList { pub name: String, group: Option, internal: bool, - endpoints: Vec, + pub endpoints: Vec, local_endpoints: Vec, } @@ -69,7 +69,7 @@ impl EndpointList { } return false; } - fn has_local(&self) -> bool { + pub fn has_local(&self) -> bool { self.local_endpoints.len() > 0 } @@ -85,7 +85,7 @@ impl EndpointList { drop(local); } - fn count(&self) -> usize { + pub fn count(&self) -> usize { self.endpoints.len() } pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { diff --git a/src/registry/mod.rs b/src/registry/mod.rs index e6c8b3f..3977e18 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -19,22 +19,27 @@ pub use endpoint_list::EndpointList; pub use event_endpoint::EventEndpoint; pub use node::{Client, Node}; use node_catalog::NodeCatalog; +use regex::Regex; pub use registry::Registry; use service_catalog::ServiceCatalog; use service_item::ServiceItem; +use lazy_static::lazy_static; // pub use event_endpoint::EventEndpoint; + type ActionsMap = HashMap>; +fn get_internal_service_regex_match(text: &str) -> bool { + lazy_static! { + static ref RE: Regex = Regex::new(r"^\$").unwrap(); + + } + RE.is_match(text) +} + + #[derive(PartialEq, Eq)] pub struct Logger {} -#[derive(PartialEq, Eq)] -pub struct ServiceBroker { - node_id: String, - instance_id: String, - moleculer_version: String, - logger: Arc, -} trait FnType {} @@ -76,7 +81,7 @@ impl FnType for Event {} pub trait EndpointTrait { ///Data is eiter an Action struct or Event structs type Data; - fn new(node : Arc , service: Arc, data: Self::Data) -> Self; + fn new(node: Arc, service: Arc, data: Self::Data) -> Self; fn node(&self) -> &Node; fn service(&self) -> &ServiceItem; fn update(&mut self, data: Self::Data); @@ -118,3 +123,11 @@ enum EndpointType { pub struct Opts { strategy: T, } +pub struct ListOptions { + only_local: bool, + only_available: bool, + skip_internal: bool, + with_actions: bool, + with_events: bool, + grouping: bool, +} diff --git a/src/registry/node.rs b/src/registry/node.rs index 2bd7fff..8fdc6ad 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -1,6 +1,7 @@ -use std::net::IpAddr; +use std::{net::IpAddr, sync::Arc}; use chrono::Duration; +use serde_json::Value; use super::ServiceItem; @@ -21,12 +22,12 @@ pub struct Node { port: Option, hostname: Option, udp_address: Option, + pub raw_info: Option, /* - raw_info cpu cpuseq */ - services: Vec, + pub services: Vec>, pub seq: usize, offline_since: Option, } @@ -39,6 +40,7 @@ impl Node { available: true, local: false, client: None, + raw_info: None, /* change this later with actual process uptime. */ diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index 54f01c6..be80799 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -1,28 +1,27 @@ use std::{collections::HashMap, net::IpAddr, sync::Arc}; -use super::{node, ServiceBroker, Client, Logger, Node, Registry}; +use std::sync::RwLock; + +use super::{node, Client, Logger, Node, Registry}; + -#[derive(PartialEq, Eq)] pub struct NodeCatalog { - nodes: HashMap, - local_node: Option, + pub local_node: Option>, } impl NodeCatalog { pub fn new() -> Self { - Self { - nodes: HashMap::new(), local_node: None, } } ///Create a local node - fn create_local_node(&mut self , version : String , node_id : String , instance_id : String) -> Node { + fn create_local_node(&mut self, version: String, node_id: String, instance_id: String) -> Arc { let client = Client { client_type: "rust".to_string(), lang_version: "1.56.1".to_string(), - version: version + version: version, }; let node = Node::new(node_id) .set_local(true) @@ -33,8 +32,10 @@ impl NodeCatalog { .set_client(client); self.nodes.insert(node.id.to_string(), node.clone()); - self.local_node = Some(node.clone()); - return node; + let node = Arc::new(node); + let node_c = Arc::clone(&node); + self.local_node = Some(node); + return node_c; todo!() /* node.metadata = self.broker.metadata.clone() @@ -119,3 +120,4 @@ fn get_ip_list() -> Vec { fn get_hostname() -> String { todo!() } + diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 92ee670..aa65ca6 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,16 +1,17 @@ -use crate::ServiceBrokerMessage; +use crate::{ServiceBrokerMessage, service::SchemaActions, ServiceBroker}; use super::*; -use tokio::sync::mpsc::{Sender}; - +use serde_json::Value; +use tokio::sync::mpsc::Sender; pub struct Registry { pub logger: Arc, broker_sender: Sender, - broker : Arc, + broker: Arc, nodes: NodeCatalog, services: ServiceCatalog, actions: ActionCatalog, + /* metrics strategy factor @@ -19,7 +20,6 @@ pub struct Registry { events */ } - impl Registry { pub fn new(broker: Arc) -> Self { let logger = &broker.logger; @@ -40,8 +40,26 @@ impl Registry { fn update_metrics(&self) { todo!("update metrics") } - pub fn register_local_service(&mut self, svc: ServiceItem) { - todo!("after service has been done") + pub fn register_local_service(&mut self, svc: Service) { + if !self + .services + .has(&svc.full_name, Some(&self.broker.node_id)) + { + let service = self.services.add( + Arc::clone(&self.nodes.local_node.as_ref().unwrap()), + &svc, + true, + ); + if let Some(actions) = svc.actions { + let local_node = Arc::clone(&self.nodes.local_node.as_ref().unwrap()); + self.register_actions(local_node , Arc::clone(&service) , actions); + } + if let Some(events) = svc.events { + self.register_events(); + } + //TODO:Add service to the local node. + //self.nodes.local_node.unwrap().services.push(Arc::clone(&service)); + } } pub fn register_services() { todo!("add remote serice support") @@ -54,8 +72,25 @@ impl Registry { _ => false, } } - fn register_actions() { - todo!() + fn register_actions(&mut self , node : Arc , service: Arc , actions : Vec) { + actions.iter().for_each(|action|{ + if !Registry::check_action_visibility(action, &node){ + return; + } + if node.local{ + //TODO:stuff with middleware and handlers. + + + }else if let Some(_) = self.broker.transit { + //TODO: for remote services + return; + } + let node = Arc::clone(&node); + let service = Arc::clone(&service); + self.actions.add(node, service, action.to_owned()); + //TODO: + //add the action to the service. + }); } fn create_private_action_endpoint(action: Action) { todo!() @@ -86,10 +121,10 @@ impl Registry { match node_id { Some(id) => { if id == self.broker.node_id { - self.regenerate_local_raw_info(true); + self.regenerate_local_raw_info(Some(true)); } } - None => self.regenerate_local_raw_info(true), + None => {self.regenerate_local_raw_info(Some(true));}, } } fn unregister_service_by_node_id(&mut self, node_id: &str) { @@ -99,19 +134,26 @@ impl Registry { self.actions.remove(action_name, node_id); } - fn register_events() { + fn register_events(&mut self) { todo!() } fn unregister_event(&mut self, node_id: &str, event_name: &str) { todo!() } - fn regenerate_local_raw_info(&self, incSeq: bool) { + fn regenerate_local_raw_info(&self, incSeq: Option)->Value { todo!() } - fn get_local_node_info(&self, force: bool) { - todo!() + fn get_local_node_info(&self, force: bool)->Value { + if let None = self.nodes.local_node{ + return self.regenerate_local_raw_info(None); + } + if force { + return self.regenerate_local_raw_info(None); + } + let value = self.nodes.local_node.as_ref().unwrap().raw_info.to_owned(); + value.unwrap() } fn get_node_info(&self, node_id: &str) -> Option { todo!() @@ -119,13 +161,14 @@ impl Registry { fn process_node_info(&self) { todo!() } - fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { + pub fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { self.nodes.list(only_available, with_services) } - fn get_services_list(&self) -> Vec<&ServiceItem> { - todo!() + pub fn get_services_list(&self, opts: ListOptions) -> Vec<&Arc> { + self.services.list(opts) } - fn get_actions_list(&self) -> Vec<&ActionEndpoint> { + fn get_actions_list(&self , opts:ListOptions) -> Vec<&ActionEndpoint> { + //self.actions.list(opts) todo!() } fn get_event_list(&self) -> Vec<&EventEndpoint> { diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 72e9c3b..8b8e83a 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,8 +1,8 @@ use super::*; - +use regex::Regex; #[derive(PartialEq, Eq)] pub struct ServiceCatalog { - services: Vec, + services: Vec>, } impl ServiceCatalog { @@ -12,9 +12,13 @@ impl ServiceCatalog { } } ///Add a new service - pub fn add(&mut self, node: Arc, service: Arc, local: bool) { + pub fn add(&mut self, node: Arc, service: &Service, local: bool) -> Arc { let service_item = ServiceItem::new(node, service, local); + let service_item = Arc::new(service_item); + + let item = Arc::clone(&service_item); self.services.push(service_item); + item } ///Check the service exsists pub fn has(&self, full_name: &str, node_id: Option<&str>) -> bool { @@ -27,25 +31,47 @@ impl ServiceCatalog { None => false, } } - pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&ServiceItem> { + pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&Arc> { self.services .iter() .find(|svc| svc.equals(full_name, node_id)) } - pub fn get_mut(&mut self, full_name: &str, node_id: Option<&str>) -> Option<&mut ServiceItem> { + pub fn get_mut( + &mut self, + full_name: &str, + node_id: Option<&str>, + ) -> Option<&mut Arc> { self.services .iter_mut() .find(|svc| svc.equals(full_name, node_id)) } - pub fn list(&self) { - todo!() + pub fn list( + &self, + opts : ListOptions + ) -> Vec<&Arc> { + + self.services.iter().filter(|svc| { + if opts.skip_internal && get_internal_service_regex_match(&svc.name) { + return false; + } + if opts.only_local && !svc.local { + return false; + } + if opts.only_available && !svc.node.available { + return false; + } + + return true; + }).collect() + // TODO:("implement grouping and all that stuff") + } pub fn get_local_node_service(&self) { todo!() } //remove all endpoints by node_id. pub fn remove_all_by_node_id(&mut self, node_id: &str) { - let services: Vec<&ServiceItem> = self + let services: Vec<&Arc> = self .services .iter() .filter(|svc| { diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index 216346d..9bdb3e1 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -5,7 +5,7 @@ pub struct ServiceItem { pub name: String, pub node: Arc, pub local: bool, - full_name: String, + pub full_name: String, version: String, actions: ActionsMap, /* @@ -15,7 +15,7 @@ pub struct ServiceItem { */ } impl ServiceItem { - pub fn new(node: Arc, service: Arc, local: bool) -> Self { + pub fn new(node: Arc, service: &Service, local: bool) -> Self { Self { node, local, diff --git a/src/service.rs b/src/service.rs index ece0895..ecd8982 100644 --- a/src/service.rs +++ b/src/service.rs @@ -14,8 +14,8 @@ pub struct Service { schema: Schema, original_schema: Option, metadata: HashMap, - actions: HashMap, - events: HashMap, + pub actions: Option>, + pub events: Option>, } #[derive(PartialEq, Eq, Clone)] struct Schema { @@ -33,7 +33,10 @@ struct Schema { struct SchemaMixins {} #[derive(PartialEq, Eq, Clone)] -struct SchemaActions {} +pub struct SchemaActions { + name:String, + handler:fn() +} #[derive(PartialEq, Eq, Clone)] struct SchemaEvents {} diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs index 4b7b873..6e71fa7 100644 --- a/src/strategies/mod.rs +++ b/src/strategies/mod.rs @@ -1,6 +1,7 @@ use std::sync::Arc; -use crate::registry::{ActionEndpoint, ServiceBroker, Registry , Opts}; +use crate::registry::{ActionEndpoint, Registry , Opts}; +use crate::ServiceBroker; mod round_robin; From 0be6872bd21fd2567a36881a2bb7861c7a9fa310 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Fri, 4 Feb 2022 00:44:37 +0530 Subject: [PATCH 13/22] service lifecycyle methods --- src/broker.rs | 29 ++++++-- src/registry/mod.rs | 12 +-- src/registry/registry.rs | 4 +- src/registry/service_catalog.rs | 4 +- src/registry/service_item.rs | 4 +- src/service.rs | 125 ++++++++++++++++++++++++++++---- 6 files changed, 146 insertions(+), 32 deletions(-) diff --git a/src/broker.rs b/src/broker.rs index 6950b77..9c265ef 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,25 +1,32 @@ use std::{ any, collections::HashMap, - sync::{mpsc::{Receiver, Sender}, Arc}, + sync::{ + mpsc::{Receiver, Sender}, + Arc, + }, }; use anyhow::{bail, Error, Result}; use chrono::{DateTime, Utc}; -use crate::{registry::{service_item::ServiceItem, Logger}, service, Registry, Service}; +use crate::{ + registry::{service_item::ServiceItem, Logger}, + service::{self, ServiceSpec}, + Registry, Service, +}; pub struct ServiceBroker { reciever: Receiver, started: bool, namespace: Option, metdata: HashMap, - pub node_id: String, + pub node_id: String, instance: String, services: Vec, - pub transit : Option, - pub logger : Arc, + pub transit: Option, + pub logger: Arc, /* local bus options @@ -36,7 +43,7 @@ pub struct ServiceBroker { registry: Registry, } -pub struct Transit{} +pub struct Transit {} impl ServiceBroker { fn start(&mut self) { @@ -47,7 +54,7 @@ impl ServiceBroker { fn add_local_service(&mut self, service: Service) { self.services.push(service); } - fn register_local_service(&mut self, service: Service) { + fn register_local_service(&mut self, service: ServiceSpec) { self.registry.register_local_service(service); } @@ -94,7 +101,13 @@ impl ServiceBroker { } pub enum ServiceBrokerMessage { - + AddLocalService(Service), + RegisterLocalService(ServiceSpec), + WaitForServices { + dependencies: Vec, + timeout: i64, + interval: i64, + }, } fn remove_from_list(list: &mut Vec, value: &T) { diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 3977e18..cbf6ba6 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -48,7 +48,7 @@ pub struct Action { pub name: String, visibility: Visibility, handler: fn(), - service: Option, + // service: Option, } impl Action { @@ -57,13 +57,13 @@ impl Action { name, visibility: Visibility::Protected, handler, - service: None, + // service: None, } } - pub fn set_service(mut self, service: Service) -> Action { - self.service = Some(service); - self - } + // pub fn set_service(mut self, service: Service) -> Action { + // self.service = Some(service); + // self + // } } #[derive(PartialEq, Eq, Clone)] diff --git a/src/registry/registry.rs b/src/registry/registry.rs index aa65ca6..281d217 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,4 +1,4 @@ -use crate::{ServiceBrokerMessage, service::SchemaActions, ServiceBroker}; +use crate::{ServiceBrokerMessage, service::{SchemaActions, ServiceSpec}, ServiceBroker}; use super::*; use serde_json::Value; @@ -40,7 +40,7 @@ impl Registry { fn update_metrics(&self) { todo!("update metrics") } - pub fn register_local_service(&mut self, svc: Service) { + pub fn register_local_service(&mut self, svc: ServiceSpec) { if !self .services .has(&svc.full_name, Some(&self.broker.node_id)) diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 8b8e83a..2a97001 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,3 +1,5 @@ +use crate::service::ServiceSpec; + use super::*; use regex::Regex; #[derive(PartialEq, Eq)] @@ -12,7 +14,7 @@ impl ServiceCatalog { } } ///Add a new service - pub fn add(&mut self, node: Arc, service: &Service, local: bool) -> Arc { + pub fn add(&mut self, node: Arc, service: &ServiceSpec, local: bool) -> Arc { let service_item = ServiceItem::new(node, service, local); let service_item = Arc::new(service_item); diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index 9bdb3e1..9e2be8f 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -1,3 +1,5 @@ +use crate::service::ServiceSpec; + use super::*; #[derive(PartialEq, Eq, Clone)] @@ -15,7 +17,7 @@ pub struct ServiceItem { */ } impl ServiceItem { - pub fn new(node: Arc, service: &Service, local: bool) -> Self { + pub fn new(node: Arc, service: &ServiceSpec, local: bool) -> Self { Self { node, local, diff --git a/src/service.rs b/src/service.rs index ecd8982..85d1d9d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,10 +1,14 @@ use std::{collections::HashMap, sync::Arc}; +use crate::{ + registry::{Action, Event, Logger}, + ServiceBrokerMessage, +}; use chrono::Duration; +use log::info; +use tokio::sync::mpsc::Sender; -use crate::registry::{Action, Event, Logger}; - -#[derive(PartialEq, Eq, Clone)] +#[derive(Clone)] pub struct Service { pub name: String, pub full_name: String, @@ -16,7 +20,9 @@ pub struct Service { metadata: HashMap, pub actions: Option>, pub events: Option>, + broker_sender: Sender, } + #[derive(PartialEq, Eq, Clone)] struct Schema { mixins: Option>, @@ -27,6 +33,10 @@ struct Schema { version: Option, settings: HashMap, metadata: Option>, + created: Option, + started: Option, + stopped: Option, + dependencies: Option>, } #[derive(PartialEq, Eq, Clone)] @@ -34,8 +44,8 @@ struct SchemaMixins {} #[derive(PartialEq, Eq, Clone)] pub struct SchemaActions { - name:String, - handler:fn() + name: String, + handler: fn(), } #[derive(PartialEq, Eq, Clone)] @@ -45,8 +55,32 @@ enum SchemaMerged { MergedFn(fn()), MergedFnVec(Vec), } +pub struct ServiceSpec { + pub(crate) name: String, + pub(crate) version: String, + pub(crate) full_name: String, + pub(crate) settings: HashMap, + /* + pub(crate)metadata + pub(crate)*/ + pub(crate) actions: Option>, + pub(crate) events: Option>, +} impl Service { + fn get_service_spec(&self) -> ServiceSpec { + //TODO: do something about actions and events + let service_spec = ServiceSpec { + name: self.name.clone(), + full_name: self.full_name.clone(), + settings: Service::get_public_settings(&self.settings), + version: self.version.clone(), + actions: None, + events: None, + }; + service_spec + } + fn parse_service_schema(&mut self, schema: Schema) { self.original_schema = Some(schema.clone()); @@ -88,16 +122,71 @@ impl Service { todo!("add service specification") } - pub fn init(&mut self) { - todo!("call broker to initialise the service and call the init method of service") + fn get_public_settings(settings: &HashMap) -> HashMap { + settings.clone() } - pub fn start(&mut self) { - todo!("call the broker to start the services and call the start method of services") + pub async fn init(&self) { + info!("Service {} is createing....", self.full_name); + if let Some(created) = self.schema.created { + created(); + } + let _result = self + .broker_sender + .send(ServiceBrokerMessage::AddLocalService(self.clone())) + .await; + info!("Service {} created.", self.full_name); + + todo!("call broker middlware") } - pub fn stop(&mut self) { - todo!("call the broker to stop the service and call the stop method of service") + pub async fn start(&self) { + info!("Service {} is starting...", self.full_name); + + if let Some(dependencies) = &self.schema.dependencies { + let timeout: i64 = match self.settings.get("$dependencyTimeout") { + //TODO:raise an error rateher than default. + Some(val) => val.parse().unwrap_or(0), + None => 0, + }; + //TODO: get interal from broker options + let interval: i64 = match self.settings.get("$dependencyInterval") { + Some(val) => val.parse().unwrap_or(0), + None => 0, + }; + + self.wait_for_services(dependencies, timeout, interval) + .await; + } + + if let Some(started) = &self.schema.started { + started(); + } + + let _result = self + .broker_sender + .send(ServiceBrokerMessage::RegisterLocalService( + Service::get_service_spec(&self), + )) + .await; + + info!("Service {} started.", self.full_name); + + todo!("call service starting middleware"); + todo!("call service started middleware") + } + + pub async fn stop(&self) { + info!("Service {} is stopping...", self.full_name); + + if let Some(stopped) = self.schema.stopped { + stopped(); + } + + info!("Service {} stopped.", self.full_name); + + todo!("call service stopping middlewares"); + todo!("call service stopped middleware"); } fn create_action(&self, action_def: fn(), name: &str) -> Action { @@ -111,7 +200,8 @@ impl Service { } //TODO add caching settings from settins //TODO better way to handle this instead of clone. - action = action.set_service(self.clone()); + //TODO see if it is even necessary to give action access to the service. + // action = action.set_service(self.clone()); action } @@ -125,8 +215,15 @@ impl Service { todo!() } - fn wait_for_services(&self, service_names: Vec, timout: Duration, interval: Duration) { - todo!("call broker to wait for services") + async fn wait_for_services(&self, service_names: &Vec, timeout: i64, interval: i64) { + let _result = self + .broker_sender + .send(ServiceBrokerMessage::WaitForServices { + dependencies: service_names.clone(), + interval, + timeout, + }) + .await; } fn get_versioned_full_name(name: &str, version: Option<&String>) -> String { From c2d5fc695371a476fb08754799236932ebaf4a3a Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Fri, 4 Feb 2022 10:20:41 +0530 Subject: [PATCH 14/22] service tests --- makefile | 4 + src/broker.rs | 13 +- src/logger.rs | 1 - src/packet.rs | 1 - src/registry/mod.rs | 6 +- src/registry/registry.rs | 63 +++++--- src/service.rs | 311 ++++++++++++++++++++++++++++++++++----- src/strategies/mod.rs | 2 +- 8 files changed, 331 insertions(+), 70 deletions(-) create mode 100644 makefile diff --git a/makefile b/makefile new file mode 100644 index 0000000..d7ea6f4 --- /dev/null +++ b/makefile @@ -0,0 +1,4 @@ +#Run library test while suppressing the warnings +test: + RUSTFLAGS=-Awarnings cargo test --lib -- --nocapture +.PHONY: test \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs index 9c265ef..9d8d1e2 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,19 +1,18 @@ use std::{ - any, collections::HashMap, sync::{ - mpsc::{Receiver, Sender}, + mpsc::{Receiver, }, Arc, }, }; -use anyhow::{bail, Error, Result}; +use anyhow::{bail, Result}; -use chrono::{DateTime, Utc}; +use chrono:: Utc; use crate::{ - registry::{service_item::ServiceItem, Logger}, - service::{self, ServiceSpec}, + registry:: Logger, + service::ServiceSpec, Registry, Service, }; @@ -99,7 +98,7 @@ impl ServiceBroker { }) } } - +#[derive(PartialEq ,Debug)] pub enum ServiceBrokerMessage { AddLocalService(Service), RegisterLocalService(ServiceSpec), diff --git a/src/logger.rs b/src/logger.rs index 5ae7983..993ea22 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,4 +1,3 @@ -use log::{debug, error, info, log_enabled, Level}; trait LoggerTrait { fn init(); diff --git a/src/packet.rs b/src/packet.rs index a0d7749..74bfdaf 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,4 +1,3 @@ -use core::fmt; enum PacketType { Unknown, diff --git a/src/registry/mod.rs b/src/registry/mod.rs index cbf6ba6..6e7dd8c 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -43,7 +43,7 @@ pub struct Logger {} trait FnType {} -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone , Debug)] pub struct Action { pub name: String, visibility: Visibility, @@ -66,14 +66,14 @@ impl Action { // } } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone , Debug)] enum Visibility { Published, Public, Protected, Private, } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone ,Debug)] pub struct Event {} impl FnType for Event {} diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 281d217..7b1b0f5 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,4 +1,7 @@ -use crate::{ServiceBrokerMessage, service::{SchemaActions, ServiceSpec}, ServiceBroker}; +use crate::{ + service::{SchemaActions, ServiceSpec}, + ServiceBroker, ServiceBrokerMessage, +}; use super::*; use serde_json::Value; @@ -11,7 +14,6 @@ pub struct Registry { nodes: NodeCatalog, services: ServiceCatalog, actions: ActionCatalog, - /* metrics strategy factor @@ -21,10 +23,20 @@ pub struct Registry { */ } impl Registry { - pub fn new(broker: Arc) -> Self { + pub fn new(broker: Arc, broker_sender: Sender) -> Self { let logger = &broker.logger; let logger = Arc::clone(&logger); - todo!() + let nodes = NodeCatalog::new(); + let services = ServiceCatalog::new(); + let actions = ActionCatalog::new(); + Registry { + logger, + broker_sender, + broker, + nodes, + services, + actions, + } } fn init() { @@ -52,7 +64,7 @@ impl Registry { ); if let Some(actions) = svc.actions { let local_node = Arc::clone(&self.nodes.local_node.as_ref().unwrap()); - self.register_actions(local_node , Arc::clone(&service) , actions); + self.register_actions(local_node, Arc::clone(&service), actions); } if let Some(events) = svc.events { self.register_events(); @@ -72,16 +84,19 @@ impl Registry { _ => false, } } - fn register_actions(&mut self , node : Arc , service: Arc , actions : Vec) { - actions.iter().for_each(|action|{ - if !Registry::check_action_visibility(action, &node){ + fn register_actions( + &mut self, + node: Arc, + service: Arc, + actions: Vec, + ) { + actions.iter().for_each(|action| { + if !Registry::check_action_visibility(action, &node) { return; } - if node.local{ + if node.local { //TODO:stuff with middleware and handlers. - - - }else if let Some(_) = self.broker.transit { + } else if let Some(_) = self.broker.transit { //TODO: for remote services return; } @@ -124,7 +139,9 @@ impl Registry { self.regenerate_local_raw_info(Some(true)); } } - None => {self.regenerate_local_raw_info(Some(true));}, + None => { + self.regenerate_local_raw_info(Some(true)); + } } } fn unregister_service_by_node_id(&mut self, node_id: &str) { @@ -141,19 +158,19 @@ impl Registry { todo!() } - fn regenerate_local_raw_info(&self, incSeq: Option)->Value { + fn regenerate_local_raw_info(&self, incSeq: Option) -> Value { todo!() } - fn get_local_node_info(&self, force: bool)->Value { - if let None = self.nodes.local_node{ + fn get_local_node_info(&self, force: bool) -> Value { + if let None = self.nodes.local_node { return self.regenerate_local_raw_info(None); } if force { return self.regenerate_local_raw_info(None); } - let value = self.nodes.local_node.as_ref().unwrap().raw_info.to_owned(); - value.unwrap() + let value = self.nodes.local_node.as_ref().unwrap().raw_info.to_owned(); + value.unwrap() } fn get_node_info(&self, node_id: &str) -> Option { todo!() @@ -161,13 +178,13 @@ impl Registry { fn process_node_info(&self) { todo!() } - pub fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { + pub fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { self.nodes.list(only_available, with_services) } - pub fn get_services_list(&self, opts: ListOptions) -> Vec<&Arc> { + pub fn get_services_list(&self, opts: ListOptions) -> Vec<&Arc> { self.services.list(opts) } - fn get_actions_list(&self , opts:ListOptions) -> Vec<&ActionEndpoint> { + fn get_actions_list(&self, opts: ListOptions) -> Vec<&ActionEndpoint> { //self.actions.list(opts) todo!() } @@ -178,3 +195,7 @@ impl Registry { todo!() } } +#[cfg(test)] +mod tests { + +} diff --git a/src/service.rs b/src/service.rs index 85d1d9d..dd0649e 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,35 +1,47 @@ -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; use crate::{ - registry::{Action, Event, Logger}, + registry::{Action, Event}, ServiceBrokerMessage, }; -use chrono::Duration; use log::info; -use tokio::sync::mpsc::Sender; +use tokio::sync::mpsc::UnboundedSender; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Service { pub name: String, pub full_name: String, pub version: String, settings: HashMap, - logger: Arc, schema: Schema, original_schema: Option, metadata: HashMap, pub actions: Option>, pub events: Option>, - broker_sender: Sender, + broker_sender: UnboundedSender, } -#[derive(PartialEq, Eq, Clone)] +impl PartialEq for Service { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.full_name == other.full_name + && self.version == other.version + && self.settings == other.settings + && self.schema == other.schema + && self.original_schema == other.original_schema + && self.metadata == other.metadata + && self.actions == other.actions + && self.events == other.events + } +} + +#[derive(PartialEq, Eq, Clone, Debug)] struct Schema { mixins: Option>, actions: Option>, events: Option>, merged: SchemaMerged, - name: Option, + name: String, version: Option, settings: HashMap, metadata: Option>, @@ -39,27 +51,28 @@ struct Schema { dependencies: Option>, } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] struct SchemaMixins {} -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct SchemaActions { name: String, handler: fn(), } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] struct SchemaEvents {} -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] enum SchemaMerged { MergedFn(fn()), MergedFnVec(Vec), } +#[derive(PartialEq, Debug)] pub struct ServiceSpec { pub(crate) name: String, pub(crate) version: String, pub(crate) full_name: String, - pub(crate) settings: HashMap, + settings: HashMap, /* pub(crate)metadata pub(crate)*/ @@ -73,7 +86,7 @@ impl Service { let service_spec = ServiceSpec { name: self.name.clone(), full_name: self.full_name.clone(), - settings: Service::get_public_settings(&self.settings), + settings: self.get_public_settings(), version: self.version.clone(), actions: None, events: None, @@ -85,21 +98,15 @@ impl Service { self.original_schema = Some(schema.clone()); match schema.merged { - SchemaMerged::MergedFn(func) => { - - //TODO research about functions - } + SchemaMerged::MergedFn(merged) => merged(), SchemaMerged::MergedFnVec(func_vec) => { for func in func_vec { - //TODO resarch more about functions + func() } } } - if let None = schema.name { - //TODO throw error if no name available - } - self.name = schema.name.unwrap().clone(); + self.name = schema.name; self.version = match schema.version { Some(v) => v, None => "0.0.1".to_string(), @@ -122,8 +129,8 @@ impl Service { todo!("add service specification") } - fn get_public_settings(settings: &HashMap) -> HashMap { - settings.clone() + fn get_public_settings(&self) -> HashMap { + self.settings.clone() } pub async fn init(&self) { @@ -133,11 +140,10 @@ impl Service { } let _result = self .broker_sender - .send(ServiceBrokerMessage::AddLocalService(self.clone())) - .await; + .send(ServiceBrokerMessage::AddLocalService(self.clone())); info!("Service {} created.", self.full_name); - todo!("call broker middlware") + // todo!("call broker middlware") } pub async fn start(&self) { @@ -167,13 +173,12 @@ impl Service { .broker_sender .send(ServiceBrokerMessage::RegisterLocalService( Service::get_service_spec(&self), - )) - .await; + )); info!("Service {} started.", self.full_name); - todo!("call service starting middleware"); - todo!("call service started middleware") + // todo!("call service starting middleware"); + //todo!("call service started middleware") } pub async fn stop(&self) { @@ -194,7 +199,7 @@ impl Service { let name_prefix = self.settings.get("$noServiceNamePrefix"); if let Some(name_prefix) = name_prefix { let name_prefix: bool = name_prefix.parse().unwrap(); - if name_prefix { + if !name_prefix { action.name = format!("{}.{}", self.full_name.to_string(), action.name); } } @@ -222,8 +227,7 @@ impl Service { dependencies: service_names.clone(), interval, timeout, - }) - .await; + }); } fn get_versioned_full_name(name: &str, version: Option<&String>) -> String { @@ -234,3 +238,238 @@ impl Service { name } } +#[cfg(test)] +mod tests { + use tokio::sync::mpsc::{self, UnboundedSender}; + + use super::*; + fn test_merge_func() { + println!("test merge function"); + } + fn test_started_func() { + println!("test start func"); + } + fn test_created_func() { + println!("test created func"); + } + fn test_stop_func() { + println!("test stop func"); + } + fn action_func() { + println!("action_func"); + } + + fn get_test_schema(dependencies: Option>) -> Schema { + let merged = SchemaMerged::MergedFn(test_merge_func); + let schema = Schema { + mixins: None, + actions: None, + events: None, + merged, + name: "test_service".to_string(), + version: None, + settings: HashMap::new(), + metadata: None, + created: Some(test_created_func), + started: Some(test_started_func), + stopped: Some(test_stop_func), + dependencies: dependencies, + }; + + schema + } + + fn get_test_service( + schema: Option, + settings: Option>, + actions: Option>, + broker_sender: Option>, + ) -> Service { + let name = "test_service".to_string(); + let version = "1.0".to_string(); + let full_name = Service::get_versioned_full_name(&name, Some(&version)); + let settings = match settings { + Some(settings) => settings, + None => HashMap::new(), + }; + let schema = match schema { + Some(schema) => schema, + None => get_test_schema(None), + }; + + let original_schema = get_test_schema(None); + let broker_sender = match broker_sender { + Some(sender) => sender, + None => { + let (sender, recv) = mpsc::unbounded_channel::(); + sender + } + }; + let service = Service { + name, + full_name, + version, + settings, + schema, + original_schema: Some(original_schema), + metadata: HashMap::new(), + actions: actions, + events: None, + broker_sender, + }; + service + } + #[test] + fn service_get_service_spec() { + let service = get_test_service(None, None, None, None); + let service_spec = ServiceSpec { + name: service.name.clone(), + version: service.version.clone(), + full_name: service.full_name.clone(), + settings: service.settings.clone(), + actions: None, + events: None, + }; + + let service_spec_gen = service.get_service_spec(); + assert_eq!(service_spec_gen, service_spec) + } + #[test] + fn service_get_public_settings() { + let mut settings = HashMap::new(); + settings.insert("test".to_string(), "settings".to_string()); + let service = get_test_service(None, Some(settings.clone()), None, None); + assert_eq!(service.get_public_settings(), settings); + } + #[test] + fn service_init() { + let (sender, mut recv) = mpsc::unbounded_channel::(); + let service = get_test_service(None, None, None, Some(sender)); + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(async { service.init().await }); + rt.block_on(async { + let result = recv.recv().await; + + let expected_result = ServiceBrokerMessage::AddLocalService(service); + assert_eq!(result, Some(expected_result)); + }); + } + #[test] + fn service_start() { + let (sender, mut recv) = mpsc::unbounded_channel::(); + let service = get_test_service(None, None, None, Some(sender)); + let service_spec = service.get_service_spec(); + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(async { service.start().await }); + rt.block_on(async { + let result = recv.recv().await; + let expected_result = ServiceBrokerMessage::RegisterLocalService(service_spec); + assert_eq!(result, Some(expected_result)); + }); + } + #[test] + fn service_start_with_dependencies() { + let (sender, mut recv) = mpsc::unbounded_channel::(); + let service_names: Vec = + vec!["Service one".to_string(), " Service two".to_string()]; + + let schema = get_test_schema(Some(service_names.clone())); + let service = get_test_service(Some(schema), None, None, Some(sender)); + let service_spec = service.get_service_spec(); + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(async { service.start().await }); + rt.block_on(async { + let result = recv.recv().await; + let expected_result = ServiceBrokerMessage::WaitForServices { + dependencies: service_names, + timeout: 0, + interval: 0, + }; + assert_eq!(result, Some(expected_result)); + + let result = recv.recv().await; + let expected_result = ServiceBrokerMessage::RegisterLocalService(service_spec); + assert_eq!(result, Some(expected_result)); + }); + } + #[test] + fn service_create_action_name() { + let no_service_name_prefix = "$noServiceNamePrefix".to_string(); + let name = "action_func"; + let mut settings = HashMap::new(); + settings.insert(no_service_name_prefix.clone(), "true".to_string()); + let service = get_test_service(None, Some(settings.clone()), None, None); + let action = service.create_action(action_func, name); + let expected_action = Action::new(name.to_string(), action_func); + assert_eq!(action, expected_action); + settings.insert(no_service_name_prefix.clone(), "false".to_string()); + let service = get_test_service(None, Some(settings), None, None); + let action_2 = service.create_action(action_func, name); + let name = format!("{}.{}", service.full_name, name); + let expected_action_2 = Action::new(name, action_func); + assert_eq!(action_2, expected_action_2); + let service = get_test_service(None, None, None, None); + let name = "action_func"; + let expected_action_3 = Action::new(name.to_string(), action_func); + let action_3 = service.create_action(action_func, name); + assert_eq!(action_3, expected_action_3); + } + #[test] + #[should_panic] + fn service_create_action_name_panic() { + let no_service_name_prefix = "$noServiceNamePrefix".to_string(); + let mut settings = HashMap::new(); + let name = "action_func"; + settings.insert(no_service_name_prefix, "non_bool_value".to_string()); + let service = get_test_service(None, Some(settings), None, None); + let action = service.create_action(action_func, name); + } + #[test] + fn service_wait_for_service() { + let (sender, mut recv) = mpsc::unbounded_channel::(); + let service = get_test_service(None, None, None, Some(sender)); + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + let service_names: Vec = + vec!["Service one".to_string(), " Service two".to_string()]; + let timeout = 10; + let interval = 20; + rt.block_on(async { + let _result = service + .wait_for_services(&service_names, timeout, interval) + .await; + }); + rt.block_on(async { + let result = recv.recv().await; + let expected_result = ServiceBrokerMessage::WaitForServices { + dependencies: service_names, + timeout, + interval, + }; + assert_eq!(result, Some(expected_result)); + }); + } + #[test] + fn service_get_versioned_full_name() { + let version = "1.0"; + let name = "test_service"; + let expected_full_name = format!("{}.{}", version, name); + let version = "1.0".to_string(); + let version = Some(&version); + let full_name = Service::get_versioned_full_name(name, version); + assert_eq!(full_name , expected_full_name); + let full_name_2 = Service::get_versioned_full_name(name, None); + assert_eq!(full_name_2 , name); + } +} diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs index 6e71fa7..deb40c0 100644 --- a/src/strategies/mod.rs +++ b/src/strategies/mod.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::registry::{ActionEndpoint, Registry , Opts}; +use crate::registry::{ActionEndpoint, Registry , }; use crate::ServiceBroker; mod round_robin; From d39d5d3b20825e1e0ae8b843ace67b7b701265d7 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 5 Feb 2022 09:41:33 +0530 Subject: [PATCH 15/22] feat: private action ep --- Cargo.lock | 56 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++- src/registry/registry.rs | 44 +++++++++++++++++++++---------- src/service.rs | 1 - 4 files changed, 90 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d62240c..edf474a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "env_logger" version = "0.9.0" @@ -172,11 +191,13 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", + "derive_more", "env_logger", "lazy_static", "log", "regex", "serde_json", + "thiserror", "tokio", ] @@ -299,6 +320,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.9" @@ -311,6 +341,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" + [[package]] name = "serde" version = "1.0.136" @@ -363,6 +399,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index 66202d2..b81d0a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,6 @@ serde_json = "1.0.0" anyhow = "1.0.53" tokio = { version = "1.16.1", features = ["full"] } regex = "1.5.4" -lazy_static = "1.3.0" \ No newline at end of file +lazy_static = "1.3.0" +derive_more = "0.99.17" +thiserror = "1.0" \ No newline at end of file diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 7b1b0f5..9c52a3d 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,9 +1,8 @@ -use crate::{ - service::{SchemaActions, ServiceSpec}, - ServiceBroker, ServiceBrokerMessage, -}; +use crate::{service::ServiceSpec, ServiceBroker, ServiceBrokerMessage}; +use derive_more::Display; use super::*; +use anyhow::{bail, Error}; use serde_json::Value; use tokio::sync::mpsc::Sender; @@ -107,8 +106,15 @@ impl Registry { //add the action to the service. }); } - fn create_private_action_endpoint(action: Action) { - todo!() + fn create_private_action_endpoint(&self, action: Action) -> anyhow::Result { + let local_node = match &self.nodes.local_node { + Some(node) => node, + None => bail!("No local node available"), + }; + let node = Arc::clone(local_node); + todo!("add service to action") + // let action_ep = ActionEndpoint::new(node, service, action); + // Ok(action_ep) } pub fn has_services(&self, full_name: &str, node_id: Option<&str>) -> bool { self.services.has(full_name, node_id) @@ -162,15 +168,21 @@ impl Registry { todo!() } - fn get_local_node_info(&self, force: bool) -> Value { + fn get_local_node_info(&self, force: bool) -> Result { if let None = self.nodes.local_node { - return self.regenerate_local_raw_info(None); + return Ok(self.regenerate_local_raw_info(None)); } if force { - return self.regenerate_local_raw_info(None); + return Ok(self.regenerate_local_raw_info(None)); + } + if let None = self.nodes.local_node { + return Err(RegistryError::NoLocalNodeFound); } let value = self.nodes.local_node.as_ref().unwrap().raw_info.to_owned(); - value.unwrap() + match value { + Some(value) => Ok(value), + None => Err(RegistryError::NoLocalNodeFound), + } } fn get_node_info(&self, node_id: &str) -> Option { todo!() @@ -195,7 +207,13 @@ impl Registry { todo!() } } -#[cfg(test)] -mod tests { - +use thiserror::Error; +#[derive(Error, Debug)] +enum RegistryError { + #[error("No local node found")] + NoLocalNodeFound, } + +#[cfg(test)] + +mod tests {} diff --git a/src/service.rs b/src/service.rs index dd0649e..c7dfda6 100644 --- a/src/service.rs +++ b/src/service.rs @@ -204,7 +204,6 @@ impl Service { } } //TODO add caching settings from settins - //TODO better way to handle this instead of clone. //TODO see if it is even necessary to give action access to the service. // action = action.set_service(self.clone()); action From 1fe5dca74aa133ffe9dffafa5d7787aca5ff13f8 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sun, 13 Feb 2022 16:32:13 +0530 Subject: [PATCH 16/22] refactor: registry refactores --- src/registry/action_catalog.rs | 2 +- src/registry/action_endpoint.rs | 17 ++++---- src/registry/endpoint_list.rs | 8 ++-- src/registry/event_endpoint.rs | 15 +++---- src/registry/mod.rs | 38 ++++++++--------- src/registry/node.rs | 2 +- src/registry/node_catalog.rs | 33 ++++++++++----- src/registry/registry.rs | 72 +++++++++++++++------------------ src/registry/service_catalog.rs | 65 +++++++++++++++-------------- src/registry/service_item.rs | 11 +++-- 10 files changed, 135 insertions(+), 128 deletions(-) diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index 3675d77..3916de4 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -13,7 +13,7 @@ impl ActionCatalog { actions: HashMap::new(), } } - pub fn add(&mut self, node: Arc, service: Arc, action: Action) { + pub fn add(&mut self, node: &Node, service: &ServiceItem, action: Action) { let list = self.actions.get_mut(&action.name); match list { Some(list) => list.add(node, service, action), diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 948ba8c..94914bc 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -12,9 +12,9 @@ impl EndpointTrait for ActionEndpoint { fn update(&mut self, data: Self::Data) { self.action = data; } - fn new(node: Arc, service: Arc, data: Self::Data) -> Self { - let endpoint = Endpoint::new(node, service); - let name = format!("{}:{}", endpoint.id, data.name); + fn new(node_id: &str, service: &ServiceItem, data: Self::Data) -> Self { + let endpoint = Endpoint::new(node_id, service); + let name = format!("{}:{}", endpoint.node_id, data.name); Self { endpoint, name, @@ -22,13 +22,10 @@ impl EndpointTrait for ActionEndpoint { } } - fn node(&self) -> &Node { - &self.endpoint.node + fn node(&self) -> &str { + &self.endpoint.node_id } - fn service(&self) -> &ServiceItem { - &self.endpoint.service - } fn is_local(&self) -> bool { self.endpoint.local } @@ -36,9 +33,9 @@ impl EndpointTrait for ActionEndpoint { self.endpoint.state } fn id(&self) -> &str { - &self.endpoint.id + &self.endpoint.node_id } fn service_name(&self) -> &str { - &self.endpoint.service.name + &self.endpoint.service } } diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index f0d2715..1e9ce27 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -25,11 +25,11 @@ impl EndpointList { } } - pub fn add(&mut self, node: Arc, service: Arc, data: T::Data) { + pub fn add(&mut self, node: &Node, service:&ServiceItem, data: T::Data) { let entry = self .endpoints .iter_mut() - .find(|x| x.node() == &*node && x.service().name == service.name); + .find(|x| x.service_name() == service.unique_name()); match entry { Some(found) => { @@ -39,7 +39,7 @@ impl EndpointList { None => {} } - let ep = T::new(Arc::clone(&node), Arc::clone(&service), data); + let ep = T::new(&node.id, service, data); self.endpoints.push(ep.clone()); if ep.is_local() { @@ -101,7 +101,7 @@ impl EndpointList { } pub fn remove_by_service(&mut self, service: &ServiceItem) { self.endpoints.retain(|ep| { - let delete = ep.service() == service; + let delete = ep.service_name() == service.unique_name(); !delete }); self.update_local_endpoints(); diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs index d8cd7d6..a96101a 100644 --- a/src/registry/event_endpoint.rs +++ b/src/registry/event_endpoint.rs @@ -11,8 +11,8 @@ impl EndpointTrait for EventEndpoint { fn update(&mut self, data: Self::Data) { self.event = data; } - fn new(node: Arc, service: Arc, data: Self::Data) -> Self { - let endpoint = Endpoint::new(node, service); + fn new(node_id: &str, service: &ServiceItem, data: Self::Data) -> Self { + let endpoint = Endpoint::new(node_id, service); Self { endpoint, @@ -20,13 +20,10 @@ impl EndpointTrait for EventEndpoint { } } - fn node(&self) -> &Node { - &self.endpoint.node + fn node(&self) -> &str { + &self.endpoint.node_id } - fn service(&self) -> &ServiceItem { - &self.endpoint.service - } fn is_local(&self) -> bool { self.endpoint.local } @@ -34,9 +31,9 @@ impl EndpointTrait for EventEndpoint { self.endpoint.state } fn id(&self) -> &str { - &self.endpoint.id + &self.endpoint.node_id } fn service_name(&self) -> &str { - &self.endpoint.service.name + &self.endpoint.service } } diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 6e7dd8c..40b7ec6 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -17,33 +17,30 @@ use action_catalog::ActionCatalog; pub use action_endpoint::ActionEndpoint; pub use endpoint_list::EndpointList; pub use event_endpoint::EventEndpoint; +use lazy_static::lazy_static; pub use node::{Client, Node}; use node_catalog::NodeCatalog; use regex::Regex; pub use registry::Registry; use service_catalog::ServiceCatalog; use service_item::ServiceItem; -use lazy_static::lazy_static; // pub use event_endpoint::EventEndpoint; - type ActionsMap = HashMap>; fn get_internal_service_regex_match(text: &str) -> bool { lazy_static! { - static ref RE: Regex = Regex::new(r"^\$").unwrap(); - + static ref RE: Regex = Regex::new(r"^\$").unwrap(); } RE.is_match(text) } - #[derive(PartialEq, Eq)] pub struct Logger {} trait FnType {} -#[derive(PartialEq, Eq, Clone , Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Action { pub name: String, visibility: Visibility, @@ -66,14 +63,14 @@ impl Action { // } } -#[derive(PartialEq, Eq, Clone , Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] enum Visibility { Published, Public, Protected, Private, } -#[derive(PartialEq, Eq, Clone ,Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Event {} impl FnType for Event {} @@ -81,9 +78,8 @@ impl FnType for Event {} pub trait EndpointTrait { ///Data is eiter an Action struct or Event structs type Data; - fn new(node: Arc, service: Arc, data: Self::Data) -> Self; - fn node(&self) -> &Node; - fn service(&self) -> &ServiceItem; + fn new(node_id: &str, service: &ServiceItem, data: Self::Data) -> Self; + fn node(&self) -> &str; fn update(&mut self, data: Self::Data); fn is_local(&self) -> bool; fn is_available(&self) -> bool; @@ -93,22 +89,20 @@ pub trait EndpointTrait { #[derive(PartialEq, Eq, Clone)] struct Endpoint { - node: Arc, - service: Arc, + service: String, state: bool, - id: String, + node_id: String, local: bool, } impl Endpoint { - fn new(node: Arc, service: Arc) -> Self { - let id = node.id.to_string(); + fn new(node_id: &str, service: &ServiceItem) -> Self { let local = service.local; + let service = service.unique_name(); Self { - node, service, state: true, - id: id, + node_id: node_id.to_string(), local, } } @@ -131,3 +125,11 @@ pub struct ListOptions { with_events: bool, grouping: bool, } +use thiserror::Error; +#[derive(Error, Debug)] +enum RegistryError { + #[error("No local node found")] + NoLocalNodeFound, + #[error("No service found")] + NoServiceItemFound, +} diff --git a/src/registry/node.rs b/src/registry/node.rs index 8fdc6ad..5a4c090 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -27,7 +27,7 @@ pub struct Node { cpu cpuseq */ - pub services: Vec>, + pub services: Vec, pub seq: usize, offline_since: Option, } diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index be80799..9768ae4 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -2,22 +2,26 @@ use std::{collections::HashMap, net::IpAddr, sync::Arc}; use std::sync::RwLock; -use super::{node, Client, Logger, Node, Registry}; +use anyhow::bail; + +use crate::registry::RegistryError; +use super::{node, Client, Logger, Node, Registry}; pub struct NodeCatalog { nodes: HashMap, - pub local_node: Option>, + local_node_id: String, } impl NodeCatalog { pub fn new() -> Self { + //TODO: add the create local node logic here Self { nodes: HashMap::new(), - local_node: None, + local_node_id: "".to_string(), } } ///Create a local node - fn create_local_node(&mut self, version: String, node_id: String, instance_id: String) -> Arc { + fn create_local_node(&mut self, version: String, node_id: String, instance_id: String) { let client = Client { client_type: "rust".to_string(), lang_version: "1.56.1".to_string(), @@ -30,12 +34,9 @@ impl NodeCatalog { .set_hostname(get_hostname()) .set_seq(1) .set_client(client); - + //TODO:data constency between local node and node catalog self.nodes.insert(node.id.to_string(), node.clone()); - let node = Arc::new(node); - let node_c = Arc::clone(&node); - self.local_node = Some(node); - return node_c; + self.local_node_id = node.id; todo!() /* node.metadata = self.broker.metadata.clone() @@ -53,6 +54,19 @@ impl NodeCatalog { pub fn get_node(&self, id: &str) -> Option<&Node> { self.nodes.get(id) } + pub fn local_node(&self) -> anyhow::Result<&Node> { + match self.nodes.get(&self.local_node_id) { + Some(node) => Ok(node), + None => bail!(RegistryError::NoLocalNodeFound), + } + } + pub fn local_node_mut(&mut self) -> anyhow::Result<&mut Node> { + match self.nodes.get_mut(&self.local_node_id) { + Some(node) => Ok(node), + None => bail!(RegistryError::NoLocalNodeFound), + } + } + pub fn get_node_mut(&mut self, id: &str) -> Option<&mut Node> { self.nodes.get_mut(id) } @@ -120,4 +134,3 @@ fn get_ip_list() -> Vec { fn get_hostname() -> String { todo!() } - diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 9c52a3d..19c11ac 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,5 +1,4 @@ use crate::{service::ServiceSpec, ServiceBroker, ServiceBrokerMessage}; -use derive_more::Display; use super::*; use anyhow::{bail, Error}; @@ -51,31 +50,33 @@ impl Registry { fn update_metrics(&self) { todo!("update metrics") } - pub fn register_local_service(&mut self, svc: ServiceSpec) { + pub fn register_local_service(&mut self, svc: ServiceSpec) -> anyhow::Result<()> { if !self .services .has(&svc.full_name, Some(&self.broker.node_id)) { - let service = self.services.add( - Arc::clone(&self.nodes.local_node.as_ref().unwrap()), - &svc, - true, - ); + let node = self.nodes.local_node()?; + + let service_full_name = self.services.add(node, &svc, true); if let Some(actions) = svc.actions { - let local_node = Arc::clone(&self.nodes.local_node.as_ref().unwrap()); - self.register_actions(local_node, Arc::clone(&service), actions); + self.register_actions(&service_full_name, actions); } if let Some(events) = svc.events { self.register_events(); } - //TODO:Add service to the local node. - //self.nodes.local_node.unwrap().services.push(Arc::clone(&service)); + + { + let local_node = self.nodes.local_node_mut()?; + + local_node.services.push(service_full_name); + } } + Ok(()) } pub fn register_services() { todo!("add remote serice support") } - fn check_action_visibility(action: &Action, node: &Arc) -> bool { + fn check_action_visibility(action: &Action, node: &Node) -> bool { match action.visibility { Visibility::Published => true, Visibility::Public => true, @@ -85,12 +86,14 @@ impl Registry { } fn register_actions( &mut self, - node: Arc, - service: Arc, + service_full_name: &str, actions: Vec, - ) { + ) -> anyhow::Result<()> { + let node = self.nodes.local_node()?; + let service = self.services.get_mut(service_full_name, Some(&node.id))?; + actions.iter().for_each(|action| { - if !Registry::check_action_visibility(action, &node) { + if !Registry::check_action_visibility(action, node) { return; } if node.local { @@ -99,19 +102,17 @@ impl Registry { //TODO: for remote services return; } - let node = Arc::clone(&node); - let service = Arc::clone(&service); + self.actions.add(node, service, action.to_owned()); //TODO: + // service.add_action(action) //add the action to the service. }); + Ok(()) } fn create_private_action_endpoint(&self, action: Action) -> anyhow::Result { - let local_node = match &self.nodes.local_node { - Some(node) => node, - None => bail!("No local node available"), - }; - let node = Arc::clone(local_node); + let node = self.nodes.local_node()?; + todo!("add service to action") // let action_ep = ActionEndpoint::new(node, service, action); // Ok(action_ep) @@ -168,20 +169,18 @@ impl Registry { todo!() } - fn get_local_node_info(&self, force: bool) -> Result { - if let None = self.nodes.local_node { - return Ok(self.regenerate_local_raw_info(None)); - } + fn get_local_node_info(&self, force: bool) -> anyhow::Result { + // if let None = self.nodes.local_node() { + // return Ok(self.regenerate_local_raw_info(None)); + // } if force { return Ok(self.regenerate_local_raw_info(None)); } - if let None = self.nodes.local_node { - return Err(RegistryError::NoLocalNodeFound); - } - let value = self.nodes.local_node.as_ref().unwrap().raw_info.to_owned(); + + let value = self.nodes.local_node()?.raw_info.to_owned(); match value { Some(value) => Ok(value), - None => Err(RegistryError::NoLocalNodeFound), + None => bail!(RegistryError::NoLocalNodeFound), } } fn get_node_info(&self, node_id: &str) -> Option { @@ -193,7 +192,7 @@ impl Registry { pub fn get_node_list(&self, only_available: bool, with_services: bool) -> Vec<&Node> { self.nodes.list(only_available, with_services) } - pub fn get_services_list(&self, opts: ListOptions) -> Vec<&Arc> { + pub fn get_services_list(&self, opts: ListOptions) -> Vec<&ServiceItem> { self.services.list(opts) } fn get_actions_list(&self, opts: ListOptions) -> Vec<&ActionEndpoint> { @@ -207,13 +206,6 @@ impl Registry { todo!() } } -use thiserror::Error; -#[derive(Error, Debug)] -enum RegistryError { - #[error("No local node found")] - NoLocalNodeFound, -} - #[cfg(test)] mod tests {} diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 2a97001..b78b502 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,10 +1,11 @@ +use anyhow::bail; + use crate::service::ServiceSpec; use super::*; -use regex::Regex; #[derive(PartialEq, Eq)] pub struct ServiceCatalog { - services: Vec>, + services: Vec, } impl ServiceCatalog { @@ -14,13 +15,11 @@ impl ServiceCatalog { } } ///Add a new service - pub fn add(&mut self, node: Arc, service: &ServiceSpec, local: bool) -> Arc { + pub fn add(&mut self, node: &Node, service: &ServiceSpec, local: bool) -> String { let service_item = ServiceItem::new(node, service, local); - let service_item = Arc::new(service_item); - - let item = Arc::clone(&service_item); + let full_name = service_item.full_name.clone(); self.services.push(service_item); - item + full_name } ///Check the service exsists pub fn has(&self, full_name: &str, node_id: Option<&str>) -> bool { @@ -33,7 +32,7 @@ impl ServiceCatalog { None => false, } } - pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&Arc> { + pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&ServiceItem> { self.services .iter() .find(|svc| svc.equals(full_name, node_id)) @@ -42,42 +41,46 @@ impl ServiceCatalog { &mut self, full_name: &str, node_id: Option<&str>, - ) -> Option<&mut Arc> { - self.services + ) -> anyhow::Result<&mut ServiceItem> { + let result = self + .services .iter_mut() - .find(|svc| svc.equals(full_name, node_id)) + .find(|svc| svc.equals(full_name, node_id)); + match result { + Some(service_item) => Ok(service_item), + None => bail!(RegistryError::NoServiceItemFound), + } } - pub fn list( - &self, - opts : ListOptions - ) -> Vec<&Arc> { - - self.services.iter().filter(|svc| { - if opts.skip_internal && get_internal_service_regex_match(&svc.name) { - return false; - } - if opts.only_local && !svc.local { - return false; - } - if opts.only_available && !svc.node.available { - return false; - } + pub fn list(&self, opts: ListOptions) -> Vec<&ServiceItem> { + self.services + .iter() + .filter(|svc| { + if opts.skip_internal && get_internal_service_regex_match(&svc.name) { + return false; + } + if opts.only_local && !svc.local { + return false; + } + //TODO: find a way to get node available + // if opts.only_available && !svc.node.available { + // return false; + // } - return true; - }).collect() + return true; + }) + .collect() // TODO:("implement grouping and all that stuff") - } pub fn get_local_node_service(&self) { todo!() } //remove all endpoints by node_id. pub fn remove_all_by_node_id(&mut self, node_id: &str) { - let services: Vec<&Arc> = self + let services: Vec<&ServiceItem> = self .services .iter() .filter(|svc| { - if svc.node.id == node_id { + if svc.node == node_id { todo!("remove actions and events in registry"); return false; } diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index 9e2be8f..2b8ec14 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -5,7 +5,7 @@ use super::*; #[derive(PartialEq, Eq, Clone)] pub struct ServiceItem { pub name: String, - pub node: Arc, + pub node: String, pub local: bool, pub full_name: String, version: String, @@ -17,9 +17,9 @@ pub struct ServiceItem { */ } impl ServiceItem { - pub fn new(node: Arc, service: &ServiceSpec, local: bool) -> Self { + pub fn new(node: &Node, service: &ServiceSpec, local: bool) -> Self { Self { - node, + node: node.id.clone(), local, actions: HashMap::new(), full_name: service.full_name.to_string(), @@ -29,7 +29,7 @@ impl ServiceItem { } pub fn equals(&self, full_name: &str, node_id: Option<&str>) -> bool { match node_id { - Some(id) => self.node.id == id && self.full_name == full_name, + Some(id) => self.node == id && self.full_name == full_name, None => self.full_name == full_name, } } @@ -53,4 +53,7 @@ impl ServiceItem { pub fn add_event(&mut self, event: EndpointList) { todo!("Implement the events map") } + pub fn unique_name(&self) -> String { + format!("{}{}{}", self.full_name, self.version, self.node) + } } From b528aa4078ed562f4623b07a0809a57f6799108c Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sun, 13 Feb 2022 15:24:39 +0530 Subject: [PATCH 17/22] feat: context --- src/broker.rs | 56 ++++++++--- src/context.rs | 168 ++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- src/registry/action_endpoint.rs | 12 ++- src/registry/event_endpoint.rs | 12 ++- src/registry/mod.rs | 3 +- 6 files changed, 233 insertions(+), 22 deletions(-) create mode 100644 src/context.rs diff --git a/src/broker.rs b/src/broker.rs index 9d8d1e2..dcffece 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,20 +1,20 @@ use std::{ collections::HashMap, - sync::{ - mpsc::{Receiver, }, - Arc, - }, + sync::{mpsc::Receiver, Arc}, }; use anyhow::{bail, Result}; -use chrono:: Utc; +use chrono::Utc; +use serde_json::Value; +use tokio::sync::oneshot; -use crate::{ - registry:: Logger, - service::ServiceSpec, - Registry, Service, -}; +use crate::{registry::Logger, service::ServiceSpec, Registry, Service}; + +#[derive(Default)] +pub struct BrokerOptions { + pub max_call_level: usize, +} pub struct ServiceBroker { reciever: Receiver, @@ -26,9 +26,10 @@ pub struct ServiceBroker { services: Vec, pub transit: Option, pub logger: Arc, + pub options: BrokerOptions, /* local bus - options + logger metricss middlewere @@ -98,7 +99,7 @@ impl ServiceBroker { }) } } -#[derive(PartialEq ,Debug)] +#[derive(Debug)] pub enum ServiceBrokerMessage { AddLocalService(Service), RegisterLocalService(ServiceSpec), @@ -107,7 +108,38 @@ pub enum ServiceBrokerMessage { timeout: i64, interval: i64, }, + Broadcast { + event_name: String, + data: Value, + opts: Value, + }, + Emit { + event_name: String, + data: Value, + opts: Value, + }, + Call { + action_name: String, + params: Value, + opts: Value, + result_channel: oneshot::Sender, + }, +} +impl PartialEq for ServiceBrokerMessage { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::AddLocalService(l0), Self::AddLocalService(r0)) => l0 == r0, + (Self::RegisterLocalService(l0), Self::RegisterLocalService(r0)) => l0 == r0, + (Self::WaitForServices { dependencies: l_dependencies, timeout: l_timeout, interval: l_interval }, Self::WaitForServices { dependencies: r_dependencies, timeout: r_timeout, interval: r_interval }) => l_dependencies == r_dependencies && l_timeout == r_timeout && l_interval == r_interval, + (Self::Broadcast { event_name: l_event_name, data: l_data, opts: l_opts }, Self::Broadcast { event_name: r_event_name, data: r_data, opts: r_opts }) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, + (Self::Emit { event_name: l_event_name, data: l_data, opts: l_opts }, Self::Emit { event_name: r_event_name, data: r_data, opts: r_opts }) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, + (Self::Call { action_name: l_action_name, params: l_params, opts: l_opts, result_channel: l_result_channel }, Self::Call { action_name: r_action_name, params: r_params, opts: r_opts, result_channel: r_result_channel }) => l_action_name == r_action_name && l_params == r_params && l_opts == r_opts, + _ => false + } + } } +#[derive(PartialEq, Debug)] +pub struct HandlerResult {} fn remove_from_list(list: &mut Vec, value: &T) { list.retain(|t| { diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..61e6c08 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,168 @@ +use std::sync::Arc; + +use anyhow::{bail, Result}; +use chrono::NaiveDateTime; +use serde_json::{json, Value}; +use tokio::sync::{mpsc::Sender, oneshot}; + +use crate::{ + registry::{ + service_item::ServiceItem, Action, ActionEndpoint, EndpointTrait, EndpointType, Event, + }, + HandlerResult, ServiceBroker, ServiceBrokerMessage, +}; + +struct ContextOptions { + timeout: i64, + retries: usize, +} + +pub struct Context { + id: String, + broker_sender: Sender, + action: Option, + event: Option, + node_id: Option, + tracing: bool, + level: usize, + broker: Arc, + endpoint: Option, + service: ServiceItem, + start_hr_time: NaiveDateTime, + options: ContextOptions, + event_type: EventType, + event_groups: Vec, + parent_id: Option, + caller: Option, + meta: Value, + locals: Value, + request_id: String, + parent_ctx: Option>>, + + /* + tracing + span + span_stack + need_ack + ack_id + startTime = null; + startHrTime = null; + stopTime = null; + duration = null; + error = null; + */ + cached_result: bool, +} +enum EventType { + Emit, + Broadcast, +} + +impl Context { + fn new(broker: Arc, endpoint: E) -> Self { + // let mut node_id = None; + // if let Some(broker) = broker { + // node_id = Some(broker.node_id.clone()); + // //broker generate uid; + // } + todo!() + } + + fn create(broker: Arc, endpoint: E, params: Value, opts: Value) { + let mut ctx = Context::new(broker, endpoint); + } + + fn set_endpoint(&mut self, endpoint: Option) { + //self.endpoint = Some(ep); + if let Some(ep) = endpoint { + self.node_id = Some(ep.id().to_owned()); + let ep_type = ep.ep_type(); + match ep_type { + EndpointType::Action => {} + EndpointType::Event => {} + } + } + } + + async fn call(&self, action_name: &str, params: Value, mut opts: Value) -> Result<()> { + let mut opts = opts.as_object(); + if let Some(opts) = opts { + //TODO:set the parent context + //opts.insert("parentCtx".to_string(), self.clone()); + } + let opts = Value::Object(opts.unwrap().to_owned()); + if self.options.timeout > 0 { + //TODO: callculate time difference for distributed distance + } + + if self.broker.options.max_call_level > 0 + && self.level >= self.broker.options.max_call_level + { + bail!("Max call level error") + } + + let (sender, mut recv) = oneshot::channel::(); + + let _result = self + .broker_sender + .send(ServiceBrokerMessage::Call { + action_name: action_name.to_string(), + params, + opts, + result_channel: sender, + }); + let result = recv.await?; + + //TODO:merge meta of the context object + + Ok(()) + } + + async fn emit(&self, event_name: &str, data: Value, opts: Option) { + let mut opts: Value = match opts { + Some(opts) => { + let value = json!({ "groups": opts }); + value + } + _ => json!({}), + }; + if let Some(groups) = opts.get("groups") { + if !groups.is_array() { + opts = json!({ "groups": vec![groups] }); + }; + } + //TODO:Set the parent context + let _result = self.broker_sender.send(ServiceBrokerMessage::Emit { + event_name: event_name.to_string(), + data, + opts, + }); + } + + async fn broadcast(&self, event_name: &str, data: Value, opts: Option) { + let mut opts: Value = match opts { + Some(opts) => { + let value = json!({ "groups": opts }); + value + } + _ => json!({}), + }; + if let Some(groups) = opts.get("groups") { + if !groups.is_array() { + opts = json!({ "groups": vec![groups] }); + }; + } + //TODO:Set the parent context + let _result = self.broker_sender.send(ServiceBrokerMessage::Broadcast { + event_name: event_name.to_string(), + data, + opts, + }); + } + fn start_span() { + todo!("while implementing tracing") + } + fn finish_span() { + todo!("while implementing tracing") + } +} diff --git a/src/lib.rs b/src/lib.rs index a33a840..7663c2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,9 @@ pub mod service; pub mod broker; pub mod logger; pub mod packet; +pub mod context; pub use service::Service; pub use registry::Registry; pub use broker::ServiceBrokerMessage; -pub use broker::ServiceBroker; \ No newline at end of file +pub use broker::ServiceBroker; +pub use broker::HandlerResult; \ No newline at end of file diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index 948ba8c..112bd22 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -9,9 +9,6 @@ pub struct ActionEndpoint { impl EndpointTrait for ActionEndpoint { type Data = Action; - fn update(&mut self, data: Self::Data) { - self.action = data; - } fn new(node: Arc, service: Arc, data: Self::Data) -> Self { let endpoint = Endpoint::new(node, service); let name = format!("{}:{}", endpoint.id, data.name); @@ -21,7 +18,6 @@ impl EndpointTrait for ActionEndpoint { action: data, } } - fn node(&self) -> &Node { &self.endpoint.node } @@ -29,6 +25,10 @@ impl EndpointTrait for ActionEndpoint { fn service(&self) -> &ServiceItem { &self.endpoint.service } + + fn update(&mut self, data: Self::Data) { + self.action = data; + } fn is_local(&self) -> bool { self.endpoint.local } @@ -41,4 +41,8 @@ impl EndpointTrait for ActionEndpoint { fn service_name(&self) -> &str { &self.endpoint.service.name } + + fn ep_type(&self) -> EndpointType { + EndpointType::Action + } } diff --git a/src/registry/event_endpoint.rs b/src/registry/event_endpoint.rs index d8cd7d6..2f0bc31 100644 --- a/src/registry/event_endpoint.rs +++ b/src/registry/event_endpoint.rs @@ -8,9 +8,6 @@ pub struct EventEndpoint { impl EndpointTrait for EventEndpoint { type Data = Event; - fn update(&mut self, data: Self::Data) { - self.event = data; - } fn new(node: Arc, service: Arc, data: Self::Data) -> Self { let endpoint = Endpoint::new(node, service); Self { @@ -19,7 +16,6 @@ impl EndpointTrait for EventEndpoint { event: data, } } - fn node(&self) -> &Node { &self.endpoint.node } @@ -27,6 +23,10 @@ impl EndpointTrait for EventEndpoint { fn service(&self) -> &ServiceItem { &self.endpoint.service } + + fn update(&mut self, data: Self::Data) { + self.event = data; + } fn is_local(&self) -> bool { self.endpoint.local } @@ -39,4 +39,8 @@ impl EndpointTrait for EventEndpoint { fn service_name(&self) -> &str { &self.endpoint.service.name } + + fn ep_type(&self) -> EndpointType { + EndpointType::Event + } } diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 6e7dd8c..79696d3 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -89,6 +89,7 @@ pub trait EndpointTrait { fn is_available(&self) -> bool; fn id(&self) -> &str; fn service_name(&self) -> &str; + fn ep_type(&self)->EndpointType; } #[derive(PartialEq, Eq, Clone)] @@ -114,7 +115,7 @@ impl Endpoint { } } -enum EndpointType { +pub enum EndpointType { Action, Event, } From 51c75abcf1c96505be2be93c4c5e9056d10d4afe Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Tue, 15 Feb 2022 14:48:04 +0530 Subject: [PATCH 18/22] refactor: fixed clippy errors --- src/broker.rs | 66 +++++++++++++++++++++++++++++---- src/context.rs | 22 +++++------ src/lib.rs | 18 +++++---- src/registry/action_catalog.rs | 22 +++-------- src/registry/endpoint_list.rs | 25 +++++-------- src/registry/node.rs | 5 +-- src/registry/node_catalog.rs | 19 ++++------ src/registry/registry.rs | 11 +++--- src/registry/service_catalog.rs | 19 +++------- src/service.rs | 17 ++++----- 10 files changed, 120 insertions(+), 104 deletions(-) diff --git a/src/broker.rs b/src/broker.rs index dcffece..f4c016f 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -60,7 +60,7 @@ impl ServiceBroker { fn destroy_service(&mut self, name: &str, version: &str) -> Result<()> { let service_index = self.get_local_service_index(name, version); - if let None = service_index { + if service_index.is_none() { bail!( "no service with the name {} and version {} found", name, @@ -86,7 +86,7 @@ impl ServiceBroker { } fn services_changed(&self, local_service: bool) { - if (self.started && local_service) { + if self.started && local_service { todo!("notifify remote nodes") } } @@ -95,7 +95,7 @@ impl ServiceBroker { if s.name == name && s.version == version { return true; } - return false; + false }) } } @@ -130,11 +130,61 @@ impl PartialEq for ServiceBrokerMessage { match (self, other) { (Self::AddLocalService(l0), Self::AddLocalService(r0)) => l0 == r0, (Self::RegisterLocalService(l0), Self::RegisterLocalService(r0)) => l0 == r0, - (Self::WaitForServices { dependencies: l_dependencies, timeout: l_timeout, interval: l_interval }, Self::WaitForServices { dependencies: r_dependencies, timeout: r_timeout, interval: r_interval }) => l_dependencies == r_dependencies && l_timeout == r_timeout && l_interval == r_interval, - (Self::Broadcast { event_name: l_event_name, data: l_data, opts: l_opts }, Self::Broadcast { event_name: r_event_name, data: r_data, opts: r_opts }) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, - (Self::Emit { event_name: l_event_name, data: l_data, opts: l_opts }, Self::Emit { event_name: r_event_name, data: r_data, opts: r_opts }) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, - (Self::Call { action_name: l_action_name, params: l_params, opts: l_opts, result_channel: l_result_channel }, Self::Call { action_name: r_action_name, params: r_params, opts: r_opts, result_channel: r_result_channel }) => l_action_name == r_action_name && l_params == r_params && l_opts == r_opts, - _ => false + ( + Self::WaitForServices { + dependencies: l_dependencies, + timeout: l_timeout, + interval: l_interval, + }, + Self::WaitForServices { + dependencies: r_dependencies, + timeout: r_timeout, + interval: r_interval, + }, + ) => { + l_dependencies == r_dependencies + && l_timeout == r_timeout + && l_interval == r_interval + } + ( + Self::Broadcast { + event_name: l_event_name, + data: l_data, + opts: l_opts, + }, + Self::Broadcast { + event_name: r_event_name, + data: r_data, + opts: r_opts, + }, + ) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, + ( + Self::Emit { + event_name: l_event_name, + data: l_data, + opts: l_opts, + }, + Self::Emit { + event_name: r_event_name, + data: r_data, + opts: r_opts, + }, + ) => l_event_name == r_event_name && l_data == r_data && l_opts == r_opts, + ( + Self::Call { + action_name: l_action_name, + params: l_params, + opts: l_opts, + result_channel: l_result_channel, + }, + Self::Call { + action_name: r_action_name, + params: r_params, + opts: r_opts, + result_channel: r_result_channel, + }, + ) => l_action_name == r_action_name && l_params == r_params && l_opts == r_opts, + _ => false, } } } diff --git a/src/context.rs b/src/context.rs index 61e6c08..6cf859b 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,9 +6,7 @@ use serde_json::{json, Value}; use tokio::sync::{mpsc::Sender, oneshot}; use crate::{ - registry::{ - service_item::ServiceItem, Action, ActionEndpoint, EndpointTrait, EndpointType, Event, - }, + registry::{service_item::ServiceItem, Action, EndpointTrait, EndpointType, Event}, HandlerResult, ServiceBroker, ServiceBrokerMessage, }; @@ -85,7 +83,7 @@ impl Context { } async fn call(&self, action_name: &str, params: Value, mut opts: Value) -> Result<()> { - let mut opts = opts.as_object(); + let opts = opts.as_object(); if let Some(opts) = opts { //TODO:set the parent context //opts.insert("parentCtx".to_string(), self.clone()); @@ -101,16 +99,14 @@ impl Context { bail!("Max call level error") } - let (sender, mut recv) = oneshot::channel::(); + let (sender, recv) = oneshot::channel::(); - let _result = self - .broker_sender - .send(ServiceBrokerMessage::Call { - action_name: action_name.to_string(), - params, - opts, - result_channel: sender, - }); + let _result = self.broker_sender.send(ServiceBrokerMessage::Call { + action_name: action_name.to_string(), + params, + opts, + result_channel: sender, + }); let result = recv.await?; //TODO:merge meta of the context object diff --git a/src/lib.rs b/src/lib.rs index 7663c2f..e518b61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,14 @@ -pub mod registry; -pub mod strategies; -pub mod service; pub mod broker; +pub mod context; pub mod logger; pub mod packet; -pub mod context; -pub use service::Service; -pub use registry::Registry; -pub use broker::ServiceBrokerMessage; +pub mod registry; +pub mod service; +pub mod strategies; +pub use broker::HandlerResult; pub use broker::ServiceBroker; -pub use broker::HandlerResult; \ No newline at end of file +pub use broker::ServiceBrokerMessage; +pub use registry::Registry; +pub use service::Service; + +const INTERNAL_PREFIX: char = '$'; diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index 3916de4..ced6fda 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -2,18 +2,13 @@ use std::collections::HashMap; use super::*; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Default)] pub struct ActionCatalog { actions: ActionsMap, } impl ActionCatalog { - pub fn new() -> Self { - Self { - actions: HashMap::new(), - } - } - pub fn add(&mut self, node: &Node, service: &ServiceItem, action: Action) { + pub fn add(&mut self, node: &Node, service: &ServiceItem, action: Action) { let list = self.actions.get_mut(&action.name); match list { Some(list) => list.add(node, service, action), @@ -37,7 +32,7 @@ impl ActionCatalog { } fn remove_by_service(&mut self, service: &ServiceItem) { self.actions.iter_mut().for_each(|item| { - let (key, el) = item; + let (_, el) = item; el.remove_by_service(service); }); } @@ -53,7 +48,7 @@ impl ActionCatalog { .iter() .filter(|item| { let (name, ep_list) = item; - if opts.skip_internal && get_internal_service_regex_match(&name) { + if opts.skip_internal && get_internal_service_regex_match(name) { return false; } if opts.only_local && !ep_list.has_local() { @@ -70,15 +65,10 @@ impl ActionCatalog { } } } - return true; - }) - .collect(); - let res = res - .values() - .map(|ep| { - return ep.to_owned(); + true }) .collect(); + let res = res.values().map(|ep| ep.to_owned()).collect(); res } } diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index 1e9ce27..150fe86 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use crate::INTERNAL_PREFIX; use super::*; #[derive(PartialEq, Eq, Clone)] @@ -12,7 +12,7 @@ pub struct EndpointList { impl EndpointList { pub fn new(name: String, group: Option) -> Self { - let internal = name.starts_with("$"); + let internal = name.starts_with(INTERNAL_PREFIX); let endpoints = Vec::new(); let local_endpoints = Vec::new(); @@ -25,18 +25,14 @@ impl EndpointList { } } - pub fn add(&mut self, node: &Node, service:&ServiceItem, data: T::Data) { + pub fn add(&mut self, node: &Node, service: &ServiceItem, data: T::Data) { let entry = self .endpoints .iter_mut() .find(|x| x.service_name() == service.unique_name()); - - match entry { - Some(found) => { - found.update(data); - return; - } - None => {} + if let Some(entry) = entry { + entry.update(data); + return; } let ep = T::new(&node.id, service, data); @@ -67,10 +63,10 @@ impl EndpointList { return true; } } - return false; + false } pub fn has_local(&self) -> bool { - self.local_endpoints.len() > 0 + !self.local_endpoints.is_empty() } fn update_local_endpoints(&mut self) { @@ -94,10 +90,7 @@ impl EndpointList { .find(|e| e.id() == node_id && e.is_available()) } fn has_node_id(&self, node_id: &str) -> bool { - match self.endpoints.iter().find(|e| e.id() == node_id) { - Some(_) => true, - None => false, - } + self.endpoints.iter().find(|e| e.id() == node_id).is_some() } pub fn remove_by_service(&mut self, service: &ServiceItem) { self.endpoints.retain(|ep| { diff --git a/src/registry/node.rs b/src/registry/node.rs index 5a4c090..ad48da9 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -1,9 +1,8 @@ -use std::{net::IpAddr, sync::Arc}; +use std::{net::IpAddr }; use chrono::Duration; use serde_json::Value; -use super::ServiceItem; #[derive(PartialEq, Eq, Clone)] pub struct Node { @@ -35,7 +34,7 @@ pub struct Node { impl Node { pub fn new(id: String) -> Self { Self { - id: id, + id, instance_id: None, available: true, local: false, diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index 9768ae4..f4320e8 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -1,12 +1,10 @@ use std::{collections::HashMap, net::IpAddr, sync::Arc}; -use std::sync::RwLock; - use anyhow::bail; use crate::registry::RegistryError; -use super::{node, Client, Logger, Node, Registry}; +use super::{Client, Node}; pub struct NodeCatalog { nodes: HashMap, @@ -25,7 +23,7 @@ impl NodeCatalog { let client = Client { client_type: "rust".to_string(), lang_version: "1.56.1".to_string(), - version: version, + version, }; let node = Node::new(node_id) .set_local(true) @@ -46,10 +44,7 @@ impl NodeCatalog { self.nodes.insert(id.to_string(), node); } pub fn had_node(&self, id: &str) -> bool { - match self.nodes.get(id) { - Some(_) => true, - None => false, - } + self.nodes.get(id).is_some() } pub fn get_node(&self, id: &str) -> Option<&Node> { self.nodes.get(id) @@ -100,10 +95,10 @@ impl NodeCatalog { if only_available && !node.available { return false; } - if with_services && node.services_len() <= 0 { + if with_services && node.services_len() == 0 { return false; } - return true; + true }) .collect() } @@ -114,10 +109,10 @@ impl NodeCatalog { if only_available && !node.available { return false; } - if with_services && node.services_len() <= 0 { + if with_services && node.services_len() == 0 { return false; } - return true; + true }) .collect() } diff --git a/src/registry/registry.rs b/src/registry/registry.rs index 19c11ac..ea3e58e 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,7 +1,7 @@ use crate::{service::ServiceSpec, ServiceBroker, ServiceBrokerMessage}; use super::*; -use anyhow::{bail, Error}; +use anyhow::bail; use serde_json::Value; use tokio::sync::mpsc::Sender; @@ -23,10 +23,10 @@ pub struct Registry { impl Registry { pub fn new(broker: Arc, broker_sender: Sender) -> Self { let logger = &broker.logger; - let logger = Arc::clone(&logger); + let logger = Arc::clone(logger); let nodes = NodeCatalog::new(); let services = ServiceCatalog::new(); - let actions = ActionCatalog::new(); + let actions = ActionCatalog::default(); Registry { logger, broker_sender, @@ -98,11 +98,10 @@ impl Registry { } if node.local { //TODO:stuff with middleware and handlers. - } else if let Some(_) = self.broker.transit { + } else if self.broker.transit.is_some() { //TODO: for remote services return; } - self.actions.add(node, service, action.to_owned()); //TODO: // service.add_action(action) @@ -165,7 +164,7 @@ impl Registry { todo!() } - fn regenerate_local_raw_info(&self, incSeq: Option) -> Value { + fn regenerate_local_raw_info(&self, inc_seq: Option) -> Value { todo!() } diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index b78b502..8ff998c 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,19 +1,15 @@ use anyhow::bail; -use crate::service::ServiceSpec; +use crate::{service::ServiceSpec, errors::RegistryError}; use super::*; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq , Default)] pub struct ServiceCatalog { services: Vec, } impl ServiceCatalog { - pub fn new() -> Self { - Self { - services: Vec::new(), - } - } + ///Add a new service pub fn add(&mut self, node: &Node, service: &ServiceSpec, local: bool) -> String { let service_item = ServiceItem::new(node, service, local); @@ -27,10 +23,7 @@ impl ServiceCatalog { .services .iter() .find(|svc| svc.equals(full_name, node_id)); - match svc { - Some(_) => true, - None => false, - } + svc.is_some() } pub fn get(&self, full_name: &str, node_id: Option<&str>) -> Option<&ServiceItem> { self.services @@ -66,7 +59,7 @@ impl ServiceCatalog { // return false; // } - return true; + true }) .collect() // TODO:("implement grouping and all that stuff") @@ -97,7 +90,7 @@ impl ServiceCatalog { return false; } - return true; + true }) } } diff --git a/src/service.rs b/src/service.rs index c7dfda6..5017b4d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -83,15 +83,14 @@ pub struct ServiceSpec { impl Service { fn get_service_spec(&self) -> ServiceSpec { //TODO: do something about actions and events - let service_spec = ServiceSpec { + ServiceSpec { name: self.name.clone(), full_name: self.full_name.clone(), settings: self.get_public_settings(), version: self.version.clone(), actions: None, events: None, - }; - service_spec + } } fn parse_service_schema(&mut self, schema: Schema) { @@ -172,7 +171,7 @@ impl Service { let _result = self .broker_sender .send(ServiceBrokerMessage::RegisterLocalService( - Service::get_service_spec(&self), + Service::get_service_spec(self), )); info!("Service {} started.", self.full_name); @@ -219,11 +218,11 @@ impl Service { todo!() } - async fn wait_for_services(&self, service_names: &Vec, timeout: i64, interval: i64) { + async fn wait_for_services(&self, service_names: &[String], timeout: i64, interval: i64) { let _result = self .broker_sender .send(ServiceBrokerMessage::WaitForServices { - dependencies: service_names.clone(), + dependencies: service_names.to_vec(), interval, timeout, }); @@ -467,8 +466,8 @@ mod tests { let version = "1.0".to_string(); let version = Some(&version); let full_name = Service::get_versioned_full_name(name, version); - assert_eq!(full_name , expected_full_name); + assert_eq!(full_name, expected_full_name); let full_name_2 = Service::get_versioned_full_name(name, None); - assert_eq!(full_name_2 , name); - } + assert_eq!(full_name_2, name); + } } From 6c7905c385ceda5cfeb7b7ea4f03b9f2cf6f390e Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 19 Feb 2022 21:53:46 +0530 Subject: [PATCH 19/22] feat:ip-addr utilities --- src/utils.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/utils.rs diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..0d6f0cb --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,31 @@ +use std::borrow::Cow; + +use uuid::Uuid; + +pub(crate) fn generate_uuid() -> String { + Uuid::new_v4().to_string() +} + +fn remove_from_list(list: &mut Vec, value: &T) { + list.retain(|t| { + if t == value { + return false; + } + true + }); +} +pub(crate) fn hostname() -> Cow<'static, str> { + hostname::get() + .map(|s| Cow::Owned(s.to_string_lossy().to_string().to_lowercase())) + .unwrap_or_else(|_| Cow::Borrowed("unknown_host_name")) +} + +pub(crate) fn ip_list() -> Vec { + get_if_addrs::get_if_addrs() + .unwrap_or_default() + .iter() + .map(|interface| interface.addr.ip()) + .filter(|ip| ip.is_ipv4() && !ip.is_loopback()) + .map(|ip| ip.to_string()) + .collect() +} From 1f59511e776977bf0649e7ea89331d9be2872b82 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 19 Feb 2022 21:54:14 +0530 Subject: [PATCH 20/22] feat:basic error enums --- src/errors/mod.rs | 4 ++++ src/errors/registry.rs | 8 ++++++++ src/errors/service_broker.rs | 14 ++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 src/errors/mod.rs create mode 100644 src/errors/registry.rs create mode 100644 src/errors/service_broker.rs diff --git a/src/errors/mod.rs b/src/errors/mod.rs new file mode 100644 index 0000000..790bf1f --- /dev/null +++ b/src/errors/mod.rs @@ -0,0 +1,4 @@ +mod registry; +mod service_broker; +pub use registry::RegistryError; +pub use service_broker::ServiceBrokerError; diff --git a/src/errors/registry.rs b/src/errors/registry.rs new file mode 100644 index 0000000..ce9f62d --- /dev/null +++ b/src/errors/registry.rs @@ -0,0 +1,8 @@ +use thiserror::Error; +#[derive(Error, Debug)] +pub enum RegistryError { + #[error("No local node found")] + NoLocalNodeFound, + #[error("No service found")] + NoServiceItemFound, +} diff --git a/src/errors/service_broker.rs b/src/errors/service_broker.rs new file mode 100644 index 0000000..ee83608 --- /dev/null +++ b/src/errors/service_broker.rs @@ -0,0 +1,14 @@ +use thiserror::Error; +#[derive(Error, Debug)] +pub enum ServiceBrokerError { + #[error("Service {action_name:?} is not registered locally.")] + ServiceNotFound { + action_name: String, + node_id: String, + }, + #[error("Service {action_name:?} is not available locally.")] + ServiceNotAvailable { + action_name: String, + node_id: String, + }, +} From cd25d17c7dcd9a784969325daa0859cc0e4d5794 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Sat, 19 Feb 2022 21:54:42 +0530 Subject: [PATCH 21/22] feat:service broker enabled for calling actions: --- Cargo.lock | 99 +++++- Cargo.toml | 7 +- makefile | 6 +- src/broker.rs | 546 ++++++++++++++++++++++++++++++-- src/context.rs | 181 +++++++---- src/lib.rs | 2 + src/logger.rs | 1 - src/packet.rs | 1 - src/registry/action_catalog.rs | 2 +- src/registry/action_endpoint.rs | 2 +- src/registry/endpoint_list.rs | 93 +++++- src/registry/mod.rs | 36 +-- src/registry/node.rs | 19 +- src/registry/node_catalog.rs | 44 ++- src/registry/registry.rs | 41 ++- src/registry/service_catalog.rs | 5 +- src/registry/service_item.rs | 2 +- src/service.rs | 63 ++-- src/strategies/mod.rs | 23 +- src/strategies/round_robin.rs | 40 ++- 20 files changed, 974 insertions(+), 239 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edf474a..fad45ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -46,6 +46,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "c_linked_list" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" + [[package]] name = "cfg-if" version = "1.0.0" @@ -62,7 +68,7 @@ dependencies = [ "num-integer", "num-traits", "time", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -97,6 +103,45 @@ dependencies = [ "termcolor", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "get_if_addrs" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" +dependencies = [ + "c_linked_list", + "get_if_addrs-sys", + "libc", + "winapi 0.2.8", +] + +[[package]] +name = "get_if_addrs-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" +dependencies = [ + "gcc", + "libc", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -106,6 +151,17 @@ dependencies = [ "libc", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + [[package]] name = "humantime" version = "2.1.0" @@ -157,6 +213,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "memchr" version = "2.4.1" @@ -173,7 +235,7 @@ dependencies = [ "log", "miow", "ntapi", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -182,7 +244,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -193,12 +255,15 @@ dependencies = [ "chrono", "derive_more", "env_logger", + "get_if_addrs", + "hostname", "lazy_static", "log", "regex", "serde_json", "thiserror", "tokio", + "uuid", ] [[package]] @@ -207,7 +272,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -267,7 +332,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -427,7 +492,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -446,7 +511,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "tokio-macros", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -466,12 +531,28 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -494,7 +575,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b81d0a9..14cfeb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,11 @@ env_logger = "0.9.0" log= "0.4.14" serde_json = "1.0.0" anyhow = "1.0.53" -tokio = { version = "1.16.1", features = ["full"] } +tokio = { version = "1.16.1", features = ["full" ,"time"] } regex = "1.5.4" lazy_static = "1.3.0" derive_more = "0.99.17" -thiserror = "1.0" \ No newline at end of file +thiserror = "1.0" +uuid = { version = "0.8", features = ["serde", "v4"] } +hostname = "0.3.1" +get_if_addrs = "0.5.3" \ No newline at end of file diff --git a/makefile b/makefile index d7ea6f4..beec8ab 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,8 @@ #Run library test while suppressing the warnings test: RUSTFLAGS=-Awarnings cargo test --lib -- --nocapture -.PHONY: test \ No newline at end of file +test-broker: + RUSTFLAGS=-Awarnings cargo test --lib -- broker::tests --nocapture +test-services: + RUSTFLAGS=-Awarnings cargo test --lib -- services::tests --nocapture +.PHONY: test test-broker test-services \ No newline at end of file diff --git a/src/broker.rs b/src/broker.rs index f4c016f..101490e 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -1,32 +1,124 @@ use std::{ + any::Any, collections::HashMap, sync::{mpsc::Receiver, Arc}, }; use anyhow::{bail, Result}; +use log::{debug, info, warn}; -use chrono::Utc; +use crate::{ + context::Context, + errors::ServiceBrokerError, + registry::{self, endpoint_list, node, ActionEndpoint, EndpointTrait, EventEndpoint, Payload}, + strategies::{RoundRobinStrategy, Strategy}, + utils, +}; +use chrono::{DateTime, Duration, Local, NaiveDateTime, Utc}; use serde_json::Value; -use tokio::sync::oneshot; +use tokio::{ + sync::{ + mpsc::{UnboundedReceiver, UnboundedSender}, + oneshot, RwLock, + }, + task, +}; use crate::{registry::Logger, service::ServiceSpec, Registry, Service}; -#[derive(Default)] +#[derive(Debug)] +struct RetryPolicy { + enabled: bool, + retries: usize, + delay: usize, + max_delay: usize, + factor: usize, + /* + check : + */ +} +impl Default for RetryPolicy { + fn default() -> Self { + Self { + enabled: false, + retries: 5, + delay: 100, + max_delay: 1000, + factor: 2, + } + } +} + +#[derive(Debug)] pub struct BrokerOptions { + transporter: String, + heartbeat_frequency: Duration, + heartbeat_timeout: Duration, + offline_check_frequency: Duration, + offline_timeout: Duration, + neighbours_checkout_timeout: Duration, + wait_for_dependencies_timeout: Duration, + namespace: String, + request_timeout: Duration, + mcall_timeout: Duration, + retry_policy: RetryPolicy, pub max_call_level: usize, + pub metrics: bool, + metrics_rate: f32, + wait_for_neighbours_interval: Duration, + dont_wait_for_neighbours: bool, + strategy_factory: RwLock, + pub metadata : Value + /* + discover_node_id : fn()->String, + metrics bool + metric + middleware + loglevel + logformat + transporter factory + */ } +impl Default for BrokerOptions { + fn default() -> Self { + Self { + transporter: "TCP".to_string(), + heartbeat_frequency: Duration::seconds(5), + heartbeat_timeout: Duration::seconds(15), + offline_check_frequency: Duration::seconds(20), + offline_timeout: Duration::minutes(10), + dont_wait_for_neighbours: true, + neighbours_checkout_timeout: Duration::seconds(2), + wait_for_dependencies_timeout: Duration::seconds(2), + namespace: "".to_string(), + request_timeout: Duration::seconds(3), + mcall_timeout: Duration::seconds(5), + retry_policy: RetryPolicy::default(), + metrics: false, + metrics_rate: 1.0, + max_call_level: 100, + wait_for_neighbours_interval: Duration::milliseconds(200), + strategy_factory: RwLock::new(RoundRobinStrategy::new()),metadata:Value::Null + } + } +} + +#[derive(Debug)] + pub struct ServiceBroker { - reciever: Receiver, + reciever: UnboundedReceiver, + pub(crate) sender: UnboundedSender, started: bool, namespace: Option, - metdata: HashMap, + metdata: Payload, pub node_id: String, - instance: String, + pub instance: String, services: Vec, pub transit: Option, pub logger: Arc, pub options: BrokerOptions, + /* local bus @@ -40,8 +132,9 @@ pub struct ServiceBroker { tracer transporter */ - registry: Registry, + registry: Option, } +#[derive(Debug)] pub struct Transit {} @@ -51,14 +144,21 @@ impl ServiceBroker { self.started = true; } + fn stop(&mut self) { + todo!("handle stopping the broker") + } + fn add_local_service(&mut self, service: Service) { self.services.push(service); } - fn register_local_service(&mut self, service: ServiceSpec) { - self.registry.register_local_service(service); + fn register_local_service(&mut self, service: ServiceSpec) -> anyhow::Result<()> { + match &mut self.registry { + Some(registry) => registry.register_local_service(service), + None => todo!(), + } } - fn destroy_service(&mut self, name: &str, version: &str) -> Result<()> { + async fn destroy_service(&mut self, name: &str, version: &str) -> Result<()> { let service_index = self.get_local_service_index(name, version); if service_index.is_none() { bail!( @@ -73,14 +173,16 @@ impl ServiceBroker { { let service = self.services.get_mut(service_index).unwrap(); full_name = service.full_name.clone(); - service.stop(); + service.stop().await; } { self.services.remove(service_index); } + match &mut self.registry { + Some(registry) => registry.unregister_service(&full_name, Some(&self.node_id)), + None => todo!(), + } - self.registry - .unregister_service(&full_name, Some(&self.node_id)); self.services_changed(true); Ok(()) } @@ -95,10 +197,198 @@ impl ServiceBroker { if s.name == name && s.version == version { return true; } - false + false }) } + + fn wait_for_services(&self, service_names: Vec, timeout: i64, interval: i64) { + info!("Waiting for service(s) {:?}", service_names); + let start_time = Local::now(); + let check = async { + let service_statuses = service_names.iter().map(|service_name| { + let status = self + .registry + .as_ref() + .unwrap() + .has_services(service_name, None); + return ServiceStatus { + name: service_name, + available: status, + }; + }); + + let available_services: Vec = service_statuses + .clone() + .filter(|service| service.available) + .collect(); + if available_services.len() == service_names.len() { + info!("Service(s) {:?} are available.", service_names); + return; + } + + let unavailable_services: Vec = service_statuses + .filter(|service| !service.available) + .collect(); + + debug!("{} {:?} of {} services are availablle. {} {} are still unavailable. Waiting for further..." , + available_services.len(), + available_services.iter().map(|service_status| service_status.name).collect::(), + service_names.len(), + unavailable_services.len(), + unavailable_services.iter().map(|service_status|service_status.name).collect::()); + + if Local::now() - start_time > Duration::milliseconds(timeout) { + //TODO: reject the future. + return; + } + //TODO: add the setTimeout thing + // Delay::new() + }; + } + + async fn call( + &self, + action_name: &str, + params: Payload, + opts: CallOptions, + sender: oneshot::Sender>, + ) -> anyhow::Result<()> { + let ctx = Context::new(&self, "test_service".to_string()); + let ctx = ctx.child_action_context(&self, params.clone(), Some(opts.clone()), action_name); + let endpoint = self.find_next_action_endpoint(action_name, &opts, &ctx)?; + let endpoint = endpoint.clone(); + if endpoint.is_local() { + debug!( + "Call action locally. {{ action: {} , request_id : {:?} }}", + ctx.action(), + ctx.request_id + ) + } else { + debug!( + "Call action on remote node. {{ action: {} , node_id : {} , request_id : {:?} }}", + ctx.action(), + ctx.node_id(), + ctx.request_id + ) + } + task::spawn(async move { + let result = (endpoint.action.handler)(ctx, Some(params)); + let _ = sender.send(Ok(result)); + }); + Ok(()) + } + + fn find_next_action_endpoint( + &self, + action_name: &str, + opts: &CallOptions, + ctx: &Context, + ) -> anyhow::Result<&ActionEndpoint> { + if let Some(node_id) = &opts.node_id { + let ep = self + .registry + .as_ref() + .unwrap() + .get_action_endpoint_by_node_id(action_name, node_id); + match ep { + Some(ep) => Ok(ep), + None => { + warn!("Service {} is not found on {} node.", action_name, node_id); + + bail!(ServiceBrokerError::ServiceNotFound { + action_name: action_name.to_string(), + node_id: node_id.to_string() + }) + } + } + } else { + //Get endpoint list by action name. + let ep_list = self + .registry + .as_ref() + .unwrap() + .get_action_endpoints(action_name); + match ep_list { + Some(ep_list) => { + let ep = ep_list.next(ctx, &self.options.strategy_factory); + match ep { + Some(ep) => Ok(ep), + None => { + warn!("Service {} is not available.", action_name); + bail!(ServiceBrokerError::ServiceNotAvailable { + action_name: action_name.to_string(), + node_id: "".to_string() + }); + } + } + } + None => { + warn!("Service {} is not registered.", action_name); + + bail!(ServiceBrokerError::ServiceNotFound { + action_name: action_name.to_string(), + node_id: "".to_string() + }) + } + } + } + } + + fn get_local_action_endpoint( + &self, + action_name: &str, + ctx: &Context, + ) -> anyhow::Result<&ActionEndpoint> { + //Find action endpoints by name. + let ep_list = self + .registry + .as_ref() + .unwrap() + .get_action_endpoints(action_name); + let available = match ep_list { + Some(endpoint_list) => !endpoint_list.has_local(), + None => false, + }; + if !available { + bail!(ServiceBrokerError::ServiceNotFound { + action_name: action_name.to_string(), + node_id: self.node_id.clone() + }) + } + //Get local endpoint. + match ep_list + .unwrap() + .next_local(ctx, &self.options.strategy_factory) + { + Some(ep) => Ok(ep), + None => { + bail!(ServiceBrokerError::ServiceNotAvailable { + action_name: action_name.to_string(), + node_id: self.node_id.clone() + }) + } + } + } + + fn get_local_node_info(&self) -> anyhow::Result { + self.registry.as_ref().unwrap().get_local_node_info(false) + } + + fn emit_local_services(&self, ctx: Context) { + todo!("event catalog implementation left") + + // self.registry. + } + + fn get_cpu_usage() { + todo!("get cpu usageI") + } + + fn generate_uid() -> String { + utils::generate_uuid() + } } + #[derive(Debug)] pub enum ServiceBrokerMessage { AddLocalService(Service), @@ -120,10 +410,11 @@ pub enum ServiceBrokerMessage { }, Call { action_name: String, - params: Value, - opts: Value, - result_channel: oneshot::Sender, + params: Payload, + opts: CallOptions, + result_channel: oneshot::Sender>, }, + Close, } impl PartialEq for ServiceBrokerMessage { fn eq(&self, other: &Self) -> bool { @@ -184,18 +475,225 @@ impl PartialEq for ServiceBrokerMessage { result_channel: r_result_channel, }, ) => l_action_name == r_action_name && l_params == r_params && l_opts == r_opts, + (Self::Close, Self::Close) => true, _ => false, } } } + #[derive(PartialEq, Debug)] -pub struct HandlerResult {} +pub struct HandlerResult { + pub(crate) data: u32, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CallOptions { + meta: Payload, + node_id: Option, +} -fn remove_from_list(list: &mut Vec, value: &T) { - list.retain(|t| { - if t == value { - return false; +struct ServiceStatus<'a> { + name: &'a str, + available: bool, +} + +#[cfg(test)] +mod tests { + use crate::{ + registry::{Action, Visibility}, + service::{Schema, SchemaMerged}, + Registry, Service, + }; + use tokio::{sync::mpsc, task}; + + use super::*; + fn test_merge_func() { + println!("test merge function"); + } + fn test_started_func() { + println!("test start func"); + } + fn test_created_func() { + println!("test created func"); + } + fn test_stop_func() { + println!("test stop func"); + } + fn action_func(context: Context, payload: Option) -> HandlerResult { + println!("action_func"); + + let data = fibonacci(40); + HandlerResult { data } + } + + fn get_test_broker( + recv: mpsc::UnboundedReceiver, + sender: mpsc::UnboundedSender, + ) -> ServiceBroker { + ServiceBroker { + reciever: recv, + started: false, + namespace: None, + metdata: Payload {}, + sender, + node_id: "test_node".to_string(), + instance: "test_instance".to_string(), + services: Vec::new(), + transit: None, + logger: Arc::new(Logger {}), + options: BrokerOptions::default(), + registry: None, + } + } + fn get_test_schema(dependencies: Option>) -> Schema { + let merged = SchemaMerged::MergedFn(test_merge_func); + let schema = Schema { + mixins: None, + actions: None, + events: None, + merged, + name: "test_service".to_string(), + version: None, + settings: HashMap::new(), + metadata: None, + created: Some(test_created_func), + started: Some(test_started_func), + stopped: Some(test_stop_func), + dependencies: dependencies, + }; + + schema + } + fn fibonacci(n: u32) -> u32 { + match n { + 0 => 1, + 1 => 1, + _ => fibonacci(n - 1) + fibonacci(n - 2), } - return true; - }); + } + fn get_test_service( + schema: Option, + settings: Option>, + actions: Option>, + broker_sender: Option>, + ) -> Service { + let name = "test_service".to_string(); + let version = "1.0".to_string(); + let full_name = Service::get_versioned_full_name(&name, Some(&version)); + let settings = match settings { + Some(settings) => settings, + None => HashMap::new(), + }; + let schema = match schema { + Some(schema) => schema, + None => get_test_schema(None), + }; + + let original_schema = get_test_schema(None); + let broker_sender = match broker_sender { + Some(sender) => sender, + None => { + let (sender, recv) = mpsc::unbounded_channel::(); + sender + } + }; + let service = Service { + name, + full_name, + version, + settings, + schema, + original_schema: Some(original_schema), + metadata: HashMap::new(), + actions: actions, + events: None, + broker_sender, + }; + service + } + #[test] + fn broker_call() { + let (sender, recv) = mpsc::unbounded_channel::(); + let (_, fake_recv) = mpsc::unbounded_channel(); + let mut broker_original = get_test_broker(recv, sender.clone()); + let broker = get_test_broker(fake_recv, sender.clone()); + let broker_arc = Arc::new(broker); + let action = Action { + name: "action_func".to_string(), + visibility: Visibility::Public, + handler: action_func, + }; + let service = get_test_service(None, None, Some(vec![action]), Some(sender.clone())); + let registry = Registry::new(Arc::clone(&broker_arc), sender.clone()); + let actions = registry.actions.clone(); + broker_original.registry = Some(registry); + broker_original.start(); + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + rt.block_on(async { + let join_handle = rt.spawn(async move { + while let Some(message) = broker_original.reciever.recv().await { + match message { + ServiceBrokerMessage::AddLocalService(service) => { + broker_original.add_local_service(service) + } + ServiceBrokerMessage::RegisterLocalService(service_spec) => broker_original + .register_local_service(service_spec) + .unwrap(), + ServiceBrokerMessage::Call { + action_name, + params, + opts, + result_channel, + } => { + let result = broker_original + .call(&action_name, params, opts, result_channel) + .await; + } + ServiceBrokerMessage::Close => return, + _ => {} + } + } + }); + // let sender = sender.clone(); + task::spawn(async move { + service.init().await; + service.start().await; + println!("{:?}", actions); + let start = Local::now(); + let sender = sender.clone(); + let mut jhs = Vec::new(); + for _ in 0..10 { + let sender = sender.clone(); + let jh = task::spawn(async move { + let (one_sender, recv) = oneshot::channel(); + + let _ = sender.send(ServiceBrokerMessage::Call { + action_name: "action_func".to_string(), + params: Payload {}, + opts: CallOptions { + meta: Payload {}, + node_id: Some("test_node".to_string()), + }, + result_channel: one_sender, + }); + let _result = recv.await; + }); + jhs.push(jh); + } + for jh in jhs{ + jh.await; + } + let end = Local::now(); + let __ = sender.send(ServiceBrokerMessage::Close); + println!("{:?}", end - start); + drop(sender); + }); + + let _ = join_handle.await; + }); + } } diff --git a/src/context.rs b/src/context.rs index 6cf859b..0c42bcf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -3,40 +3,46 @@ use std::sync::Arc; use anyhow::{bail, Result}; use chrono::NaiveDateTime; use serde_json::{json, Value}; -use tokio::sync::{mpsc::Sender, oneshot}; +use tokio::sync::{ + mpsc::{Sender, UnboundedSender}, + oneshot, +}; use crate::{ - registry::{service_item::ServiceItem, Action, EndpointTrait, EndpointType, Event}, - HandlerResult, ServiceBroker, ServiceBrokerMessage, + broker::{BrokerOptions, CallOptions}, + registry::{service_item::ServiceItem, Action, EndpointTrait, EndpointType, Event, Payload}, + utils, HandlerResult, ServiceBroker, ServiceBrokerMessage, }; +#[derive(Debug, Clone)] struct ContextOptions { - timeout: i64, - retries: usize, + timeout: Option, + retries: Option, } -pub struct Context { +#[derive(Debug)] +pub struct Context { id: String, - broker_sender: Sender, - action: Option, - event: Option, + pub request_id: Option, + broker_sender: UnboundedSender, + action: Option, + event: Option, + parent_id: Option, + event_groups: Option>, + event_type: EventType, + pub params: Option, + meta: Payload, + caller: Option, + locals: Option, node_id: Option, + tracing: bool, level: usize, - broker: Arc, - endpoint: Option, - service: ServiceItem, - start_hr_time: NaiveDateTime, - options: ContextOptions, - event_type: EventType, - event_groups: Vec, - parent_id: Option, - caller: Option, - meta: Value, - locals: Value, - request_id: String, - parent_ctx: Option>>, + service: String, + + options: ContextOptions, + parent_ctx: Option>, /* tracing span @@ -51,55 +57,122 @@ pub struct Context { */ cached_result: bool, } +#[derive(Debug)] enum EventType { Emit, Broadcast, } -impl Context { - fn new(broker: Arc, endpoint: E) -> Self { - // let mut node_id = None; - // if let Some(broker) = broker { - // node_id = Some(broker.node_id.clone()); - // //broker generate uid; - // } - todo!() +impl Context { + pub fn new(broker: &ServiceBroker, service: String) -> Self { + let id = utils::generate_uuid(); + let request_id = id.clone(); + let meta = Payload {}; + + Self { + id, + request_id: Some(request_id), + broker_sender: broker.sender.clone(), + action: None, + event: None, + parent_id: None, + event_groups: None, + event_type: EventType::Emit, + meta, + caller: None, + locals: None, + node_id: Some(broker.node_id.clone()), + tracing: false, + level: 1, + options: ContextOptions { + timeout: None, + retries: None, + }, + parent_ctx: None, + cached_result: false, + service: service, + params: None, + } } - fn create(broker: Arc, endpoint: E, params: Value, opts: Value) { - let mut ctx = Context::new(broker, endpoint); - } + pub fn child_action_context( + &self, + broker: &ServiceBroker, + params: Payload, + opts: Option, + action: &str, + ) -> Self { + // let parent_ctx = self.clone(); + let meta = self.meta.to_owned(); + if broker.options.metrics { + //TODO: + //meta = meta.add("tracing" , true) + } + if opts.is_some() { + //TODO: + //copy the options meta + } + let id = utils::generate_uuid(); + let mut request_id = id.clone(); + if let Some(id) = self.request_id.clone() { + request_id = id; + } - fn set_endpoint(&mut self, endpoint: Option) { - //self.endpoint = Some(ep); - if let Some(ep) = endpoint { - self.node_id = Some(ep.id().to_owned()); - let ep_type = ep.ep_type(); - match ep_type { - EndpointType::Action => {} - EndpointType::Event => {} - } + let mut caller = action.to_string(); + + let service: Vec<&str> = caller.split('.').collect(); + let service = service.get(0).unwrap().to_string(); + Self { + id, + request_id: Some(request_id), + broker_sender: self.broker_sender.clone(), + action: Some(action.to_string()), + event: None, + parent_id: Some(self.id.clone()), + event_groups: None, + event_type: EventType::Emit, + meta, + caller: Some(caller), + locals: self.locals.to_owned(), + node_id: self.node_id.clone(), + tracing: self.tracing, + level: self.level + 1, + options: self.options.to_owned(), + parent_ctx: None, + cached_result: false, + service: service, + params: Some(params), } } - async fn call(&self, action_name: &str, params: Value, mut opts: Value) -> Result<()> { - let opts = opts.as_object(); - if let Some(opts) = opts { - //TODO:set the parent context - //opts.insert("parentCtx".to_string(), self.clone()); - } - let opts = Value::Object(opts.unwrap().to_owned()); - if self.options.timeout > 0 { + pub fn action(&self) -> &str { + self.action.as_ref().unwrap() + } + pub fn node_id(&self) -> &String { + self.node_id.as_ref().unwrap() + } + + async fn call( + &self, + broker_options: &BrokerOptions, + action_name: &str, + params: Payload, + mut opts: CallOptions, + ) -> Result<()> { + // if let Some(opts) = opts { + //TODO:set the parent context + //opts.insert("parentCtx".to_string(), self.clone()); + // } + // let opts = Value::Object(opts.unwrap().to_owned()); + if self.options.timeout > Some(0) { //TODO: callculate time difference for distributed distance } - if self.broker.options.max_call_level > 0 - && self.level >= self.broker.options.max_call_level - { + if broker_options.max_call_level > 0 && self.level >= broker_options.max_call_level { bail!("Max call level error") } - let (sender, recv) = oneshot::channel::(); + let (sender, recv) = oneshot::channel::>(); let _result = self.broker_sender.send(ServiceBrokerMessage::Call { action_name: action_name.to_string(), diff --git a/src/lib.rs b/src/lib.rs index e518b61..1da9a74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,12 @@ pub mod broker; pub mod context; +pub mod errors; pub mod logger; pub mod packet; pub mod registry; pub mod service; pub mod strategies; +pub mod utils; pub use broker::HandlerResult; pub use broker::ServiceBroker; pub use broker::ServiceBrokerMessage; diff --git a/src/logger.rs b/src/logger.rs index 993ea22..80703e2 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,4 +1,3 @@ - trait LoggerTrait { fn init(); fn stop(); diff --git a/src/packet.rs b/src/packet.rs index 74bfdaf..8af8a94 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,4 +1,3 @@ - enum PacketType { Unknown, Event, diff --git a/src/registry/action_catalog.rs b/src/registry/action_catalog.rs index ced6fda..8930496 100644 --- a/src/registry/action_catalog.rs +++ b/src/registry/action_catalog.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use super::*; -#[derive(PartialEq, Eq, Default)] +#[derive(PartialEq, Eq, Default, Debug, Clone)] pub struct ActionCatalog { actions: ActionsMap, } diff --git a/src/registry/action_endpoint.rs b/src/registry/action_endpoint.rs index a8c6cfb..9d971c6 100644 --- a/src/registry/action_endpoint.rs +++ b/src/registry/action_endpoint.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct ActionEndpoint { endpoint: Endpoint, pub action: Action, diff --git a/src/registry/endpoint_list.rs b/src/registry/endpoint_list.rs index 150fe86..e0d0569 100644 --- a/src/registry/endpoint_list.rs +++ b/src/registry/endpoint_list.rs @@ -1,16 +1,18 @@ +use tokio::sync::RwLock; + use crate::INTERNAL_PREFIX; use super::*; -#[derive(PartialEq, Eq, Clone)] -pub struct EndpointList { +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct EndpointList { pub name: String, group: Option, internal: bool, - pub endpoints: Vec, - local_endpoints: Vec, + pub endpoints: Vec, + local_endpoints: Vec, } -impl EndpointList { +impl EndpointList { pub fn new(name: String, group: Option) -> Self { let internal = name.starts_with(INTERNAL_PREFIX); let endpoints = Vec::new(); @@ -25,7 +27,7 @@ impl EndpointList { } } - pub fn add(&mut self, node: &Node, service: &ServiceItem, data: T::Data) { + pub fn add(&mut self, node: &Node, service: &ServiceItem, data: E::Data) { let entry = self .endpoints .iter_mut() @@ -35,26 +37,83 @@ impl EndpointList { return; } - let ep = T::new(&node.id, service, data); + let ep = E::new(&node.id, service, data); self.endpoints.push(ep.clone()); if ep.is_local() { self.local_endpoints.push(ep) } } - fn get_first(&self) -> Option<&T> { + fn get_first(&self) -> Option<&E> { self.endpoints.get(0) } - fn select(&self) -> &T { - todo!() + fn select<'a, S: Strategy>( + &self, + list: Vec<&'a E>, + ctx: &Context, + strategy: &RwLock, + ) -> Option<&'a E> { + let mut strategy = strategy.blocking_write(); + let ret = strategy.select(list, Some(ctx)); + ret } - fn next(&self) -> &T { - todo!() + pub fn next(&self, ctx: &Context, strategy: &RwLock) -> Option<&E> { + if self.endpoints.is_empty() { + return None; + } + + if self.internal && self.has_local() { + return self.next_local(ctx, strategy); + } + + if self.endpoints.len() == 1 { + let ep = self.endpoints.get(0); + if let Some(ep) = ep { + ep.is_available(); + return Some(ep); + } + return None; + } + + //TODO: Search local item based on registr opts + let ep_list: Vec<&E> = self + .endpoints + .iter() + .filter(|ep| ep.is_available()) + .collect(); + if ep_list.is_empty() { + return None; + } + + self.select(ep_list, ctx, strategy) } - fn next_local(&self) -> &T { - todo!() + pub fn next_local(&self, ctx: &Context, strategy: &RwLock) -> Option<&E> { + if self.local_endpoints.is_empty() { + return None; + } + + if self.local_endpoints.len() == 1 { + let ep = self.local_endpoints.get(0); + if let Some(ep) = ep { + ep.is_available(); + return Some(ep); + } + return None; + } + + //TODO: Search local item based on registr opts + let ep_list: Vec<&E> = self + .endpoints + .iter() + .filter(|ep| ep.is_available()) + .collect(); + if ep_list.is_empty() { + return None; + } + + self.select(ep_list, ctx, strategy) } pub fn has_available(&self) -> bool { @@ -70,7 +129,7 @@ impl EndpointList { } fn update_local_endpoints(&mut self) { - let mut local: Vec = Vec::new(); + let mut local: Vec = Vec::new(); for ep in &self.endpoints { if ep.is_local() { let e = ep.clone(); @@ -84,13 +143,13 @@ impl EndpointList { pub fn count(&self) -> usize { self.endpoints.len() } - pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&T> { + pub fn get_endpoint_by_node_id(&self, node_id: &str) -> Option<&E> { self.endpoints .iter() .find(|e| e.id() == node_id && e.is_available()) } fn has_node_id(&self, node_id: &str) -> bool { - self.endpoints.iter().find(|e| e.id() == node_id).is_some() + self.endpoints.iter().any(|e| e.id() == node_id) } pub fn remove_by_service(&mut self, service: &ServiceItem) { self.endpoints.retain(|ep| { diff --git a/src/registry/mod.rs b/src/registry/mod.rs index caa96e4..1566041 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::sync::Arc; use super::service::Service; -use crate::strategies::Strategy; +use crate::{context::Context, strategies::Strategy, HandlerResult}; use action_catalog::ActionCatalog; pub use action_endpoint::ActionEndpoint; pub use endpoint_list::EndpointList; @@ -20,6 +20,7 @@ pub use event_endpoint::EventEndpoint; use lazy_static::lazy_static; pub use node::{Client, Node}; use node_catalog::NodeCatalog; + use regex::Regex; pub use registry::Registry; use service_catalog::ServiceCatalog; @@ -35,21 +36,25 @@ fn get_internal_service_regex_match(text: &str) -> bool { RE.is_match(text) } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Debug)] pub struct Logger {} -trait FnType {} +pub type ActionHandler = fn(Context, Option) -> HandlerResult; + +#[derive(Default, Debug, PartialEq, Eq, Clone)] +pub struct Payload {} #[derive(PartialEq, Eq, Clone, Debug)] + pub struct Action { pub name: String, - visibility: Visibility, - handler: fn(), + pub(crate) visibility: Visibility, + pub handler: ActionHandler, // service: Option, } impl Action { - pub fn new(name: String, handler: fn()) -> Self { + pub fn new(name: String, handler: ActionHandler) -> Self { Self { name, visibility: Visibility::Protected, @@ -64,15 +69,16 @@ impl Action { } #[derive(PartialEq, Eq, Clone, Debug)] -enum Visibility { +pub enum Visibility { Published, Public, Protected, Private, } #[derive(PartialEq, Eq, Clone, Debug)] -pub struct Event {} -impl FnType for Event {} +pub struct Event { + pub event_name: String, +} ///Endpoint trait for endpoint list pub trait EndpointTrait { @@ -85,10 +91,10 @@ pub trait EndpointTrait { fn is_available(&self) -> bool; fn id(&self) -> &str; fn service_name(&self) -> &str; - fn ep_type(&self)->EndpointType; + fn ep_type(&self) -> EndpointType; } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] struct Endpoint { service: String, state: bool, @@ -126,11 +132,3 @@ pub struct ListOptions { with_events: bool, grouping: bool, } -use thiserror::Error; -#[derive(Error, Debug)] -enum RegistryError { - #[error("No local node found")] - NoLocalNodeFound, - #[error("No service found")] - NoServiceItemFound, -} diff --git a/src/registry/node.rs b/src/registry/node.rs index ad48da9..aa29004 100644 --- a/src/registry/node.rs +++ b/src/registry/node.rs @@ -1,23 +1,22 @@ -use std::{net::IpAddr }; +use std::net::IpAddr; use chrono::Duration; use serde_json::Value; - -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Node { pub id: String, instance_id: Option, pub available: bool, pub local: bool, last_heartbeat_time: Duration, + metadata : Value, /* feields that need to be added later. config - metadata */ client: Option, - ip_list: Vec, + ip_list: Vec, port: Option, hostname: Option, udp_address: Option, @@ -40,6 +39,8 @@ impl Node { local: false, client: None, raw_info: None, + metadata : Value::Null, + //TODO: /* change this later with actual process uptime. */ @@ -83,7 +84,7 @@ impl Node { self.local = value; self } - pub fn set_ip_list(mut self, ip_list: Vec) -> Self { + pub fn set_ip_list(mut self, ip_list: Vec) -> Self { self.ip_list = ip_list; self } @@ -103,8 +104,12 @@ impl Node { self.seq = seq; self } + pub fn set_metadata(mut self , metadata:Value)->Self{ + self.metadata = metadata; + self + } } -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Client { pub(crate) client_type: String, diff --git a/src/registry/node_catalog.rs b/src/registry/node_catalog.rs index f4320e8..14ab60e 100644 --- a/src/registry/node_catalog.rs +++ b/src/registry/node_catalog.rs @@ -1,11 +1,18 @@ -use std::{collections::HashMap, net::IpAddr, sync::Arc}; +use std::{ + collections::HashMap, + net::{IpAddr, Ipv4Addr}, + sync::Arc, +}; use anyhow::bail; +use serde_json::Value; -use crate::registry::RegistryError; +use crate::{errors::RegistryError, utils}; use super::{Client, Node}; +#[derive(Debug)] + pub struct NodeCatalog { nodes: HashMap, local_node_id: String, @@ -19,26 +26,22 @@ impl NodeCatalog { } } ///Create a local node - fn create_local_node(&mut self, version: String, node_id: String, instance_id: String) { + pub fn create_local_node(&mut self, client_version: String, node_id: String, instance_id: String , metadata:Value) { let client = Client { client_type: "rust".to_string(), lang_version: "1.56.1".to_string(), - version, + version:client_version, }; let node = Node::new(node_id) .set_local(true) - .set_ip_list(get_ip_list()) + .set_ip_list(utils::ip_list()) .set_instance_id(instance_id) - .set_hostname(get_hostname()) + .set_hostname(utils::hostname().into_owned()) .set_seq(1) - .set_client(client); - //TODO:data constency between local node and node catalog + .set_client(client). + set_metadata(metadata); self.nodes.insert(node.id.to_string(), node.clone()); self.local_node_id = node.id; - todo!() - /* - node.metadata = self.broker.metadata.clone() - */ } pub fn add(&mut self, id: &str, node: Node) { self.nodes.insert(id.to_string(), node); @@ -49,22 +52,23 @@ impl NodeCatalog { pub fn get_node(&self, id: &str) -> Option<&Node> { self.nodes.get(id) } + pub fn get_node_mut(&mut self, id: &str) -> Option<&mut Node> { + self.nodes.get_mut(id) + } pub fn local_node(&self) -> anyhow::Result<&Node> { - match self.nodes.get(&self.local_node_id) { + match self.get_node(&self.local_node_id) { Some(node) => Ok(node), None => bail!(RegistryError::NoLocalNodeFound), } } pub fn local_node_mut(&mut self) -> anyhow::Result<&mut Node> { - match self.nodes.get_mut(&self.local_node_id) { + let local_node_id = self.local_node_id.clone(); + match self.get_node_mut(&local_node_id) { Some(node) => Ok(node), None => bail!(RegistryError::NoLocalNodeFound), } } - pub fn get_node_mut(&mut self, id: &str) -> Option<&mut Node> { - self.nodes.get_mut(id) - } pub fn delete(&mut self, id: &str) -> Option { self.nodes.remove(id) } @@ -123,9 +127,3 @@ impl NodeCatalog { self.nodes.values_mut().collect() } } -fn get_ip_list() -> Vec { - todo!() -} -fn get_hostname() -> String { - todo!() -} diff --git a/src/registry/registry.rs b/src/registry/registry.rs index ea3e58e..70ab00b 100644 --- a/src/registry/registry.rs +++ b/src/registry/registry.rs @@ -1,18 +1,19 @@ -use crate::{service::ServiceSpec, ServiceBroker, ServiceBrokerMessage}; +use crate::{errors::RegistryError, service::ServiceSpec, ServiceBroker, ServiceBrokerMessage}; use super::*; use anyhow::bail; use serde_json::Value; -use tokio::sync::mpsc::Sender; +use tokio::sync::mpsc::UnboundedSender; +#[derive(Debug)] pub struct Registry { - pub logger: Arc, - broker_sender: Sender, + broker_sender: UnboundedSender, broker: Arc, nodes: NodeCatalog, services: ServiceCatalog, - actions: ActionCatalog, + pub(crate) actions: ActionCatalog, /* + events metrics strategy factor discoverer @@ -21,14 +22,22 @@ pub struct Registry { */ } impl Registry { - pub fn new(broker: Arc, broker_sender: Sender) -> Self { - let logger = &broker.logger; - let logger = Arc::clone(logger); - let nodes = NodeCatalog::new(); - let services = ServiceCatalog::new(); + pub fn new( + broker: Arc, + broker_sender: UnboundedSender, + ) -> Self { + //TODO:get the library version for the client + + let mut nodes = NodeCatalog::new(); + nodes.create_local_node( + "1.0".to_string(), + broker.node_id.clone(), + broker.instance.clone(), + broker.options.metadata.clone(), + ); + let services = ServiceCatalog::default(); let actions = ActionCatalog::default(); Registry { - logger, broker_sender, broker, nodes, @@ -59,7 +68,7 @@ impl Registry { let service_full_name = self.services.add(node, &svc, true); if let Some(actions) = svc.actions { - self.register_actions(&service_full_name, actions); + self.register_actions(&service_full_name, actions)?; } if let Some(events) = svc.events { self.register_events(); @@ -126,10 +135,10 @@ impl Registry { &self, action_name: &str, node_id: &str, - ) -> Option<&EndpointList> { + ) -> Option<&ActionEndpoint> { let list = self.actions.get(action_name); if let Some(list) = list { - list.get_endpoint_by_node_id(node_id); + return list.get_endpoint_by_node_id(node_id); } None } @@ -168,7 +177,7 @@ impl Registry { todo!() } - fn get_local_node_info(&self, force: bool) -> anyhow::Result { + pub fn get_local_node_info(&self, force: bool) -> anyhow::Result { // if let None = self.nodes.local_node() { // return Ok(self.regenerate_local_raw_info(None)); // } @@ -194,7 +203,7 @@ impl Registry { pub fn get_services_list(&self, opts: ListOptions) -> Vec<&ServiceItem> { self.services.list(opts) } - fn get_actions_list(&self, opts: ListOptions) -> Vec<&ActionEndpoint> { + fn get_action_list(&self, opts: ListOptions) -> Vec<&ActionEndpoint> { //self.actions.list(opts) todo!() } diff --git a/src/registry/service_catalog.rs b/src/registry/service_catalog.rs index 8ff998c..79df9dd 100644 --- a/src/registry/service_catalog.rs +++ b/src/registry/service_catalog.rs @@ -1,15 +1,14 @@ use anyhow::bail; -use crate::{service::ServiceSpec, errors::RegistryError}; +use crate::{errors::RegistryError, service::ServiceSpec}; use super::*; -#[derive(PartialEq, Eq , Default)] +#[derive(PartialEq, Eq, Default, Debug)] pub struct ServiceCatalog { services: Vec, } impl ServiceCatalog { - ///Add a new service pub fn add(&mut self, node: &Node, service: &ServiceSpec, local: bool) -> String { let service_item = ServiceItem::new(node, service, local); diff --git a/src/registry/service_item.rs b/src/registry/service_item.rs index 2b8ec14..80a9980 100644 --- a/src/registry/service_item.rs +++ b/src/registry/service_item.rs @@ -2,7 +2,7 @@ use crate::service::ServiceSpec; use super::*; -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct ServiceItem { pub name: String, pub node: String, diff --git a/src/service.rs b/src/service.rs index 5017b4d..3e2e4f8 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - registry::{Action, Event}, + registry::{Action, ActionHandler, Event}, ServiceBrokerMessage, }; use log::info; @@ -12,13 +12,13 @@ pub struct Service { pub name: String, pub full_name: String, pub version: String, - settings: HashMap, - schema: Schema, - original_schema: Option, - metadata: HashMap, + pub(crate) settings: HashMap, + pub(crate) schema: Schema, + pub(crate) original_schema: Option, + pub(crate) metadata: HashMap, pub actions: Option>, pub events: Option>, - broker_sender: UnboundedSender, + pub(crate) broker_sender: UnboundedSender, } impl PartialEq for Service { @@ -36,23 +36,23 @@ impl PartialEq for Service { } #[derive(PartialEq, Eq, Clone, Debug)] -struct Schema { - mixins: Option>, - actions: Option>, - events: Option>, - merged: SchemaMerged, - name: String, - version: Option, - settings: HashMap, - metadata: Option>, - created: Option, - started: Option, - stopped: Option, - dependencies: Option>, +pub struct Schema { + pub(crate) mixins: Option>, + pub(crate) actions: Option>, + pub(crate) events: Option>, + pub(crate) merged: SchemaMerged, + pub(crate) name: String, + pub(crate) version: Option, + pub(crate) settings: HashMap, + pub(crate) metadata: Option>, + pub(crate) created: Option, + pub(crate) started: Option, + pub(crate) stopped: Option, + pub(crate) dependencies: Option>, } #[derive(PartialEq, Eq, Clone, Debug)] -struct SchemaMixins {} +pub struct SchemaMixins {} #[derive(PartialEq, Eq, Clone, Debug)] pub struct SchemaActions { @@ -61,9 +61,9 @@ pub struct SchemaActions { } #[derive(PartialEq, Eq, Clone, Debug)] -struct SchemaEvents {} +pub struct SchemaEvents {} #[derive(PartialEq, Eq, Clone, Debug)] -enum SchemaMerged { +pub enum SchemaMerged { MergedFn(fn()), MergedFnVec(Vec), } @@ -88,7 +88,7 @@ impl Service { full_name: self.full_name.clone(), settings: self.get_public_settings(), version: self.version.clone(), - actions: None, + actions: self.actions.clone(), events: None, } } @@ -193,7 +193,7 @@ impl Service { todo!("call service stopped middleware"); } - fn create_action(&self, action_def: fn(), name: &str) -> Action { + fn create_action(&self, action_def: ActionHandler, name: &str) -> Action { let mut action = Action::new(name.to_string(), action_def); let name_prefix = self.settings.get("$noServiceNamePrefix"); if let Some(name_prefix) = name_prefix { @@ -203,8 +203,6 @@ impl Service { } } //TODO add caching settings from settins - //TODO see if it is even necessary to give action access to the service. - // action = action.set_service(self.clone()); action } @@ -228,7 +226,7 @@ impl Service { }); } - fn get_versioned_full_name(name: &str, version: Option<&String>) -> String { + pub fn get_versioned_full_name(name: &str, version: Option<&String>) -> String { let mut name = name.to_string(); if let Some(v) = version { name = format!("{}.{}", v, name); @@ -240,6 +238,12 @@ impl Service { mod tests { use tokio::sync::mpsc::{self, UnboundedSender}; + use crate::{ + context::Context, + registry::{ActionEndpoint, Payload}, + HandlerResult, + }; + use super::*; fn test_merge_func() { println!("test merge function"); @@ -253,8 +257,11 @@ mod tests { fn test_stop_func() { println!("test stop func"); } - fn action_func() { + fn action_func(context: Context, payload: Option) -> HandlerResult { println!("action_func"); + println!("context: {:?}", context); + println!("payload: {:?}", payload); + HandlerResult { data: 1 } } fn get_test_schema(dependencies: Option>) -> Schema { diff --git a/src/strategies/mod.rs b/src/strategies/mod.rs index deb40c0..81d677b 100644 --- a/src/strategies/mod.rs +++ b/src/strategies/mod.rs @@ -1,19 +1,14 @@ -use std::sync::Arc; - -use crate::registry::{ActionEndpoint, Registry , }; -use crate::ServiceBroker; mod round_robin; - - +use crate::context::Context; +use crate::registry::EndpointTrait; +pub use round_robin::RoundRobinStrategy; pub trait Strategy { - fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self; - fn select<'a>( + // fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self; + fn select<'a, E: EndpointTrait>( &mut self, - list: Vec<&'a ActionEndpoint>, - ctx: Option, - ) -> Option<&'a ActionEndpoint>; + list: Vec<&'a E>, + ctx: Option<&Context>, + ) -> Option<&'a E>; } -pub struct Context {} - -pub struct StrategyOpts{} \ No newline at end of file +pub struct StrategyOpts {} diff --git a/src/strategies/round_robin.rs b/src/strategies/round_robin.rs index b61ae23..ceb3422 100644 --- a/src/strategies/round_robin.rs +++ b/src/strategies/round_robin.rs @@ -1,30 +1,36 @@ use super::*; use std::sync::Arc; -struct RoundRobinStrategy { - registry: Arc, - broker: Arc, - opts: StrategyOpts, +#[derive(Debug)] +pub struct RoundRobinStrategy { counter: usize, } impl RoundRobinStrategy { - // fn new() -> Self {} + pub fn new() -> Self { + RoundRobinStrategy { counter: 0 } + } } -impl Strategy for RoundRobinStrategy { - fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self { - Self { - broker, - registry, - opts, - counter: 0, - } +impl Default for RoundRobinStrategy { + fn default() -> Self { + Self::new() } - fn select<'a>( +} + +impl Strategy for RoundRobinStrategy { + // fn new(registry: Arc, broker: Arc, opts: StrategyOpts) -> Self { + // Self { + // broker, + // registry, + // opts, + // counter: 0, + // } + // } + fn select<'a, E: EndpointTrait>( &mut self, - list: Vec<&'a ActionEndpoint>, - ctx: Option, - ) -> Option<&'a ActionEndpoint> { + list: Vec<&'a E>, + ctx: Option<&Context>, + ) -> Option<&'a E> { if self.counter >= list.len() { self.counter = 0; } From bb1d802071d260c82e331140a377fb0e8ea9c062 Mon Sep 17 00:00:00 2001 From: Ramyak Mehra Date: Mon, 21 Feb 2022 13:40:39 +0530 Subject: [PATCH 22/22] feat:handler_result accepts any data --- src/broker.rs | 12 +++++++----- src/service.rs | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/broker.rs b/src/broker.rs index 101490e..c6d0b31 100644 --- a/src/broker.rs +++ b/src/broker.rs @@ -271,7 +271,7 @@ impl ServiceBroker { ctx.request_id ) } - task::spawn(async move { + task::spawn( async move { let result = (endpoint.action.handler)(ctx, Some(params)); let _ = sender.send(Ok(result)); }); @@ -481,9 +481,10 @@ impl PartialEq for ServiceBrokerMessage { } } -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub struct HandlerResult { - pub(crate) data: u32, + // pub(crate) data: u32, + pub(crate) data : Box, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -520,10 +521,10 @@ mod tests { println!("test stop func"); } fn action_func(context: Context, payload: Option) -> HandlerResult { - println!("action_func"); let data = fibonacci(40); - HandlerResult { data } + + HandlerResult {data: Box::new(data) } } fn get_test_broker( @@ -681,6 +682,7 @@ mod tests { result_channel: one_sender, }); let _result = recv.await; + println!("{:?}" , _result); }); jhs.push(jh); } diff --git a/src/service.rs b/src/service.rs index 3e2e4f8..287c98f 100644 --- a/src/service.rs +++ b/src/service.rs @@ -261,7 +261,7 @@ mod tests { println!("action_func"); println!("context: {:?}", context); println!("payload: {:?}", payload); - HandlerResult { data: 1 } + HandlerResult { data: Box::new(1) } } fn get_test_schema(dependencies: Option>) -> Schema {