diff --git a/Cargo.toml b/Cargo.toml index 42a6c1d..51c95b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,13 +17,18 @@ exclude = ["examples/*", "benches/*", "tests/*", ".gitignore"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + +# polaris-spec dep +polaris-specification = {version = "=1.5.4-2"} + +# common dep bytes = {version = "1.4.0"} +regex = {version = "1.11.1"} schemars = {version = "0.8.16"} serde = {version = "1.0.198", features = ["derive"]} serde-duration-ext = {version = "0.1.0"} serde_json = {version = "1.0.116"} serde_yaml = {version = "0.9.34"} - uuid = {version = "1.8.0", features = [ "v4", # Lets you generate random UUIDs "fast-rng", # Use a faster (but still sufficiently random) RNG @@ -54,6 +59,8 @@ tonic = {version = "0.11.0"} # logging tracing = {version = "0.1.36"} +tracing-appender = {version = "0.2.3"} +tracing-subscriber = {version = "0.3", features = ["default"]} # crypto aes = {version = "0.7.4"} @@ -64,7 +71,6 @@ rand = {version = "0.8.4"} rsa = {version = "0.9.6"} [dev-dependencies] -tracing-subscriber = {version = "0.3", features = ["default"]} [[example]] name = "discover" diff --git a/examples/config.rs b/examples/config.rs index 9e724ea..57d8997 100644 --- a/examples/config.rs +++ b/examples/config.rs @@ -15,22 +15,19 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; -use polaris_rust::{ - config::{ - api::{new_config_file_api_by_context, ConfigFileAPI}, - req::{ - CreateConfigFileRequest, PublishConfigFileRequest, UpdateConfigFileRequest, - UpsertAndPublishConfigFileRequest, WatchConfigFileRequest, - }, +use polaris_rust::{config::{ + api::{new_config_file_api_by_context, ConfigFileAPI}, + req::{ + CreateConfigFileRequest, PublishConfigFileRequest, UpdateConfigFileRequest, + UpsertAndPublishConfigFileRequest, WatchConfigFileRequest, }, - core::{ - context::SDKContext, - model::{ - config::{ConfigFile, ConfigFileRelease}, - error::PolarisError, - }, +}, core::{ + context::SDKContext, + model::{ + config::{ConfigFile, ConfigFileRelease}, + error::PolarisError, }, -}; +}, info}; use tracing::level_filters::LevelFilter; #[tokio::main] @@ -163,7 +160,7 @@ async fn main() -> Result<(), PolarisError> { group: "rust".to_string(), file: "rust.toml".to_string(), call_back: Arc::new(|event| { - tracing::info!("receive config change event: {:?}", event); + info!("receive config change event: {:?}", event); }), }) .await; diff --git a/examples/discover.rs b/examples/discover.rs index e632873..7a6ed94 100644 --- a/examples/discover.rs +++ b/examples/discover.rs @@ -15,19 +15,15 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; -use polaris_rust::{ - core::{ - context::SDKContext, - model::{error::PolarisError, naming::Location}, +use polaris_rust::{core::{ + context::SDKContext, + model::{error::PolarisError, loadbalance::Criteria, naming::Location, router::RouteInfo}, +}, discovery::{ + api::{new_consumer_api_by_context, new_provider_api_by_context, ConsumerAPI, ProviderAPI}, + req::{ + GetAllInstanceRequest, GetOneInstanceRequest, InstanceDeregisterRequest, InstanceRegisterRequest, WatchInstanceRequest }, - discovery::{ - api::{new_consumer_api_by_context, new_provider_api_by_context, ConsumerAPI, ProviderAPI}, - req::{ - GetAllInstanceRequest, InstanceDeregisterRequest, InstanceRegisterRequest, - WatchInstanceRequest, - }, - }, -}; +}, error, info}; use tracing::level_filters::LevelFilter; #[tokio::main] @@ -48,7 +44,7 @@ async fn main() -> Result<(), PolarisError> { let sdk_context_ret = SDKContext::default(); if sdk_context_ret.is_err() { - tracing::error!( + error!( "create sdk context fail: {}", sdk_context_ret.err().unwrap() ); @@ -61,7 +57,7 @@ async fn main() -> Result<(), PolarisError> { let provider_ret = new_provider_api_by_context(arc_ctx.clone()); if provider_ret.is_err() { - tracing::error!("create provider fail: {}", provider_ret.err().unwrap()); + error!("create provider fail: {}", provider_ret.err().unwrap()); return Err(PolarisError::new( polaris_rust::core::model::error::ErrorCode::UnknownServerError, "".to_string(), @@ -70,7 +66,7 @@ async fn main() -> Result<(), PolarisError> { let consumer_ret = new_consumer_api_by_context(arc_ctx); if consumer_ret.is_err() { - tracing::error!("create consumer fail: {}", consumer_ret.err().unwrap()); + error!("create consumer fail: {}", consumer_ret.err().unwrap()); return Err(PolarisError::new( polaris_rust::core::model::error::ErrorCode::UnknownServerError, "".to_string(), @@ -80,7 +76,7 @@ async fn main() -> Result<(), PolarisError> { let provider = provider_ret.unwrap(); let consumer = consumer_ret.unwrap(); - tracing::info!( + info!( "create discovery api client cost: {:?}", start_time.elapsed() ); @@ -114,25 +110,25 @@ async fn main() -> Result<(), PolarisError> { let _ret = provider.register(req).await; match _ret { Err(err) => { - tracing::error!("register fail: {}", err.to_string()); + error!("register fail: {}", err.to_string()); } Ok(_) => {} } - tracing::info!("begin do watch service_instances change"); + info!("begin do watch service_instances change"); let watch_rsp = consumer .watch_instance(WatchInstanceRequest { namespace: "rust-demo".to_string(), service: "polaris-rust-provider".to_string(), call_back: Arc::new(|instances| { - tracing::info!("watch instance: {:?}", instances.instances); + info!("watch instance: {:?}", instances.instances); }), }) .await; match watch_rsp { Err(err) => { - tracing::error!("watch instance fail: {}", err.to_string()); + error!("watch instance fail: {}", err.to_string()); } Ok(_) => {} } @@ -148,10 +144,34 @@ async fn main() -> Result<(), PolarisError> { match instances_ret { Err(err) => { - tracing::error!("get all instance fail: {}", err.to_string()); + error!("get all instance fail: {}", err.to_string()); } Ok(instances) => { - tracing::info!("get all instance: {:?}", instances); + info!("get all instance: {:?}", instances); + } + } + + // 执行路由以及负载均衡能力 + let mut route_info = RouteInfo::default(); + + let ret = consumer.get_one_instance(GetOneInstanceRequest{ + flow_id: uuid::Uuid::new_v4().to_string(), + timeout: Duration::from_secs(10), + namespace: "rust-demo".to_string(), + service: "polaris-rust-provider".to_string(), + criteria: Criteria{ + policy: "random".to_string(), + hash_key: "".to_string(), + }, + route_info: route_info, + }).await; + + match ret { + Err(err) => { + tracing::error!("get one instance fail: {}", err.to_string()); + } + Ok(instance) => { + tracing::info!("get one instance: {:?}", instance); } } @@ -173,7 +193,7 @@ async fn main() -> Result<(), PolarisError> { let _ret = provider.deregister(deregister_req).await; match _ret { Err(err) => { - tracing::error!("deregister fail: {}", err.to_string()); + error!("deregister fail: {}", err.to_string()); } Ok(_) => {} } diff --git a/src/circuitbreaker/api.rs b/src/circuitbreaker/api.rs index 3ff3b73..635d503 100644 --- a/src/circuitbreaker/api.rs +++ b/src/circuitbreaker/api.rs @@ -13,4 +13,131 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -pub trait CircuitBreakerAPI {} +use std::{sync::Arc, time::Duration}; + +use crate::core::{ + flow::CircuitBreakerFlow, + model::{ + circuitbreaker::{CallAbortedError, CheckResult, MethodResource, Resource, ResourceStat, RetStatus, ServiceResource}, + error::PolarisError, + }, +}; + +use super::req::{RequestContext, ResponseContext}; + +/// CircuitBreakerAPI . +#[async_trait::async_trait] +pub trait CircuitBreakerAPI +where + Self: Send + Sync, +{ + /// check_resource . + async fn check_resource(&self, resource: Resource) -> Result; + /// report_stat . + async fn report_stat(&self, stat: ResourceStat) -> Result<(), PolarisError>; + /// make_invoke_handler . + async fn make_invoke_handler( + &self, + req: RequestContext, + ) -> Result, PolarisError>; +} + +/// InvokeHandler . +pub struct InvokeHandler { + // req_ctx: 请求上下文 + req_ctx: RequestContext, + // flow: 熔断器流程 + flow: Arc, +} + +impl InvokeHandler { + pub fn new(req_ctx: RequestContext, flow: Arc) -> Self { + InvokeHandler { req_ctx, flow } + } + + /// acquire_permission 检查当前请求是否可放通 + async fn acquire_permission(&self) -> Result<(), CallAbortedError> { + let svc_res = ServiceResource::new_waith_caller( + self.req_ctx.caller_service.clone(), + self.req_ctx.callee_service.clone()); + + match self.flow.check_resource(Resource::ServiceResource(svc_res)).await { + Ok(ret) => { + if ret.pass { + Ok(()) + } else { + Err(CallAbortedError::new(ret.rule_name, ret.fallback_info)) + } + }, + Err(e) => { + // 内部异常,不触发垄断,但是需要记录 + crate::error!("[circuitbreaker][invoke] check resource failed: {:?}", e); + Ok(()) + }, + } + } + + async fn on_success(&self, rsp: ResponseContext) -> Result<(), PolarisError> { + let cost = rsp.duration.clone(); + let mut code = -1 as i32; + let mut status = RetStatus::RetSuccess; + + if let Some(r) = &self.req_ctx.result_to_code { + code = r.on_success(rsp.result.unwrap()); + } + if let Some(e) = rsp.error { + let ret = e.downcast::(); + if ret.is_ok() { + status = RetStatus::RetReject; + } + } + self.common_report(cost, code, status).await + } + + async fn on_error(&self, rsp: ResponseContext) -> Result<(), PolarisError> { + let cost = rsp.duration.clone(); + let mut code = 0 as i32; + let mut status = RetStatus::RetUnknown; + + if let Some(r) = &self.req_ctx.result_to_code { + code = r.on_success(rsp.result.unwrap()); + } + self.common_report(cost, code, status).await + } + + async fn common_report(&self, cost: Duration, code: i32, status: RetStatus) -> Result<(), PolarisError> { + let stat = ResourceStat { + resource: Resource::ServiceResource(ServiceResource::new_waith_caller( + self.req_ctx.caller_service.clone(), + self.req_ctx.callee_service.clone())), + ret_code: code.to_string(), + delay: cost, + status: status.clone(), + }; + + let ret = self.flow.report_stat(stat).await; + if ret.is_err() { + crate::error!("[circuitbreaker][invoke] report stat failed"); + return ret; + } + + if self.req_ctx.path.is_empty() { + return Ok(()); + } + + // 补充一个接口级别的数据上报 + let stat = ResourceStat { + resource: Resource::MethodResource(MethodResource::new_waith_caller( + self.req_ctx.caller_service.clone(), + self.req_ctx.callee_service.clone(), + self.req_ctx.protocol.clone(), + self.req_ctx.method.clone(), + self.req_ctx.path.clone(), + )), + ret_code: code.to_string(), + delay: cost, + status, + }; + self.flow.report_stat(stat).await + } +} diff --git a/src/circuitbreaker/default.rs b/src/circuitbreaker/default.rs new file mode 100644 index 0000000..73b9b76 --- /dev/null +++ b/src/circuitbreaker/default.rs @@ -0,0 +1,98 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::sync::Arc; + +use crate::core::{ + context::SDKContext, + flow::CircuitBreakerFlow, + model::{ + circuitbreaker::{CheckResult, Resource, ResourceStat}, + error::PolarisError, + }, +}; + +use super::{ + api::{CircuitBreakerAPI, InvokeHandler}, + req::RequestContext, +}; + +/// DefaultCircuitBreakerAPI . +pub struct DefaultCircuitBreakerAPI { + context: Arc, + // manage_sdk: 是否管理 sdk_context 的生命周期 + manage_sdk: bool, + // flow: 熔断器流程 + flow: Arc, +} + +impl DefaultCircuitBreakerAPI { + pub fn new_raw(context: SDKContext) -> Self { + let ctx = Arc::new(context); + let extensions = ctx.get_engine().get_extensions(); + Self { + context: ctx, + manage_sdk: true, + flow: Arc::new(CircuitBreakerFlow::new(extensions)), + } + } + + pub fn new(context: Arc) -> Self { + let extensions = context.get_engine().get_extensions(); + Self { + context, + manage_sdk: false, + flow: Arc::new(CircuitBreakerFlow::new(extensions)), + } + } +} + +impl Drop for DefaultCircuitBreakerAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} + +#[async_trait::async_trait] +impl CircuitBreakerAPI for DefaultCircuitBreakerAPI { + async fn check_resource(&self, resource: Resource) -> Result { + self.flow.check_resource(resource).await + } + + async fn report_stat(&self, stat: ResourceStat) -> Result<(), PolarisError> { + self.flow.report_stat(stat).await + } + + async fn make_invoke_handler( + &self, + req: RequestContext, + ) -> Result, PolarisError> { + // Implement the method logic here + Ok(Arc::new(InvokeHandler::new(req, self.flow.clone()))) + } +} diff --git a/src/circuitbreaker/mod.rs b/src/circuitbreaker/mod.rs index 721e783..e94e4b2 100644 --- a/src/circuitbreaker/mod.rs +++ b/src/circuitbreaker/mod.rs @@ -13,5 +13,6 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod api; -mod req; +pub mod api; +pub mod default; +pub mod req; diff --git a/src/circuitbreaker/req.rs b/src/circuitbreaker/req.rs index 5992645..1fd9683 100644 --- a/src/circuitbreaker/req.rs +++ b/src/circuitbreaker/req.rs @@ -12,3 +12,30 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. + +use std::{any::Any, time::Duration}; + +use crate::core::model::naming::ServiceKey; + +pub trait ResultToErrorCode +where + Self: Send + Sync, +{ + fn on_success(&self, ret: Box) -> i32; + fn on_error(&self, err: Box) -> i32; +} + +pub struct RequestContext { + pub caller_service: ServiceKey, + pub callee_service: ServiceKey, + pub protocol: String, + pub method: String, + pub path: String, + pub result_to_code: Option>, +} + +pub struct ResponseContext { + pub duration: Duration, + pub result: Option>, + pub error: Option>, +} diff --git a/src/config/api.rs b/src/config/api.rs index fa34ff7..764865d 100644 --- a/src/config/api.rs +++ b/src/config/api.rs @@ -15,13 +15,13 @@ use std::sync::Arc; -use crate::{ - config::default::DefaultConfigFileAPI, - core::{ - context::SDKContext, - model::{config::ConfigFile, error::PolarisError}, +use crate::{config::default::{DefaultConfigFileAPI, DefaultConfigGroupAPI}, core::{ + context::SDKContext, + model::{ + config::{ConfigFile, ConfigGroup}, + error::PolarisError, }, -}; +}, info}; use super::req::{ CreateConfigFileRequest, GetConfigFileRequest, GetConfigGroupRequest, PublishConfigFileRequest, @@ -33,60 +33,85 @@ use super::req::{ pub fn new_config_file_api() -> Result { let start_time = std::time::Instant::now(); let context_ret = SDKContext::default(); - tracing::info!("create sdk context cost: {:?}", start_time.elapsed()); + info!("create sdk context cost: {:?}", start_time.elapsed()); if context_ret.is_err() { return Err(context_ret.err().unwrap()); } - Ok(DefaultConfigFileAPI::new( - Arc::new(context_ret.unwrap()), - true, - )) + Ok(DefaultConfigFileAPI::new_raw(context_ret.unwrap())) } /// new_config_file_api_by_context pub fn new_config_file_api_by_context( context: Arc, ) -> Result { - Ok(DefaultConfigFileAPI::new(context, false)) + Ok(DefaultConfigFileAPI::new(context)) } +/// ConfigFileAPI 配置文件API #[async_trait::async_trait] pub trait ConfigFileAPI where Self: Send + Sync, { + /// get_config_file 获取配置文件 async fn get_config_file(&self, req: GetConfigFileRequest) -> Result; + /// create_config_file 创建配置文件 async fn create_config_file(&self, req: CreateConfigFileRequest) -> Result; + /// update_config_file 更新配置文件 async fn update_config_file(&self, req: UpdateConfigFileRequest) -> Result; + /// publish_config_file 发布配置文件 async fn publish_config_file( &self, req: PublishConfigFileRequest, ) -> Result; + /// upsert_publish_config_file 创建/更新配置文件后并发布 async fn upsert_publish_config_file( &self, req: UpsertAndPublishConfigFileRequest, ) -> Result; + /// watch_config_file 监听配置文件变更 async fn watch_config_file( &self, req: WatchConfigFileRequest, ) -> Result; } +/// new_config_group_api +pub fn new_config_group_api() -> Result { + let start_time = std::time::Instant::now(); + let context_ret = SDKContext::default(); + info!("create sdk context cost: {:?}", start_time.elapsed()); + if context_ret.is_err() { + return Err(context_ret.err().unwrap()); + } + Ok(DefaultConfigGroupAPI::new_raw(context_ret.unwrap())) +} + +/// new_config_group_api_by_context +pub fn new_config_group_api_by_context( + context: Arc, +) -> Result { + Ok(DefaultConfigGroupAPI::new(context)) +} + +/// ConfigGroupAPI 配置组API #[async_trait::async_trait] pub trait ConfigGroupAPI where Self: Send + Sync, { + /// get_publish_config_files 获取发布的配置文件列表 async fn get_publish_config_files( &self, req: GetConfigGroupRequest, - ) -> Result, PolarisError>; + ) -> Result; + /// watch_publish_config_files 监听发布的配置文件变更 async fn watch_publish_config_files( &self, req: WatchConfigGroupRequest, diff --git a/src/config/default.rs b/src/config/default.rs index 3dbd1ef..55d37e2 100644 --- a/src/config/default.rs +++ b/src/config/default.rs @@ -16,7 +16,7 @@ use std::{ collections::HashMap, sync::{ - atomic::{AtomicBool, Ordering}, + atomic::{AtomicBool, AtomicU64, Ordering}, Arc, }, }; @@ -27,7 +27,7 @@ use crate::core::{ context::SDKContext, model::{ cache::{EventType, ServerEvent}, - config::{ConfigFile, ConfigFileChangeEvent}, + config::{ConfigFile, ConfigFileChangeEvent, ConfigGroup, ConfigGroupChangeEvent}, error::PolarisError, }, plugin::cache::{Action, ResourceListener}, @@ -47,15 +47,27 @@ struct ConfigFileWatcher { req: WatchConfigFileRequest, } -struct ConfigFileResourceListener { +pub struct ConfigFileResourceListener { + // watcher_id: 用于生成唯一的 watcher_id + watcher_id: Arc, // watchers: namespace#service -> ConfigFileWatcher - watchers: Arc>>>, + watchers: Arc>>>, +} + +impl ConfigFileResourceListener { + pub async fn cancel_watch(&self, watch_key: &str, watch_id: u64) { + let mut watchers = self.watchers.write().await; + let items = watchers.get_mut(watch_key); + if let Some(vals) = items { + vals.remove(&watch_id); + } + } } #[async_trait::async_trait] impl ResourceListener for ConfigFileResourceListener { // 处理事件 - async fn on_event(&self, action: Action, val: ServerEvent) { + async fn on_event(&self, _action: Action, val: ServerEvent) { let event_key = val.event_key; let mut watch_key = event_key.namespace.clone(); let group = event_key.filter.get("group"); @@ -71,7 +83,7 @@ impl ResourceListener for ConfigFileResourceListener { match cfg_cache_opt { Some(cfg_cache_val) => { for watcher in watchers { - (watcher.req.call_back)(ConfigFileChangeEvent { + (watcher.1.req.call_back)(ConfigFileChangeEvent { config_file: cfg_cache_val.to_config_file(), }) } @@ -92,19 +104,33 @@ impl ResourceListener for ConfigFileResourceListener { /// DefaultConfigFileAPI pub struct DefaultConfigFileAPI { context: Arc, + // manage_sdk: 是否管理 sdk_context 的生命周期 manage_sdk: bool, // watchers: namespace#service -> ConfigFileWatcher watchers: Arc, - // + // register_resource_watcher: 是否已经注册资源监听器 register_resource_watcher: AtomicBool, } impl DefaultConfigFileAPI { - pub fn new(context: Arc, manage_sdk: bool) -> Self { + pub fn new_raw(context: SDKContext) -> Self { + Self { + context: Arc::new(context), + manage_sdk: true, + watchers: Arc::new(ConfigFileResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), + watchers: Arc::new(RwLock::new(HashMap::new())), + }), + register_resource_watcher: AtomicBool::new(false), + } + } + + pub fn new(context: Arc) -> Self { Self { context, - manage_sdk, + manage_sdk: false, watchers: Arc::new(ConfigFileResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), watchers: Arc::new(RwLock::new(HashMap::new())), }), register_resource_watcher: AtomicBool::new(false), @@ -112,6 +138,25 @@ impl DefaultConfigFileAPI { } } +impl Drop for DefaultConfigFileAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} + #[async_trait::async_trait] impl ConfigFileAPI for DefaultConfigFileAPI { async fn get_config_file(&self, req: GetConfigFileRequest) -> Result { @@ -159,32 +204,172 @@ impl ConfigFileAPI for DefaultConfigFileAPI { .await; } + let watch_id = self.watchers.watcher_id.fetch_add(1, Ordering::Acquire); let mut watchers = self.watchers.watchers.write().await; let watch_key = req.get_key(); - let items = watchers.entry(watch_key.clone()).or_insert_with(Vec::new); + let items = watchers + .entry(watch_key.clone()) + .or_insert_with(HashMap::new); - items.push(ConfigFileWatcher { req }); - Ok(WatchConfigFileResponse {}) + items.insert(watch_id, ConfigFileWatcher { req }); + Ok(WatchConfigFileResponse::new( + watch_id, + watch_key, + self.watchers.clone(), + )) } } /// DefaultConfigGroupAPI -pub struct DefaultConfigGroupAPI {} +pub struct DefaultConfigGroupAPI { + context: Arc, + // manage_sdk: 是否管理 sdk_context 的生命周期 + manage_sdk: bool, + // watchers: namespace#service -> ConfigFileWatcher + watchers: Arc, + // register_resource_watcher: 是否已经注册资源监听器 + register_resource_watcher: AtomicBool, +} + +impl DefaultConfigGroupAPI { + pub fn new_raw(context: SDKContext) -> Self { + Self { + context: Arc::new(context), + manage_sdk: true, + watchers: Arc::new(ConfigGroupResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), + watchers: Arc::new(RwLock::new(HashMap::new())), + }), + register_resource_watcher: AtomicBool::new(false), + } + } + + pub fn new(context: Arc) -> Self { + Self { + context, + manage_sdk: false, + watchers: Arc::new(ConfigGroupResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), + watchers: Arc::new(RwLock::new(HashMap::new())), + }), + register_resource_watcher: AtomicBool::new(false), + } + } +} + +impl Drop for DefaultConfigGroupAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} #[async_trait::async_trait] impl ConfigGroupAPI for DefaultConfigGroupAPI { async fn get_publish_config_files( &self, req: GetConfigGroupRequest, - ) -> Result, PolarisError> { - todo!() + ) -> Result { + self.context.get_engine().get_config_group_files(req).await } async fn watch_publish_config_files( &self, req: WatchConfigGroupRequest, ) -> Result { - todo!() + if self + .register_resource_watcher + .compare_exchange(false, true, Ordering::Relaxed, Ordering::SeqCst) + .is_ok() + { + // 延迟注册资源监听器 + self.context + .get_engine() + .register_resource_listener(self.watchers.clone()) + .await; + } + + let watch_id = self.watchers.watcher_id.fetch_add(1, Ordering::Acquire); + let mut watchers = self.watchers.watchers.write().await; + + let watch_key = req.get_key(); + let items = watchers + .entry(watch_key.clone()) + .or_insert_with(HashMap::new); + + items.insert(watch_id, ConfigGroupWatcher { req }); + Ok(WatchConfigGroupResponse::new( + watch_id, + watch_key, + self.watchers.clone(), + )) + } +} + +struct ConfigGroupWatcher { + req: WatchConfigGroupRequest, +} + +pub struct ConfigGroupResourceListener { + // watcher_id: 用于生成唯一的 watcher_id + watcher_id: Arc, + // watchers: namespace#group -> ConfigGroupWatcher + watchers: Arc>>>, +} + +impl ConfigGroupResourceListener { + pub async fn cancel_watch(&self, watch_key: &str, watch_id: u64) { + let mut watchers = self.watchers.write().await; + let items = watchers.get_mut(watch_key); + if let Some(vals) = items { + vals.remove(&watch_id); + } + } +} + +#[async_trait::async_trait] +impl ResourceListener for ConfigGroupResourceListener { + // 处理事件 + async fn on_event(&self, _action: Action, val: ServerEvent) { + let event_key = val.event_key; + let mut watch_key = event_key.namespace.clone(); + let group = event_key.filter.get("group"); + watch_key.push('#'); + watch_key.push_str(group.unwrap().as_str()); + + let watchers = self.watchers.read().await; + if let Some(watchers) = watchers.get(&watch_key) { + let cfg_cache_opt = val.value.to_config_group(); + match cfg_cache_opt { + Some(cfg_cache_val) => { + for watcher in watchers { + (watcher.1.req.call_back)(ConfigGroupChangeEvent { + config_group: cfg_cache_val.to_config_group().await, + }) + } + } + None => { + // do nothing + } + } + } + } + + // 获取监听的key + fn watch_key(&self) -> EventType { + EventType::ConfigFile } } diff --git a/src/config/req.rs b/src/config/req.rs index fc78d8f..ff80316 100644 --- a/src/config/req.rs +++ b/src/config/req.rs @@ -16,10 +16,12 @@ use std::{sync::Arc, time::Duration}; use crate::core::model::config::{ - ConfigFile, ConfigFileChangeEvent, ConfigFileRelease, ConfigFileRequest, ConfigPublishRequest, - ConfigReleaseRequest, + ConfigFile, ConfigFileChangeEvent, ConfigFileRelease, ConfigFileRequest, + ConfigGroupChangeEvent, ConfigPublishRequest, ConfigReleaseRequest, }; +use super::default::{ConfigFileResourceListener, ConfigGroupResourceListener}; + #[derive(Clone, Debug)] pub struct GetConfigFileRequest { pub namespace: String, @@ -48,10 +50,14 @@ impl CreateConfigFileRequest { } } +/// UpdateConfigFileRequest 配置更新请求 #[derive(Clone, Debug)] pub struct UpdateConfigFileRequest { + // flow_id 流水号 pub flow_id: String, + // timeout 超时时间 pub timeout: Duration, + // file 配置文件 pub file: ConfigFile, } @@ -126,12 +132,73 @@ impl WatchConfigFileRequest { } } -pub struct WatchConfigFileResponse {} +pub struct WatchConfigFileResponse { + pub watch_id: u64, + watch_key: String, + owner: Arc, +} -#[derive(Clone, Debug)] -pub struct GetConfigGroupRequest {} +impl WatchConfigFileResponse { + pub fn new(watch_id: u64, watch_key: String, owner: Arc) -> Self { + WatchConfigFileResponse { + watch_id, + watch_key, + owner, + } + } + + pub async fn cancel_watch(&self) { + self.owner + .cancel_watch(&self.watch_key, self.watch_id) + .await; + } +} #[derive(Clone, Debug)] -pub struct WatchConfigGroupRequest {} +pub struct GetConfigGroupRequest { + pub flow_id: String, + pub timeout: Duration, + // namespace 命名空间 + pub namespace: String, + // group 配置分组 + pub group: String, +} -pub struct WatchConfigGroupResponse {} +#[derive(Clone)] +pub struct WatchConfigGroupRequest { + pub flow_id: String, + pub timeout: Duration, + // namespace 命名空间 + pub namespace: String, + // group 配置分组 + pub group: String, + pub call_back: Arc, +} + +impl WatchConfigGroupRequest { + pub fn get_key(&self) -> String { + format!("{}#{}", self.namespace, self.group) + } +} + +pub struct WatchConfigGroupResponse { + pub watch_id: u64, + watch_key: String, + owner: Arc, +} + +impl WatchConfigGroupResponse { + pub fn new(watch_id: u64, watch_key: String, owner: Arc) -> Self { + WatchConfigGroupResponse { + watch_id, + watch_key, + owner, + } + } + + pub async fn cancel_watch(&self) { + self.owner + .cancel_watch(&self.watch_key, self.watch_id) + .await; + } +} diff --git a/src/core/config/config.rs b/src/core/config/config.rs index 040391b..3624cbb 100644 --- a/src/core/config/config.rs +++ b/src/core/config/config.rs @@ -20,6 +20,7 @@ use crate::core::config::provider::ProviderConfig; use serde::Deserialize; use std::path::Path; use std::{env, fs, io}; +use crate::info; #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -38,7 +39,7 @@ pub fn load_default<'a>() -> Result { } if env::var("POLARIS_RUST_CONFIG").is_ok() { let custom_conf_path = env::var("POLARIS_RUST_CONFIG").unwrap(); - tracing::info!("load config from env: {}", custom_conf_path); + info!("load config from env: {}", custom_conf_path); return load(env::var("POLARIS_RUST_CONFIG").unwrap()); } load(path) diff --git a/src/core/config/consumer.rs b/src/core/config/consumer.rs index 3e6ad3f..74f0004 100644 --- a/src/core/config/consumer.rs +++ b/src/core/config/consumer.rs @@ -16,12 +16,15 @@ use serde::Deserialize; use std::collections::HashMap; +use super::global::LocalCacheConfig; + #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ConsumerConfig { pub service_router: ServiceRouterConfig, pub circuit_breaker: CircuitBreakerConfig, pub load_balancer: LoadBalancerConfig, + pub local_cache: LocalCacheConfig, } #[derive(Deserialize, Debug)] diff --git a/src/core/config/global.rs b/src/core/config/global.rs index e4da898..3b9caa8 100644 --- a/src/core/config/global.rs +++ b/src/core/config/global.rs @@ -25,7 +25,7 @@ pub struct GlobalConfig { pub server_connectors: ServerConnectorConfig, pub stat_reporter: StatReporterConfig, pub location: LocationConfig, - pub local_cache: LocalCacheConfig, + pub client: ClientConfig, } impl GlobalConfig { @@ -146,7 +146,7 @@ pub struct ClusterConfig { pub lb_policy: String, } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct LocalCacheConfig { #[serde(default = "default_local_cache_name")] @@ -160,10 +160,6 @@ pub struct LocalCacheConfig { pub service_list_refresh_interval: Duration, pub persist_enable: bool, pub persist_dir: String, - pub persist_max_write_retry: u32, - pub persist_max_read_retry: u32, - #[serde(with = "serde_duration_ext")] - pub persist_retry_interval: Duration, } fn default_local_cache_name() -> String { @@ -176,3 +172,10 @@ pub struct PluginConfig { pub name: String, pub options: Option>, } + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct ClientConfig { + pub id: String, + pub labels: HashMap, +} diff --git a/src/core/context.rs b/src/core/context.rs index dc053bf..c7e142b 100644 --- a/src/core/context.rs +++ b/src/core/context.rs @@ -14,16 +14,20 @@ // specific language governing permissions and limitations under the License. use std::sync::Arc; - use crate::core::config::config::{load_default, Configuration}; use crate::core::engine::Engine; use crate::core::model::error::{ErrorCode, PolarisError}; +use crate::info; pub struct SDKContext { pub conf: Arc, engine: Arc, } +impl Drop for SDKContext { + fn drop(&mut self) {} +} + impl SDKContext { // default pub fn default() -> Result { @@ -55,7 +59,8 @@ impl SDKContext { let start_time = std::time::Instant::now(); let cfg = Arc::new(cfg); let ret = Engine::new(cfg.clone()); - tracing::info!("create engine cost: {:?}", start_time.elapsed()); + info!("create engine cost: {:?}", start_time.elapsed()); + info!("create engine cost: {:?}", start_time.elapsed()); if ret.is_err() { return Err(ret.err().unwrap()); } diff --git a/src/core/engine.rs b/src/core/engine.rs index 2dd969d..bb3cba1 100644 --- a/src/core/engine.rs +++ b/src/core/engine.rs @@ -17,40 +17,40 @@ use std::collections::HashMap; use std::sync::Arc; use tokio::runtime::{Builder, Runtime}; -use tokio::sync::RwLock; +use super::flow::{CircuitBreakerFlow, ClientFlow, RouterFlow}; +use super::model::config::{ConfigFile, ConfigGroup}; +use super::model::naming::{ServiceContractRequest, ServiceInstances}; +use super::model::ClientContext; +use super::plugin::cache::{Filter, ResourceCache, ResourceListener}; +use super::plugin::connector::Connector; +use super::plugin::location::{LocationProvider, LocationSupplier}; use crate::config::req::{ - CreateConfigFileRequest, GetConfigFileRequest, PublishConfigFileRequest, + CreateConfigFileRequest, GetConfigFileRequest, GetConfigGroupRequest, PublishConfigFileRequest, UpdateConfigFileRequest, UpsertAndPublishConfigFileRequest, }; use crate::core::config::config::Configuration; use crate::core::model::cache::{EventType, ResourceEventKey}; use crate::core::model::error::PolarisError; use crate::core::model::naming::InstanceRequest; -use crate::core::plugin::location::new_location_provider; use crate::core::plugin::plugins::Extensions; use crate::discovery::req::{ GetAllInstanceRequest, GetServiceRuleRequest, InstanceDeregisterRequest, InstanceHeartbeatRequest, InstanceRegisterRequest, InstanceRegisterResponse, InstancesResponse, - ServiceRuleResponse, + ReportServiceContractRequest, ServiceRuleResponse, }; -use super::model::config::ConfigFile; -use super::model::naming::ServiceInstances; -use super::plugin::cache::{Filter, ResourceCache, ResourceListener}; -use super::plugin::connector::Connector; -use super::plugin::loadbalance::LoadBalancer; -use super::plugin::location::{LocationProvider, LocationSupplier}; - pub struct Engine where Self: Send + Sync, { + extensions: Arc, runtime: Arc, local_cache: Arc>, server_connector: Arc>, location_provider: Arc, - load_balancer: Arc>>>>, + client_ctx: Arc, + client_flow: ClientFlow, } impl Engine { @@ -63,48 +63,32 @@ impl Engine { .build() .unwrap(), ); - - let client_id = crate::core::plugin::plugins::acquire_client_id(arc_conf.clone()); + let client_ctx = crate::core::plugin::plugins::acquire_client_context(arc_conf.clone()); + let client_ctx = Arc::new(client_ctx); // 初始化 extensions - let extensions_ret = Extensions::build(client_id, arc_conf.clone(), runtime.clone()); + let extensions_ret = + Extensions::build(client_ctx.clone(), arc_conf.clone(), runtime.clone()); if extensions_ret.is_err() { return Err(extensions_ret.err().unwrap()); } - let mut extension = extensions_ret.unwrap(); - let ret = extension.load_config_file_filters(&arc_conf.config.config_filter); - if ret.is_err() { - return Err(ret.err().unwrap()); - } + let extension = Arc::new(extensions_ret.unwrap()); + let server_connector = extension.get_server_connector(); + let local_cache = extension.get_resource_cache(); + let location_provider = extension.get_location_provider(); - // 初始化 server_connector - let ret = extension.load_server_connector(&arc_conf.global.server_connectors); - if ret.is_err() { - return Err(ret.err().unwrap()); - } - let server_connector = ret.unwrap(); - - // 初始化 local_cache - let ret = extension.load_resource_cache(&arc_conf.global.local_cache); - if ret.is_err() { - return Err(ret.err().unwrap()); - } - let local_cache = ret.unwrap(); - - // 初始化 location_provider - let ret = new_location_provider(&arc_conf.global.location); - if ret.is_err() { - return Err(ret.err().unwrap()); - } - let location_provider = ret.unwrap(); + let mut client_flow = ClientFlow::new(client_ctx.clone(), extension.clone()); + client_flow.run_flow(); Ok(Self { + extensions: extension.clone(), runtime, - local_cache: Arc::new(local_cache), + local_cache, server_connector, - location_provider: Arc::new(location_provider), - load_balancer: Arc::new(RwLock::new(extension.load_loadbalancers())), + location_provider: location_provider, + client_ctx: client_ctx, + client_flow, }) } @@ -232,6 +216,26 @@ impl Engine { }) } + /// report_service_contract 上报服务契约数据 + pub async fn report_service_contract( + &self, + req: ReportServiceContractRequest, + ) -> Result { + let connector = self.server_connector.clone(); + return connector + .report_service_contract(ServiceContractRequest { + flow_id: { + let mut flow_id = req.flow_id.clone(); + if flow_id.is_empty() { + flow_id = uuid::Uuid::new_v4().to_string(); + } + flow_id + }, + contract: req.contract, + }) + .await; + } + /// get_service_rule 获取服务规则 pub async fn get_service_rule( &self, @@ -355,9 +359,31 @@ impl Engine { } } - pub async fn lookup_loadbalancer(&self, name: &str) -> Option>> { - let lb = self.load_balancer.read().await; - lb.get(name).cloned() + pub async fn get_config_group_files( + &self, + req: GetConfigGroupRequest, + ) -> Result { + let local_cache = self.local_cache.clone(); + let mut filter = HashMap::::new(); + filter.insert("group".to_string(), req.group.clone()); + let ret = local_cache + .load_config_group_files(Filter { + resource_key: ResourceEventKey { + namespace: req.namespace.clone(), + event_type: EventType::ConfigGroup, + filter, + }, + internal_request: false, + include_cache: true, + timeout: req.timeout, + }) + .await; + + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + Ok(ret.unwrap()) } /// register_resource_listener 注册资源监听器 @@ -368,4 +394,8 @@ impl Engine { pub fn get_executor(&self) -> Arc { self.runtime.clone() } + + pub fn get_extensions(&self) -> Arc { + self.extensions.clone() + } } diff --git a/src/core/flow.rs b/src/core/flow.rs new file mode 100644 index 0000000..1918c1e --- /dev/null +++ b/src/core/flow.rs @@ -0,0 +1,245 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::{ + collections::HashMap, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + time::Duration, +}; + +use tokio::{sync::RwLock, task::JoinHandle, time::sleep}; + +use crate::core::plugin::router::ServiceRouter; + +use super::{ + model::{ + circuitbreaker::{CheckResult, CircuitBreakerStatus, Resource, ResourceStat, Status}, + error::PolarisError, + naming::ServiceInstances, + router::RouteInfo, + ClientContext, ReportClientRequest, + }, + plugin::{ + loadbalance::LoadBalancer, location::LocationSupplier, plugins::Extensions, + router::RouteContext, + }, +}; + +pub struct ClientFlow +where + Self: Send + Sync, +{ + client: Arc, + extensions: Arc, + + futures: Vec>, + + closed: Arc, +} + +impl ClientFlow { + pub fn new(client: Arc, extensions: Arc) -> Self { + ClientFlow { + client, + extensions: extensions, + futures: vec![], + closed: Arc::new(AtomicBool::new(false)), + } + } + + pub fn run_flow(&mut self) { + let client = self.client.clone(); + let extensions = self.extensions.clone(); + let is_closed = self.closed.clone(); + + let f: JoinHandle<()> = self.extensions.runtime.spawn(async move { + loop { + ClientFlow::report_client(client.clone(), extensions.clone()).await; + sleep(Duration::from_secs(60)).await; + if is_closed.load(Ordering::Relaxed) { + return; + } + } + }); + + self.futures.push(f); + } + + /// report_client 上报客户端信息数据 + pub async fn report_client(client: Arc, extensions: Arc) { + let server_connector = extensions.get_server_connector(); + let loc_provider = extensions.get_location_provider(); + let loc = loc_provider.get_location(); + let req = ReportClientRequest { + client_id: client.client_id.clone(), + host: client.host.clone(), + version: client.version.clone(), + location: loc, + }; + let ret = server_connector.report_client(req).await; + if let Err(e) = ret { + crate::error!("report client failed: {:?}", e); + } + } + + pub fn stop_flow(&mut self) { + self.closed.store(true, Ordering::SeqCst); + } +} + +/// CircuitBreakerFlow +pub struct CircuitBreakerFlow { + extensions: Arc, +} + +impl CircuitBreakerFlow { + pub fn new(extensions: Arc) -> Self { + CircuitBreakerFlow { extensions } + } + + pub async fn check_resource(&self, resource: Resource) -> Result { + let circuit_breaker_opt = self.extensions.circuit_breaker.clone(); + // 没有熔断插件,直接结束流程 + if circuit_breaker_opt.is_none() { + return Ok(CheckResult::pass()); + } + + let circuit_breaker = circuit_breaker_opt.unwrap(); + let status = circuit_breaker.check_resource(resource).await?; + Ok(CircuitBreakerFlow::convert_from_status(status)) + } + + pub async fn report_stat(&self, stat: ResourceStat) -> Result<(), PolarisError> { + let circuit_breaker_opt = self.extensions.circuit_breaker.clone(); + if circuit_breaker_opt.is_none() { + return Ok(()); + } + + let circuit_breaker = circuit_breaker_opt.unwrap(); + circuit_breaker.report_stat(stat).await + } + + fn convert_from_status(ret: CircuitBreakerStatus) -> CheckResult { + let status = ret.status; + CheckResult { + pass: status == Status::Open, + rule_name: ret.circuit_breaker, + fallback_info: ret.fallback_info.clone(), + } + } +} + +/// RouterFlow 路由流程 +pub struct RouterFlow { + load_balancer: Arc>>>>, + extensions: Arc, +} + +impl RouterFlow { + pub fn new(extensions: Arc) -> Self { + RouterFlow { + load_balancer: extensions.get_loadbalancers(), + extensions, + } + } + + /// lookup_loadbalancer 查找负载均衡器 + pub async fn lookup_loadbalancer(&self, name: &str) -> Option>> { + let lb = self.load_balancer.read().await; + lb.get(name).cloned() + } + + pub async fn choose_instances( + &self, + route_info: RouteInfo, + instances: ServiceInstances, + ) -> Result { + let router_container = self.extensions.get_router_container(); + + let route_ctx = RouteContext { + route_info, + extensions: Some(self.extensions.clone()), + }; + + let mut routers = Vec::>>::new(); + let chain = &route_ctx.route_info.chain; + + // 处理前置路由 + chain.before.iter().for_each(|name| { + if let Some(router) = router_container.before_routers.get(name) { + routers.push(router.clone()); + } + }); + + let mut tmp_instance = instances; + for (_, ele) in routers.iter().enumerate() { + let ret = ele.choose_instances(route_ctx.clone(), tmp_instance).await; + if let Err(e) = ret { + return Err(e); + } + tmp_instance = ret.unwrap().instances; + } + routers.clear(); + + // 处理核心路由 + chain.core.iter().for_each(|name| { + if let Some(router) = router_container.core_routers.get(name) { + routers.push(router.clone()); + } + }); + + for (_, ele) in routers.iter().enumerate() { + let ret = ele.choose_instances(route_ctx.clone(), tmp_instance).await; + if let Err(e) = ret { + return Err(e); + } + tmp_instance = ret.unwrap().instances; + } + routers.clear(); + + // 处理后置路由 + chain.after.iter().for_each(|name| { + if let Some(router) = router_container.before_routers.get(name) { + routers.push(router.clone()); + } + }); + + for (_, ele) in routers.iter().enumerate() { + let ret = ele.choose_instances(route_ctx.clone(), tmp_instance).await; + if let Err(e) = ret { + return Err(e); + } + tmp_instance = ret.unwrap().instances; + } + + Ok(tmp_instance) + } +} + +/// RatelimitFlow 限流流程 +pub struct RatelimitFlow { + extensions: Arc, +} + +impl RatelimitFlow { + pub fn new(extensions: Arc) -> Self { + Self { + extensions, + } + } +} \ No newline at end of file diff --git a/src/core/logger/logger.rs b/src/core/logger/logger.rs new file mode 100644 index 0000000..d2a8544 --- /dev/null +++ b/src/core/logger/logger.rs @@ -0,0 +1,173 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::sync::Arc; +use tracing::Level; +use tracing::level_filters::LevelFilter; +use tracing_appender::{non_blocking::NonBlocking, rolling}; +use tracing_subscriber::{fmt::format::{DefaultFields, Format}, FmtSubscriber}; + +use crate::core::model::error::{ErrorCode, PolarisError}; + + +struct AtomicUsize { + v: std::cell::Cell, +} + +impl AtomicUsize { + const fn new(v: usize) -> AtomicUsize { + AtomicUsize { v: std::cell::Cell::new(v) } + } + + fn load(&self, _order: std::sync::atomic::Ordering) -> usize { + self.v.get() + } + + fn store(&self, val: usize, _order: std::sync::atomic::Ordering) { + self.v.set(val) + } + + #[cfg(target_has_atomic = "ptr")] + fn compare_exchange( + &self, + current: usize, + new: usize, + _success: std::sync::atomic::Ordering, + _failure: std::sync::atomic::Ordering, + ) -> Result { + let prev = self.v.get(); + if current == prev { + self.v.set(new); + } + Ok(prev) + } +} + +// Any platform without atomics is unlikely to have multiple cores, so +// writing via Cell will not be a race condition. +unsafe impl Sync for AtomicUsize {} + +static STATE: AtomicUsize = AtomicUsize::new(0); + +// There are three different states that we care about: the logger's +// uninitialized, the logger's initializing (set_logger's been called but +// LOGGER hasn't actually been set yet), or the logger's active. +const UNINITIALIZED: usize = 0; +const INITIALIZING: usize = 1; +const INITIALIZED: usize = 2; + +// The LOGGER static holds a pointer to the global logger. It is protected by +// the STATE static which determines whether LOGGER has been initialized yet. +static mut LOGGER: &dyn Logger = &NopLogger; + +pub fn init_logger(dir: &str, file: &str, l: LevelFilter) -> Result<(), PolarisError> { + let logger = DefaultLogger::new(dir, file, l); + set_logger(Box::new(logger)) +} + +pub fn set_logger(logger: Box) -> Result<(), PolarisError> { + set_logger_inner(|| Box::leak(logger)) +} + +fn set_logger_inner(make_logger: F) -> Result<(), PolarisError> +where + F: FnOnce() -> &'static dyn Logger, +{ + match STATE.compare_exchange( + UNINITIALIZED, + INITIALIZING, + std::sync::atomic::Ordering::Acquire, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(UNINITIALIZED) => { + unsafe { + LOGGER = make_logger(); + } + STATE.store(INITIALIZED, std::sync::atomic::Ordering::Release); + Ok(()) + } + Err(INITIALIZING) => { + while STATE.load(std::sync::atomic::Ordering::Relaxed) == INITIALIZING { + std::hint::spin_loop(); + } + Err(PolarisError::new(ErrorCode::InternalError, "logger already initialized".to_string())) + } + _ => Err(PolarisError::new(ErrorCode::InternalError, "logger already initialized".to_string())), + } +} + +pub trait Logger { + fn log(&self, level: Level, msg: &str); +} + +pub struct NopLogger; + +impl Logger for NopLogger { + fn log(&self, level: Level, msg: &str) { + } +} + +pub struct DefaultLogger { + sub: Arc>>, +} + +impl DefaultLogger { + pub fn new(dir: &str, file: &str, l: LevelFilter) -> DefaultLogger { + let file_appender = rolling::never(dir, file); + let (non_blocking_appender, _guard) = tracing_appender::non_blocking(file_appender); + + let subscriber = tracing_subscriber::fmt() + .with_thread_names(true) + .with_file(true) + .with_level(true) + .with_writer(non_blocking_appender) + .with_line_number(true) + .with_thread_ids(true) + .with_max_level(l) + .finish(); + + let sub = Arc::new(Box::new(subscriber)); + + Self { + sub, + } + } +} + +impl Logger for DefaultLogger { + fn log(&self, level: Level, msg: &str) { + match level { + Level::TRACE => { + tracing::trace!(msg); + }, + Level::DEBUG => { + tracing::debug!(msg); + }, + Level::INFO => { + tracing::info!(msg); + }, + Level::WARN => { + tracing::warn!(msg); + }, + Level::ERROR => { + tracing::error!(msg); + }, + } + } +} + +pub fn log(level: Level, msg: &str) { + unsafe { LOGGER }.log(level, msg); +} diff --git a/src/core/model/pb/mod.rs b/src/core/logger/mod.rs similarity index 97% rename from src/core/model/pb/mod.rs rename to src/core/logger/mod.rs index de1f4ae..882e866 100644 --- a/src/core/model/pb/mod.rs +++ b/src/core/logger/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -pub mod lib; + +pub mod logger; diff --git a/src/core/mod.rs b/src/core/mod.rs index e5ccc02..a1ab4b2 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -16,5 +16,7 @@ pub mod config; pub mod context; mod engine; +pub mod flow; pub mod model; pub mod plugin; +pub mod logger; diff --git a/src/core/model/cache.rs b/src/core/model/cache.rs index eb776f8..1b87ae8 100644 --- a/src/core/model/cache.rs +++ b/src/core/model/cache.rs @@ -15,6 +15,7 @@ use std::{ collections::HashMap, + fmt::Display, sync::{atomic::AtomicBool, Arc}, thread::sleep, time::Duration, @@ -22,15 +23,17 @@ use std::{ use tokio::sync::RwLock; +use polaris_specification::v1::{ + config_discover_request::ConfigDiscoverRequestType, + config_discover_response::ConfigDiscoverResponseType, discover_request::DiscoverRequestType, + discover_response::DiscoverResponseType, CircuitBreaker, ClientConfigFileInfo, + ConfigDiscoverRequest, ConfigDiscoverResponse, DiscoverFilter, DiscoverRequest, + DiscoverResponse, FaultDetector, LaneGroup, RateLimit, Routing, Service, +}; + use super::{ - config::ConfigFile, + config::{ConfigFile, ConfigGroup}, naming::{Instance, ServiceInfo}, - pb::lib::{ - config_discover_request::ConfigDiscoverRequestType, discover_request::DiscoverRequestType, - CircuitBreaker, ClientConfigFileInfo, ConfigDiscoverRequest, ConfigDiscoverResponse, - DiscoverFilter, DiscoverRequest, DiscoverResponse, FaultDetector, LaneGroup, RateLimit, - Routing, Service, - }, }; #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] @@ -47,6 +50,49 @@ pub enum EventType { Namespaces, ConfigFile, ConfigGroup, + ConfigGroups, +} + +impl EventType { + pub fn to_persist_file(&self) -> String { + match self { + EventType::Instance => "instance.data".to_string(), + EventType::RouterRule => "router_rule.data".to_string(), + EventType::CircuitBreakerRule => "circuit_breaker_rule.data".to_string(), + EventType::RateLimitRule => "rate_limit_rule.data".to_string(), + EventType::Service => "service.data".to_string(), + EventType::FaultDetectRule => "fault_detect_rule.data".to_string(), + EventType::ServiceContract => "service_contract.data".to_string(), + EventType::LaneRule => "lane_rule.data".to_string(), + EventType::Namespaces => "namespaces.data".to_string(), + EventType::ConfigFile => "config_file.data".to_string(), + EventType::ConfigGroup => "config_group.data".to_string(), + _ => "unknown".to_string(), + } + } + + pub fn naming_spec_to_persist_file(t: DiscoverResponseType) -> String { + match t { + DiscoverResponseType::Instance => "instance.data".to_string(), + DiscoverResponseType::Routing => "router_rule.data".to_string(), + DiscoverResponseType::CircuitBreaker => "circuit_breaker_rule.data".to_string(), + DiscoverResponseType::RateLimit => "rate_limit_rule.data".to_string(), + DiscoverResponseType::Services => "service.data".to_string(), + DiscoverResponseType::FaultDetector => "fault_detect_rule.data".to_string(), + DiscoverResponseType::Lane => "lane_rule.data".to_string(), + DiscoverResponseType::Namespaces => "namespaces.data".to_string(), + _ => "unknown".to_string(), + } + } + + pub fn config_spec_to_persist_file(t: ConfigDiscoverResponseType) -> String { + match t { + ConfigDiscoverResponseType::ConfigFile => "config_file.data".to_string(), + ConfigDiscoverResponseType::ConfigFileNames => "config_files.data".to_string(), + ConfigDiscoverResponseType::ConfigFileGroups => "config_group.data".to_string(), + _ => "unknown".to_string(), + } + } } impl Default for EventType { @@ -70,6 +116,7 @@ impl ToString for EventType { EventType::Namespaces => "Namespaces".to_string(), EventType::ConfigFile => "ConfigFile".to_string(), EventType::ConfigGroup => "ConfigGroup".to_string(), + EventType::ConfigGroups => "ConfigGroups".to_string(), } } } @@ -88,6 +135,23 @@ pub enum CacheItemType { ConfigGroup(ConfigGroupCacheItem), } +impl Display for CacheItemType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CacheItemType::Instance(_) => write!(f, "Instance"), + CacheItemType::RouterRule(_) => write!(f, "RouterRule"), + CacheItemType::CircuitBreakerRule(_) => write!(f, "CircuitBreakerRule"), + CacheItemType::RateLimitRule(_) => write!(f, "RateLimitRule"), + CacheItemType::Service(_) => write!(f, "Service"), + CacheItemType::FaultDetectRule(_) => write!(f, "FaultDetectRule"), + CacheItemType::LaneRule(_) => write!(f, "LaneRule"), + CacheItemType::ConfigFile(_) => write!(f, "ConfigFile"), + CacheItemType::ConfigGroup(_) => write!(f, "ConfigGroup"), + _ => write!(f, "Unknown"), + } + } +} + impl CacheItemType { pub fn to_service_instances(&self) -> Option { match self { @@ -102,6 +166,13 @@ impl CacheItemType { _ => None, } } + + pub fn to_config_group(&self) -> Option { + match self { + CacheItemType::ConfigGroup(item) => Some(item.clone()), + _ => None, + } + } } #[derive(Debug, Clone)] @@ -277,7 +348,9 @@ pub trait RegistryCacheValue { // ServicesCacheItem 服务列表 pub struct ServicesCacheItem { initialized: Arc, + pub namespace: String, pub value: Arc>>, + pub revision: String, } impl Default for ServicesCacheItem { @@ -289,8 +362,10 @@ impl Default for ServicesCacheItem { impl ServicesCacheItem { pub fn new() -> Self { Self { + namespace: String::new(), initialized: Arc::new(AtomicBool::new(false)), value: Arc::new(RwLock::new(Vec::new())), + revision: String::new(), } } } @@ -298,8 +373,10 @@ impl ServicesCacheItem { impl Clone for ServicesCacheItem { fn clone(&self) -> Self { Self { + namespace: self.namespace.clone(), initialized: self.initialized.clone(), value: self.value.clone(), + revision: self.revision.clone(), } } } @@ -750,6 +827,21 @@ impl ConfigGroupCacheItem { } } + pub async fn to_config_group(&self) -> ConfigGroup { + let cache_files = self.files.read().await; + let mut files = Vec::::with_capacity(cache_files.len()); + for item in cache_files.iter() { + files.push(item.clone()); + } + + ConfigGroup { + namespace: self.namespace.clone(), + group: self.group.clone(), + files: files, + revision: self.revision.clone(), + } + } + pub fn finish_initialize(&self) { let _ = self.initialized.compare_exchange( false, diff --git a/src/core/model/circuitbreaker.rs b/src/core/model/circuitbreaker.rs index 94c13cf..d61547d 100644 --- a/src/core/model/circuitbreaker.rs +++ b/src/core/model/circuitbreaker.rs @@ -13,24 +13,38 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use std::iter::Map; +use std::{ + fmt::{self, format, Display}, + iter::Map, + str, time::Duration, +}; -enum Status { +use super::{error::{ErrorCode, PolarisError}, naming::ServiceKey}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Status { Close, HalfOpen, Open, Destroy, } +/// CircuitBreakerStatus 资源熔断状态及数据 pub struct CircuitBreakerStatus { + // 标识被哪个熔断器熔断 pub circuit_breaker: String, + // 熔断器状态 pub status: Status, + // 开始被熔断的时间 pub start_ms: u64, - pub fallback_info: FallbackInfo, + // 熔断降级信息 + pub fallback_info: Option, + // 是否被销毁 pub destroy: bool, } -enum RetStatus { +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum RetStatus { RetUnknown, RetSuccess, RetFail, @@ -40,21 +54,56 @@ enum RetStatus { } pub struct ResourceStat { - pub resource: *const dyn Resource, + pub resource: Resource, pub ret_code: String, - pub delay: u32, + pub delay: Duration, pub status: RetStatus, } -pub trait Resource {} +pub enum Resource { + ServiceResource(ServiceResource), + MethodResource(MethodResource), + InstanceResource(InstanceResource), +} + +/// ServiceResource 服务资源 +pub struct ServiceResource { + pub callee: ServiceKey, + pub caller: Option, +} -pub struct ServiceResource {} +impl ServiceResource { -impl ServiceResource {} + pub fn new(callee: ServiceKey) -> Self { + ServiceResource { caller: None, callee } + } -pub struct MethodResource {} + pub fn new_waith_caller(caller: ServiceKey, callee: ServiceKey) -> Self { + ServiceResource { caller: Some(caller), callee } + } -impl MethodResource {} +} + +/// MethodResource 方法资源 +pub struct MethodResource { + pub callee: ServiceKey, + pub caller: Option, + pub protocol: String, + pub method: String, + pub path: String, +} + +impl MethodResource { + + pub fn new(callee: ServiceKey, protocol: String, method: String, path: String) -> Self { + MethodResource { caller: None, callee, protocol, method, path } + } + + pub fn new_waith_caller(caller: ServiceKey, callee: ServiceKey, protocol: String, method: String, path: String) -> Self { + MethodResource { caller: Some(caller), callee, protocol, method, path } + } + +} pub struct InstanceResource {} @@ -63,10 +112,50 @@ impl InstanceResource {} pub struct CheckResult { pub pass: bool, pub rule_name: String, + pub fallback_info: Option, +} + +impl CheckResult { + pub fn pass() -> CheckResult { + Self { + pass: true, + rule_name: "".to_string(), + fallback_info: None, + } + } } +#[derive(Debug, Clone)] pub struct FallbackInfo { pub code: String, pub headers: Map, pub body: String, } + +pub struct CallAbortedError +where + Self: Display + Send + Sync, +{ + err: PolarisError, + pub rule_name: String, + pub fallback_info: Option, +} + +impl CallAbortedError { + pub fn new(rule_name: String, fallback_info: Option) -> Self { + CallAbortedError { + err: PolarisError::new( + ErrorCode::CircuitBreakError, + format!("rule {}, fallbackInfo {:?}", rule_name, fallback_info), + ), + rule_name, + fallback_info, + } + } +} + +impl Display for CallAbortedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.err.fmt(f) + } +} diff --git a/src/core/model/config.rs b/src/core/model/config.rs index a9aeda9..f4bd5aa 100644 --- a/src/core/model/config.rs +++ b/src/core/model/config.rs @@ -29,16 +29,16 @@ pub struct ConfigFileRequest { } impl ConfigFileRequest { - pub fn convert_spec(&self) -> crate::core::model::pb::lib::ConfigFile { - let mut tags = Vec::::new(); + pub fn convert_spec(&self) -> polaris_specification::v1::ConfigFile { + let mut tags = Vec::::new(); self.config_file.labels.iter().for_each(|(k, v)| { - tags.push(crate::core::model::pb::lib::ConfigFileTag { + tags.push(polaris_specification::v1::ConfigFileTag { key: Some(k.clone()), value: Some(v.clone()), }); }); - crate::core::model::pb::lib::ConfigFile { + polaris_specification::v1::ConfigFile { id: None, name: Some(self.config_file.name.clone()), namespace: Some(self.config_file.namespace.clone()), @@ -67,8 +67,8 @@ pub struct ConfigReleaseRequest { } impl ConfigReleaseRequest { - pub fn convert_spec(&self) -> crate::core::model::pb::lib::ConfigFileRelease { - crate::core::model::pb::lib::ConfigFileRelease { + pub fn convert_spec(&self) -> polaris_specification::v1::ConfigFileRelease { + polaris_specification::v1::ConfigFileRelease { id: None, name: Some(self.config_file.release_name.clone()), namespace: Some(self.config_file.namespace.clone()), @@ -101,27 +101,48 @@ pub struct ConfigPublishRequest { } impl ConfigPublishRequest { - pub fn convert_spec(&self) -> crate::core::model::pb::lib::ConfigFilePublishInfo { + pub fn convert_spec(&self) -> polaris_specification::v1::ConfigFilePublishInfo { todo!() } } +/// ConfigFile 配置文件 #[derive(Default, Debug, Clone)] pub struct ConfigFile { + // namespace 命名空间 pub namespace: String, + // group 配置分组 pub group: String, + // name 配置文件名 pub name: String, + // version 版本号 pub version: u64, + // content 配置内容 pub content: String, + // labels 配置标签 pub labels: HashMap, - // 配置加解密标识 + // encrypt_algo 配置加解密标识 pub encrypt_algo: String, + // encrypt_key 加密密钥 pub encrypt_key: String, } impl ConfigFile { - pub fn convert_from_spec(f: crate::core::model::pb::lib::ClientConfigFileInfo) -> ConfigFile { - todo!() + pub fn convert_from_spec(f: polaris_specification::v1::ClientConfigFileInfo) -> ConfigFile { + ConfigFile { + namespace: f.namespace.clone().unwrap(), + group: f.group.clone().unwrap(), + name: f.name.clone().unwrap(), + version: f.version.unwrap(), + content: f.content.clone().unwrap(), + labels: f + .tags + .iter() + .map(|tag| (tag.key.clone().unwrap(), tag.value.clone().unwrap())) + .collect(), + encrypt_algo: get_encrypt_algo(&f), + encrypt_key: get_encrypt_data_key(&f), + } } } @@ -139,6 +160,7 @@ pub struct ConfigGroup { pub namespace: String, pub group: String, pub files: Vec, + pub revision: String, } #[derive(Clone, Debug)] @@ -146,24 +168,27 @@ pub struct ConfigFileChangeEvent { pub config_file: ConfigFile, } -impl crate::core::model::pb::lib::ClientConfigFileInfo { - pub fn get_encrypt_data_key(&self) -> String { - for (_k, v) in self.tags.iter().enumerate() { - let label_key = v.key.clone().unwrap(); - if label_key == CONFIG_FILE_TAG_KEY_DATA_KEY { - return v.value.clone().unwrap(); - } +#[derive(Clone, Debug)] +pub struct ConfigGroupChangeEvent { + pub config_group: ConfigGroup, +} + +pub fn get_encrypt_data_key(file: &polaris_specification::v1::ClientConfigFileInfo) -> String { + for (_k, v) in file.tags.iter().enumerate() { + let label_key = v.key.clone().unwrap(); + if label_key == CONFIG_FILE_TAG_KEY_DATA_KEY { + return v.value.clone().unwrap(); } - "".to_string() } + "".to_string() +} - pub fn get_encrypt_algo(&self) -> String { - for (_k, v) in self.tags.iter().enumerate() { - let label_key = v.key.clone().unwrap(); - if label_key == CONFIG_FILE_TAG_KEY_ENCRYPT_ALGO { - return v.value.clone().unwrap(); - } +pub fn get_encrypt_algo(file: &polaris_specification::v1::ClientConfigFileInfo) -> String { + for (_k, v) in file.tags.iter().enumerate() { + let label_key = v.key.clone().unwrap(); + if label_key == CONFIG_FILE_TAG_KEY_ENCRYPT_ALGO { + return v.value.clone().unwrap(); } - "".to_string() } + "".to_string() } diff --git a/src/core/model/mod.rs b/src/core/model/mod.rs index e834aa4..a35b78e 100644 --- a/src/core/model/mod.rs +++ b/src/core/model/mod.rs @@ -13,7 +13,11 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use pb::lib::{ConfigDiscoverRequest, ConfigDiscoverResponse, DiscoverRequest, DiscoverResponse}; +use naming::Location; +use polaris_specification::v1::client::ClientType; +use polaris_specification::v1::{ + ConfigDiscoverRequest, ConfigDiscoverResponse, DiscoverRequest, DiscoverResponse, +}; pub mod cache; pub mod circuitbreaker; @@ -22,11 +26,18 @@ pub mod config; pub mod error; pub mod loadbalance; pub mod naming; -pub mod pb; pub mod ratelimit; pub mod router; pub mod stat; +use std::collections::HashMap; +use std::hash::Hash; + +use super::config::global::ClientConfig; + +static RUST_CLIENT_VERSION: &str = "v0.0.1"; +static RUST_CLIENT_TYPE: &str = "polaris-rust"; + #[derive(Clone)] pub enum DiscoverRequestInfo { Unknown, @@ -35,7 +46,7 @@ pub enum DiscoverRequestInfo { } impl DiscoverRequestInfo { - pub fn to_config_request(&self) -> pb::lib::ConfigDiscoverRequest { + pub fn to_config_request(&self) -> ConfigDiscoverRequest { match self { DiscoverRequestInfo::Configuration(req) => req.clone(), _ => { @@ -53,7 +64,7 @@ pub enum DiscoverResponseInfo { } impl DiscoverResponseInfo { - pub fn to_config_response(&self) -> pb::lib::ConfigDiscoverResponse { + pub fn to_config_response(&self) -> polaris_specification::v1::ConfigDiscoverResponse { match self { DiscoverResponseInfo::Configuration(resp) => resp.clone(), _ => { @@ -62,3 +73,220 @@ impl DiscoverResponseInfo { } } } + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub enum ArgumentType { + Custom, + Method, + Path, + Header, + Cookie, + Query, + CallerService, + CallerIP, +} + +impl ArgumentType { + pub fn parse_from_str(s: &str) -> Self { + match s { + "custom" => ArgumentType::Custom, + "method" => ArgumentType::Method, + "path" => ArgumentType::Path, + "header" => ArgumentType::Header, + "cookie" => ArgumentType::Cookie, + "query" => ArgumentType::Query, + "caller_service" => ArgumentType::CallerService, + "caller_ip" => ArgumentType::CallerIP, + _ => ArgumentType::Custom, + } + } +} + +#[derive(Debug, Clone)] +pub struct TrafficArgument { + arg_type: ArgumentType, + key: String, + value: String, +} + +impl TrafficArgument { + pub fn new(arg_type: ArgumentType, key: String, value: String) -> Self { + Self { + arg_type, + key, + value, + } + } + + pub fn get_type(&self) -> &ArgumentType { + &self.arg_type + } + + pub fn get_key(&self) -> &String { + &self.key + } + + pub fn get_value(&self) -> &String { + &self.value + } + + pub fn build_custom(key: String, value: String) -> Self { + TrafficArgument::new(ArgumentType::Custom, key, value) + } + + pub fn build_path(path: String) -> Self { + TrafficArgument::new(ArgumentType::Path, String::new(), path) + } + + pub fn build_method(method: String) -> Self { + TrafficArgument::new(ArgumentType::Method, String::new(), method) + } + + pub fn build_header(header_key: String, header_value: String) -> Self { + TrafficArgument::new(ArgumentType::Header, header_key, header_value) + } + + pub fn build_query(query_key: String, query_value: String) -> Self { + TrafficArgument::new(ArgumentType::Query, query_key, query_value) + } + + pub fn build_cookie(cookie_key: String, cookie_value: String) -> Self { + TrafficArgument::new(ArgumentType::Cookie, cookie_key, cookie_value) + } + + pub fn build_caller_service(namespace: String, service: String) -> Self { + TrafficArgument::new(ArgumentType::CallerService, namespace, service) + } + + pub fn build_caller_ip(caller_ip: String) -> Self { + TrafficArgument::new(ArgumentType::CallerIP, String::new(), caller_ip) + } + + pub fn from_label(label_key: String, label_value: String) -> Self { + if label_key == "method" { + TrafficArgument::build_method(label_value) + } else if label_key == "caller_ip" { + TrafficArgument::build_caller_ip(label_value) + } else if label_key.starts_with("header") { + TrafficArgument::build_header(label_key["header".len()..].to_string(), label_value) + } else if label_key.starts_with("query") { + TrafficArgument::build_query(label_key["query".len()..].to_string(), label_value) + } else if label_key.starts_with("caller_service") { + TrafficArgument::build_caller_service( + label_key["caller_service".len()..].to_string(), + label_value, + ) + } else if label_key == "path" { + TrafficArgument::build_path(label_value) + } else if label_key.starts_with("cookie") { + TrafficArgument::build_cookie(label_key["cookie".len()..].to_string(), label_value) + } else { + TrafficArgument::build_custom(label_key, label_value) + } + } + + pub fn to_label(&self, labels: &mut HashMap) { + match self.arg_type { + ArgumentType::Method => { + labels.insert("method".to_string(), self.value.clone()); + } + ArgumentType::CallerIP => { + labels.insert("caller_ip".to_string(), self.value.clone()); + } + ArgumentType::Header => { + labels.insert(format!("header.{}", self.key), self.value.clone()); + } + ArgumentType::Query => { + labels.insert(format!("query.{}", self.key), self.value.clone()); + } + ArgumentType::CallerService => { + labels.insert(format!("caller_service{}", self.key), self.value.clone()); + } + ArgumentType::Custom => { + labels.insert(self.key.clone(), self.value.clone()); + } + ArgumentType::Path => { + labels.insert("path".to_string(), self.value.clone()); + } + ArgumentType::Cookie => { + labels.insert(format!("cookie.{}", self.key), self.value.clone()); + } + } + } +} + +pub struct ReportClientRequest { + pub client_id: String, + pub host: String, + pub version: String, + pub location: Location, +} + +impl ReportClientRequest { + pub fn convert_spec(&self) -> polaris_specification::v1::Client { + polaris_specification::v1::Client { + id: Some(self.client_id.clone()), + host: Some(self.host.clone()), + version: Some(self.version.clone()), + location: Some(self.location.convert_spec()), + r#type: ClientType::Sdk.into(), + stat: vec![], + ctime: None, + mtime: None, + } + } +} + +pub struct ClientContext { + pub client_id: String, + pub pid: u32, + pub pod: String, + pub host: String, + pub version: String, + pub labels: HashMap, +} + +impl ClientContext { + pub fn new(client_id: String, ip: String, cfg: &ClientConfig) -> ClientContext { + let mut labels = HashMap::::new(); + labels.clone_from(&cfg.labels); + + labels.insert("CLIENT_IP".to_string(), ip.to_string()); + labels.insert("CLIENT_ID".to_string(), client_id.clone()); + labels.insert( + "CLIENT_VERSION".to_string(), + RUST_CLIENT_VERSION.to_string(), + ); + labels.insert("CLIENT_LANGUAGE".to_string(), RUST_CLIENT_TYPE.to_string()); + + Self { + client_id: client_id, + pid: std::process::id(), + pod: get_pod_name(), + host: std::env::var("HOSTNAME").unwrap_or_else(|_| "".to_string()), + version: RUST_CLIENT_VERSION.to_string(), + labels: labels, + } + } +} + +pub fn get_pod_name() -> String { + // 各种容器平台的获取容器名字的环境变量. + let container_name_envs = vec![ + // taf/sumeru容器环境变量 + "CONTAINER_NAME", + // 123容器的环境变量 + "SUMERU_POD_NAME", + // STKE(CSIG) 微信TKE TKE-x(TEG) + "POD_NAME", + // tkestack(CDG) + "MY_POD_NAME", + ]; + + for k in container_name_envs { + if let Ok(pod_name) = std::env::var(k) { + return pod_name; + } + } + return "".to_string(); +} diff --git a/src/core/model/naming.rs b/src/core/model/naming.rs index 7a023a6..17ffe97 100644 --- a/src/core/model/naming.rs +++ b/src/core/model/naming.rs @@ -13,9 +13,10 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use crate::core::model::pb::lib::HeartbeatHealthCheck; +use polaris_specification::v1::HeartbeatHealthCheck; use prost::Message; -use std::collections::HashMap; +use serde::{Deserialize, Serialize}; +use std::{any::Any, collections::HashMap}; #[derive(Default)] pub struct Services { @@ -24,7 +25,7 @@ pub struct Services { pub initialized: bool, } -#[derive(Default, Debug, PartialEq, Eq)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct ServiceKey { pub namespace: String, pub name: String, @@ -36,7 +37,7 @@ impl ServiceKey { } } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct ServiceInfo { pub id: String, pub namespace: String, @@ -78,7 +79,8 @@ impl ServiceInstances { } } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Instance { pub id: String, pub namespace: String, @@ -115,7 +117,7 @@ impl Instance { true } - pub fn convert_from_spec(data: crate::core::model::pb::lib::Instance) -> Instance { + pub fn convert_from_spec(data: polaris_specification::v1::Instance) -> Instance { let mut metadata = HashMap::::new(); for ele in data.metadata { metadata.insert(ele.0, ele.1); @@ -146,7 +148,7 @@ impl Instance { } } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct Location { pub region: String, pub zone: String, @@ -162,8 +164,8 @@ impl Location { } } - pub fn convert_spec(&self) -> crate::core::model::pb::lib::Location { - crate::core::model::pb::lib::Location { + pub fn convert_spec(&self) -> polaris_specification::v1::Location { + polaris_specification::v1::Location { region: Some(self.region.clone()), zone: Some(self.zone.clone()), campus: Some(self.campus.clone()), @@ -176,7 +178,7 @@ impl Location { } pub struct ServiceRule { - pub rules: Vec>, + pub rules: Vec>, pub revision: String, pub initialized: bool, } @@ -204,8 +206,8 @@ pub struct InstanceRequest { } impl InstanceRequest { - pub fn convert_beat_spec(&self) -> crate::core::model::pb::lib::Instance { - crate::core::model::pb::lib::Instance { + pub fn convert_beat_spec(&self) -> polaris_specification::v1::Instance { + polaris_specification::v1::Instance { id: None, namespace: Some(self.instance.namespace.clone()), service: Some(self.instance.service.clone()), @@ -230,21 +232,21 @@ impl InstanceRequest { } } - pub fn convert_spec(&self) -> crate::core::model::pb::lib::Instance { + pub fn convert_spec(&self) -> polaris_specification::v1::Instance { let ttl = self.ttl; let mut enable_health_check = Some(false); let mut health_check = None; if ttl != 0 { enable_health_check = Some(true); - health_check = Some(crate::core::model::pb::lib::HealthCheck { + health_check = Some(polaris_specification::v1::HealthCheck { r#type: i32::from( - crate::core::model::pb::lib::health_check::HealthCheckType::Heartbeat, + polaris_specification::v1::health_check::HealthCheckType::Heartbeat, ), heartbeat: Some(HeartbeatHealthCheck { ttl: Some(ttl) }), }); } - let mut spec_ins = crate::core::model::pb::lib::Instance { + let mut spec_ins = polaris_specification::v1::Instance { id: None, service: Some(self.instance.service.to_string()), namespace: Some(self.instance.namespace.to_string()), @@ -269,9 +271,9 @@ impl InstanceRequest { }; if self.ttl != 0 { spec_ins.enable_health_check = Some(true); - spec_ins.health_check = Some(crate::core::model::pb::lib::HealthCheck { + spec_ins.health_check = Some(polaris_specification::v1::HealthCheck { r#type: i32::from( - crate::core::model::pb::lib::health_check::HealthCheckType::Heartbeat, + polaris_specification::v1::health_check::HealthCheckType::Heartbeat, ), heartbeat: Some(HeartbeatHealthCheck { ttl: Some(self.ttl), @@ -310,3 +312,116 @@ pub struct ServiceInstancesChangeEvent { pub service: ServiceInfo, pub instances: Vec, } + +#[derive(Clone, Debug)] +pub struct ServiceContractRequest { + pub flow_id: String, + pub contract: ServiceContract, +} + +#[derive(Clone, Debug)] +pub struct ServiceContract { + pub name: String, + // 所属命名空间 + pub namespace: String, + // 所属服务名称 + pub service: String, + // 契约版本 + pub version: String, + // 协议,http/grpc/dubbo/thrift + pub protocol: String, + // 额外描述 + pub content: String, + // 接口描述信息 + pub interfaces: Vec, + // 标签 + pub metadata: HashMap, +} + +impl ServiceContract { + pub fn parse_from_spec(spec: polaris_specification::v1::ServiceContract) -> Self { + let mut interfaces = Vec::::new(); + for ele in spec.interfaces { + interfaces.push(ServiceInterfaceDescripitor { + name: ele.r#type.clone(), + namespace: ele.namespace.clone(), + service: ele.service.clone(), + version: ele.version.clone(), + protocol: ele.protocol.clone(), + path: ele.path.clone(), + method: ele.method.clone(), + content: ele.content.clone(), + }); + } + Self { + name: spec.name.clone(), + namespace: spec.namespace.clone(), + service: spec.service.clone(), + content: spec.content.clone(), + version: spec.version.clone(), + protocol: spec.protocol.clone(), + interfaces, + metadata: HashMap::new(), + } + } + + pub fn convert_spec(&self) -> polaris_specification::v1::ServiceContract { + let mut spec = polaris_specification::v1::ServiceContract { + id: "".to_string(), + name: self.name.clone(), + namespace: self.namespace.clone(), + service: self.service.clone(), + content: self.content.clone(), + version: self.version.clone(), + protocol: self.protocol.clone(), + interfaces: Vec::new(), + status: "".to_string(), + revision: "".to_string(), + r#type: self.name.clone(), + ctime: "".to_string(), + mtime: "".to_string(), + metadata: HashMap::new(), + }; + for ele in self.interfaces.iter() { + spec.interfaces + .push(polaris_specification::v1::InterfaceDescriptor { + id: "".to_string(), + name: self.name.clone(), + namespace: ele.namespace.clone(), + service: ele.service.clone(), + version: ele.version.clone(), + content: ele.content.clone(), + path: ele.path.clone(), + method: ele.method.clone(), + protocol: ele.protocol.clone(), + source: polaris_specification::v1::interface_descriptor::Source::Client.into(), + revision: "".to_string(), + r#type: ele.name.clone(), + ctime: "".to_string(), + mtime: "".to_string(), + }); + } + spec + } +} + +/// ServiceInterfaceDescripitor 服务接口信息描述 +#[derive(Clone, Debug)] +pub struct ServiceInterfaceDescripitor { + // 接口类型 + pub name: String, + // 所属命名空间 + pub namespace: String, + // 所属服务名称 + pub service: String, + // 契约版本 + pub version: String, + // 协议,http/grpc/dubbo/thrift + pub protocol: String, + // 接口名称,http path/dubbo interface/grpc service + pub path: String, + // 方法名称,对应 http method/ dubbo interface func/grpc service func + pub method: String, + // 接口描述信息 + pub content: String, +} diff --git a/src/core/model/pb/lib.rs b/src/core/model/pb/lib.rs deleted file mode 100644 index a050665..0000000 --- a/src/core/model/pb/lib.rs +++ /dev/null @@ -1,6030 +0,0 @@ -// This file is @generated by prost-build. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Location { - #[prost(message, optional, tag = "1")] - pub region: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub zone: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub campus: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MatchString { - #[prost(enumeration = "match_string::MatchStringType", tag = "1")] - pub r#type: i32, - #[prost(message, optional, tag = "2")] - pub value: ::core::option::Option<::prost::alloc::string::String>, - #[prost(enumeration = "match_string::ValueType", tag = "3")] - pub value_type: i32, -} -/// Nested message and enum types in `MatchString`. -pub mod match_string { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum MatchStringType { - /// Equivalent match - Exact = 0, - /// Regular match - Regex = 1, - /// Not equals match - NotEquals = 2, - /// Include match - In = 3, - /// Not include match - NotIn = 4, - /// Range match - Range = 5, - } - impl MatchStringType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - MatchStringType::Exact => "EXACT", - MatchStringType::Regex => "REGEX", - MatchStringType::NotEquals => "NOT_EQUALS", - MatchStringType::In => "IN", - MatchStringType::NotIn => "NOT_IN", - MatchStringType::Range => "RANGE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "EXACT" => Some(Self::Exact), - "REGEX" => Some(Self::Regex), - "NOT_EQUALS" => Some(Self::NotEquals), - "IN" => Some(Self::In), - "NOT_IN" => Some(Self::NotIn), - "RANGE" => Some(Self::Range), - _ => None, - } - } - } - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum ValueType { - Text = 0, - Parameter = 1, - Variable = 2, - } - impl ValueType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ValueType::Text => "TEXT", - ValueType::Parameter => "PARAMETER", - ValueType::Variable => "VARIABLE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "TEXT" => Some(Self::Text), - "PARAMETER" => Some(Self::Parameter), - "VARIABLE" => Some(Self::Variable), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StringList { - #[prost(string, repeated, tag = "1")] - pub values: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -/// 汇总查询数据 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Summary { - /// 服务总数 - #[prost(uint32, tag = "1")] - pub total_service_count: u32, - /// 健康实例总数 - #[prost(uint32, tag = "2")] - pub total_health_instance_count: u32, - /// 实例总数 - #[prost(uint32, tag = "3")] - pub total_instance_count: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ClientLabel { - #[prost(string, tag = "1")] - pub key: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub value: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Service { - #[prost(message, optional, tag = "1")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(map = "string, string", tag = "3")] - pub metadata: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub ports: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub business: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub department: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub cmdb_mod1: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub cmdb_mod2: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub cmdb_mod3: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "10")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub owners: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "13")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "14")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "16")] - pub platform_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "17")] - pub total_instance_count: ::core::option::Option, - #[prost(message, optional, tag = "18")] - pub healthy_instance_count: ::core::option::Option, - #[prost(message, repeated, tag = "19")] - pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "20")] - pub group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "22")] - pub remove_user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "23")] - pub remove_group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, optional, tag = "21")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "24")] - pub editable: ::core::option::Option, - #[prost(message, repeated, tag = "25")] - pub export_to: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ServiceAlias { - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub alias: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub alias_namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(enumeration = "AliasType", tag = "5")] - pub r#type: i32, - #[prost(message, optional, tag = "6")] - pub owners: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub service_token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "10")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub editable: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Instance { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "21")] - pub vpc_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub host: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub port: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub protocol: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub version: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub priority: ::core::option::Option, - #[prost(message, optional, tag = "9")] - pub weight: ::core::option::Option, - #[prost(message, optional, tag = "20")] - pub enable_health_check: ::core::option::Option, - #[prost(message, optional, tag = "10")] - pub health_check: ::core::option::Option, - #[prost(message, optional, tag = "11")] - pub healthy: ::core::option::Option, - #[prost(message, optional, tag = "12")] - pub isolate: ::core::option::Option, - #[prost(message, optional, tag = "13")] - pub location: ::core::option::Option, - #[prost(map = "string, string", tag = "14")] - pub metadata: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub logic_set: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "16")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "17")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "18")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "19")] - pub service_token: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HealthCheck { - #[prost(enumeration = "health_check::HealthCheckType", tag = "1")] - pub r#type: i32, - #[prost(message, optional, tag = "2")] - pub heartbeat: ::core::option::Option, -} -/// Nested message and enum types in `HealthCheck`. -pub mod health_check { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum HealthCheckType { - Unknown = 0, - Heartbeat = 1, - } - impl HealthCheckType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - HealthCheckType::Unknown => "UNKNOWN", - HealthCheckType::Heartbeat => "HEARTBEAT", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "HEARTBEAT" => Some(Self::Heartbeat), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HeartbeatHealthCheck { - #[prost(message, optional, tag = "1")] - pub ttl: ::core::option::Option, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum AliasType { - Default = 0, - Cl5sid = 1, -} -impl AliasType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - AliasType::Default => "DEFAULT", - AliasType::Cl5sid => "CL5SID", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "DEFAULT" => Some(Self::Default), - "CL5SID" => Some(Self::Cl5sid), - _ => None, - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Client { - #[prost(message, optional, tag = "1")] - pub host: ::core::option::Option<::prost::alloc::string::String>, - #[prost(enumeration = "client::ClientType", tag = "2")] - pub r#type: i32, - #[prost(message, optional, tag = "3")] - pub version: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub location: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "6")] - pub stat: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "7")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, -} -/// Nested message and enum types in `Client`. -pub mod client { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum ClientType { - Unknown = 0, - Sdk = 1, - Agent = 2, - } - impl ClientType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ClientType::Unknown => "UNKNOWN", - ClientType::Sdk => "SDK", - ClientType::Agent => "AGENT", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "SDK" => Some(Self::Sdk), - "AGENT" => Some(Self::Agent), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StatInfo { - #[prost(message, optional, tag = "1")] - pub target: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub port: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub path: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub protocol: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ServiceContract { - /// 契约ID - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// 契约名称 - /// deprecated, use type field - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// 所属命名空间 - #[prost(string, tag = "3")] - pub namespace: ::prost::alloc::string::String, - /// 所属服务名称 - #[prost(string, tag = "4")] - pub service: ::prost::alloc::string::String, - /// 协议,http/grpc/dubbo/thrift - #[prost(string, tag = "5")] - pub protocol: ::prost::alloc::string::String, - /// 契约版本 - #[prost(string, tag = "6")] - pub version: ::prost::alloc::string::String, - /// 信息摘要 - #[prost(string, tag = "7")] - pub revision: ::prost::alloc::string::String, - /// 额外描述 - #[prost(string, tag = "8")] - pub content: ::prost::alloc::string::String, - /// 接口描述信息 - #[prost(message, repeated, tag = "9")] - pub interfaces: ::prost::alloc::vec::Vec, - /// 创建时间 - #[prost(string, tag = "10")] - pub ctime: ::prost::alloc::string::String, - /// 更新时间 - #[prost(string, tag = "11")] - pub mtime: ::prost::alloc::string::String, - /// 接口状态,Offline/Online - #[prost(string, tag = "12")] - pub status: ::prost::alloc::string::String, - /// 类型 - #[prost(string, tag = "14")] - pub r#type: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InterfaceDescriptor { - /// 接口ID - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// 方法名称,对应 http method/ dubbo interface func/grpc service func - #[prost(string, tag = "2")] - pub method: ::prost::alloc::string::String, - /// 接口名称,http path/dubbo interface/grpc service - #[prost(string, tag = "3")] - pub path: ::prost::alloc::string::String, - /// 接口描述信息 - #[prost(string, tag = "4")] - pub content: ::prost::alloc::string::String, - /// 创建来源 - #[prost(enumeration = "interface_descriptor::Source", tag = "5")] - pub source: i32, - /// 接口信息摘要 - #[prost(string, tag = "6")] - pub revision: ::prost::alloc::string::String, - /// 创建时间 - #[prost(string, tag = "7")] - pub ctime: ::prost::alloc::string::String, - /// 更新时间 - #[prost(string, tag = "8")] - pub mtime: ::prost::alloc::string::String, - /// 接口名称描述信息 - /// deprecated, use type field - #[prost(string, tag = "9")] - pub name: ::prost::alloc::string::String, - /// 所属命名空间 - #[prost(string, tag = "10")] - pub namespace: ::prost::alloc::string::String, - /// 所属服务名称 - #[prost(string, tag = "11")] - pub service: ::prost::alloc::string::String, - /// 协议,http/grpc/dubbo/thrift - #[prost(string, tag = "12")] - pub protocol: ::prost::alloc::string::String, - /// 契约版本 - #[prost(string, tag = "13")] - pub version: ::prost::alloc::string::String, - /// 类型 - #[prost(string, tag = "14")] - pub r#type: ::prost::alloc::string::String, -} -/// Nested message and enum types in `InterfaceDescriptor`. -pub mod interface_descriptor { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Source { - Unknown = 0, - Manual = 1, - Client = 2, - } - impl Source { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Source::Unknown => "UNKNOWN", - Source::Manual => "Manual", - Source::Client => "Client", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "Manual" => Some(Self::Manual), - "Client" => Some(Self::Client), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DiscoverFilter { - #[prost(bool, tag = "1")] - pub only_healthy_instance: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DiscoverRequest { - #[prost(enumeration = "discover_request::DiscoverRequestType", tag = "1")] - pub r#type: i32, - #[prost(message, optional, tag = "2")] - pub service: ::core::option::Option, - #[prost(message, optional, tag = "30")] - pub filter: ::core::option::Option, -} -/// Nested message and enum types in `DiscoverRequest`. -pub mod discover_request { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum DiscoverRequestType { - Unknown = 0, - Instance = 1, - Cluster = 2, - Routing = 3, - RateLimit = 4, - CircuitBreaker = 5, - Services = 6, - Namespaces = 12, - FaultDetector = 13, - Lane = 100, - } - impl DiscoverRequestType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - DiscoverRequestType::Unknown => "UNKNOWN", - DiscoverRequestType::Instance => "INSTANCE", - DiscoverRequestType::Cluster => "CLUSTER", - DiscoverRequestType::Routing => "ROUTING", - DiscoverRequestType::RateLimit => "RATE_LIMIT", - DiscoverRequestType::CircuitBreaker => "CIRCUIT_BREAKER", - DiscoverRequestType::Services => "SERVICES", - DiscoverRequestType::Namespaces => "NAMESPACES", - DiscoverRequestType::FaultDetector => "FAULT_DETECTOR", - DiscoverRequestType::Lane => "LANE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "INSTANCE" => Some(Self::Instance), - "CLUSTER" => Some(Self::Cluster), - "ROUTING" => Some(Self::Routing), - "RATE_LIMIT" => Some(Self::RateLimit), - "CIRCUIT_BREAKER" => Some(Self::CircuitBreaker), - "SERVICES" => Some(Self::Services), - "NAMESPACES" => Some(Self::Namespaces), - "FAULT_DETECTOR" => Some(Self::FaultDetector), - "LANE" => Some(Self::Lane), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Namespace { - #[prost(message, optional, tag = "1")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub owners: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub total_service_count: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub total_health_instance_count: ::core::option::Option, - #[prost(message, optional, tag = "9")] - pub total_instance_count: ::core::option::Option, - #[prost(message, repeated, tag = "10")] - pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "11")] - pub group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "13")] - pub remove_user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "14")] - pub remove_group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub editable: ::core::option::Option, - #[prost(message, repeated, tag = "16")] - pub service_export_to: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -/// 规则所属服务以及命名空间 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Routing { - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 每个服务可以配置多条入站或者出站规则 - /// 对于每个请求,从上到下依次匹配,若命中则终止 - #[prost(message, repeated, tag = "3")] - pub inbounds: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub outbounds: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "5")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub service_token: ::core::option::Option<::prost::alloc::string::String>, - /// route rules for current service - #[prost(message, repeated, tag = "21")] - pub rules: ::prost::alloc::vec::Vec, -} -/// deprecated: only for compatible to the old version server -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Route { - /// 如果匹配Source规则,按照Destination路由 - /// 多个Source之间的关系为或 - #[prost(message, repeated, tag = "1")] - pub sources: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub destinations: ::prost::alloc::vec::Vec, - /// extendInfo 用于承载一些额外信息 - /// case 1: 升级到 v2 版本时,记录对应到 v2 版本的 id 信息 - #[prost(map = "string, string", tag = "3")] - pub extend_info: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -/// deprecated: only for compatible to the old version server -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Source { - /// 主调方服务以及命名空间 - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 主调方服务实例标签或者请求标签 - /// value支持正则匹配 - #[prost(map = "string, message", tag = "3")] - pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, -} -/// deprecated: only for compatible to the old version server -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Destination { - /// 被调方服务以及命名空间 - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 被调方服务实例标签 - /// value支持正则匹配 - #[prost(map = "string, message", tag = "3")] - pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, - /// 根据服务名和服务实例metadata筛选符合条件的服务实例子集 - /// 服务实例子集可以设置优先级和权重 - /// 优先级:整型,范围\[0, 9\],最高优先级为0 - /// 权重:整型 - /// 先按优先级路由,如果存在高优先级,不会使用低优先级 - /// 如果存在优先级相同的子集,再按权重分配 - /// 优先级和权重可以都不设置/设置一个/设置两个 - /// 如果部分设置优先级,部分没有设置,认为没有设置的优先级最低 - /// 如果部分设置权重,部分没有设置,认为没有设置的权重为0 - /// 如果全部没有设置权重,认为权重相同 - #[prost(message, optional, tag = "4")] - pub priority: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub weight: ::core::option::Option, - /// 将请求转发到代理服务 - #[prost(message, optional, tag = "6")] - pub transfer: ::core::option::Option<::prost::alloc::string::String>, - /// 是否对该set执行隔离,隔离后,不会再分配流量 - #[prost(message, optional, tag = "7")] - pub isolate: ::core::option::Option, - /// 实例分组名 - #[prost(message, optional, tag = "8")] - pub name: ::core::option::Option<::prost::alloc::string::String>, -} -/// configuration root for route -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RouteRule { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// route rule name - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// namespace namingspace of routing rules - #[prost(string, tag = "3")] - pub namespace: ::prost::alloc::string::String, - /// Enable this router - #[prost(bool, tag = "4")] - pub enable: bool, - /// Router type - #[prost(enumeration = "RoutingPolicy", tag = "5")] - pub routing_policy: i32, - /// Routing configuration for router - #[prost(message, optional, tag = "6")] - pub routing_config: ::core::option::Option<::prost_types::Any>, - /// revision routing version - #[prost(string, tag = "7")] - pub revision: ::prost::alloc::string::String, - /// ctime create time of the rules - #[prost(string, tag = "8")] - pub ctime: ::prost::alloc::string::String, - /// mtime modify time of the rules - #[prost(string, tag = "9")] - pub mtime: ::prost::alloc::string::String, - /// etime enable time of the rules - #[prost(string, tag = "10")] - pub etime: ::prost::alloc::string::String, - /// priority rules priority - #[prost(uint32, tag = "11")] - pub priority: u32, - /// description simple description rules - #[prost(string, tag = "12")] - pub description: ::prost::alloc::string::String, - /// extendInfo 用于承载一些额外信息 - /// case 1: 升级到 v2 版本时,记录对应到 v1 版本的 id 信息 - #[prost(map = "string, string", tag = "20")] - pub extend_info: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MetadataFailover { - /// failover_range metadata route bottom type - #[prost(enumeration = "metadata_failover::FailoverRange", tag = "1")] - pub failover_range: i32, - /// only use to failover_range == OTHER_KEYS - #[prost(map = "string, string", tag = "2")] - pub labels: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -/// Nested message and enum types in `MetadataFailover`. -pub mod metadata_failover { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum FailoverRange { - /// ALL return all instances - All = 0, - /// OTHERS retuen without thie labels instances - Others = 1, - /// OTHER_KEYS return other instances which match keys - OtherKeys = 2, - } - impl FailoverRange { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - FailoverRange::All => "ALL", - FailoverRange::Others => "OTHERS", - FailoverRange::OtherKeys => "OTHER_KEYS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "ALL" => Some(Self::All), - "OTHERS" => Some(Self::Others), - "OTHER_KEYS" => Some(Self::OtherKeys), - _ => None, - } - } - } -} -/// MetadataRoutingConfig metadata routing configuration -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MetadataRoutingConfig { - /// service - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - /// namespace - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - #[prost(map = "string, string", tag = "3")] - pub labels: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, - /// When metadata not found, it will fall back to the - #[prost(message, optional, tag = "4")] - pub failover: ::core::option::Option, -} -/// RuleRoutingConfig routing configuration -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RuleRoutingConfig { - /// source source info - /// deprecated: only for compatible to the old version server - #[prost(message, repeated, tag = "1")] - pub sources: ::prost::alloc::vec::Vec, - /// destination destinations info - /// deprecated: only for compatible to the old version server - #[prost(message, repeated, tag = "2")] - pub destinations: ::prost::alloc::vec::Vec, - /// rule route chain - #[prost(message, repeated, tag = "3")] - pub rules: ::prost::alloc::vec::Vec, -} -/// SubRuleRouting sub routing configuration -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubRuleRouting { - /// sub routing rule name - #[prost(string, tag = "1")] - pub name: ::prost::alloc::string::String, - /// source source info - #[prost(message, repeated, tag = "2")] - pub sources: ::prost::alloc::vec::Vec, - /// destination destinations info - #[prost(message, repeated, tag = "3")] - pub destinations: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SourceService { - /// Main tuning service and namespace - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - /// Master Control Service Example Tag or Request Label - /// Value supports regular matching - #[prost(message, repeated, tag = "3")] - pub arguments: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DestinationGroup { - /// Templated service and namespace - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - /// Templated service example label - /// Value supports regular matching - #[prost(map = "string, message", tag = "3")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, - /// According to the service name and service instance Metadata Filter the - /// qualified service instance subset Service instance subset can set priority - /// and weight Priority: integer, range \[0, 9\], the highest priority is 0 - /// Weight: Integer - /// Press priority routing, if there is high priority, low priority will not - /// use If there is a subset of the same priority, then assign by weight - /// Priority and weight can be not set / set up one / set two - /// If the section is set priority, some are not set, it is considered that the - /// priority is not set. If the part is set, some is not set, it is considered - /// that the weight is not set to 0 If you have no weight, you think the weight - /// is the same - #[prost(uint32, tag = "4")] - pub priority: u32, - #[prost(uint32, tag = "5")] - pub weight: u32, - /// Forward requests to proxy service - #[prost(string, tag = "6")] - pub transfer: ::prost::alloc::string::String, - /// Whether to isolate the SET, after isolation, no traffic will be allocated - #[prost(bool, tag = "7")] - pub isolate: bool, - /// name desition name - #[prost(string, tag = "8")] - pub name: ::prost::alloc::string::String, -} -/// SourceMatch -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SourceMatch { - #[prost(enumeration = "source_match::Type", tag = "1")] - pub r#type: i32, - /// header key or query key - #[prost(string, tag = "2")] - pub key: ::prost::alloc::string::String, - /// header value or query value - #[prost(message, optional, tag = "3")] - pub value: ::core::option::Option, -} -/// Nested message and enum types in `SourceMatch`. -pub mod source_match { - /// label type for gateway request - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Type { - /// custom arguments - Custom = 0, - /// method, match the http post/get/put/delete or grpc method - Method = 1, - /// header, match the http header, dubbo attachment, grpc header - Header = 2, - /// query, match the http query, dubbo argument - Query = 3, - /// caller host ip - CallerIp = 4, - /// path, math the http url - Path = 5, - /// cookie match http cookie - Cookie = 6, - } - impl Type { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Type::Custom => "CUSTOM", - Type::Method => "METHOD", - Type::Header => "HEADER", - Type::Query => "QUERY", - Type::CallerIp => "CALLER_IP", - Type::Path => "PATH", - Type::Cookie => "COOKIE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CUSTOM" => Some(Self::Custom), - "METHOD" => Some(Self::Method), - "HEADER" => Some(Self::Header), - "QUERY" => Some(Self::Query), - "CALLER_IP" => Some(Self::CallerIp), - "PATH" => Some(Self::Path), - "COOKIE" => Some(Self::Cookie), - _ => None, - } - } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum RoutingPolicy { - /// Route by rule rule => RuleRoutingConfig - RulePolicy = 0, - /// Route by destination metadata ==> MetadataRoutingConfig - MetadataPolicy = 1, -} -impl RoutingPolicy { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - RoutingPolicy::RulePolicy => "RulePolicy", - RoutingPolicy::MetadataPolicy => "MetadataPolicy", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "RulePolicy" => Some(Self::RulePolicy), - "MetadataPolicy" => Some(Self::MetadataPolicy), - _ => None, - } - } -} -/// 同一服务下限流规则集合 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RateLimit { - /// 限流规则集合 - #[prost(message, repeated, tag = "1")] - pub rules: ::prost::alloc::vec::Vec, - /// 限流规则汇总的revision信息 - #[prost(message, optional, tag = "2")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, -} -/// 单个限流规则信息 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Rule { - /// 限流规则唯一标识 - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则所属服务名 - #[prost(message, optional, tag = "2")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则所属命名空间 - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 可选,SUBSET标识 - #[prost(map = "string, message", tag = "4")] - pub subset: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, - /// 限流规则优先级,0值最高 - #[prost(message, optional, tag = "5")] - pub priority: ::core::option::Option, - #[prost(enumeration = "rule::Resource", tag = "6")] - pub resource: i32, - #[prost(enumeration = "rule::Type", tag = "7")] - pub r#type: i32, - /// 业务标签集合,通过KV进行匹配,全部匹配才使用该规则 - #[prost(map = "string, message", tag = "8")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, - /// 限流阈值 - /// 可以有多个粒度的配置(比如同时针对秒级,分钟级,天级),匹配一个则进行限流 - /// 全局限流模式下,该值为服务配额总量;单机限流模式下,该值为单个节点能处理的配额量 - #[prost(message, repeated, tag = "9")] - pub amounts: ::prost::alloc::vec::Vec, - /// 限流动作,对应着客户端的插件名字 - #[prost(message, optional, tag = "10")] - pub action: ::core::option::Option<::prost::alloc::string::String>, - /// 是否停用该限流规则,默认启用 - #[prost(message, optional, tag = "11")] - pub disable: ::core::option::Option, - /// 限流上报方式,同时支持按固定周期上报,以及达到配额百分比后上报 - #[prost(message, optional, tag = "12")] - pub report: ::core::option::Option, - /// 限流规则创建时间 - #[prost(message, optional, tag = "13")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则修改时间 - #[prost(message, optional, tag = "14")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则revision信息 - #[prost(message, optional, tag = "15")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - /// 服务的TOKEN信息,仅用于控制台,discover接口不下发 - #[prost(message, optional, tag = "16")] - pub service_token: ::core::option::Option<::prost::alloc::string::String>, - /// 配额调整算法 - #[prost(message, optional, tag = "17")] - pub adjuster: ::core::option::Option, - /// 通配符是否合并计算,默认分开计数 - #[prost(message, optional, tag = "18")] - pub regex_combine: ::core::option::Option, - #[prost(enumeration = "rule::AmountMode", tag = "19")] - pub amount_mode: i32, - #[prost(enumeration = "rule::FailoverType", tag = "20")] - pub failover: i32, - /// 分布式限流服务集群 - #[prost(message, optional, tag = "21")] - pub cluster: ::core::option::Option, - /// 被调接口名 - #[prost(message, optional, tag = "22")] - pub method: ::core::option::Option, - /// 被调的参数过滤条件,满足过滤条件才进入限流规则 - #[prost(message, repeated, tag = "23")] - pub arguments: ::prost::alloc::vec::Vec, - /// 限流规则名 - #[prost(message, optional, tag = "24")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则启用时间 - #[prost(message, optional, tag = "25")] - pub etime: ::core::option::Option<::prost::alloc::string::String>, - /// 最大排队时长,单位秒 - #[prost(message, optional, tag = "26")] - pub max_queue_delay: ::core::option::Option, -} -/// Nested message and enum types in `Rule`. -pub mod rule { - /// 限流资源 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Resource { - /// 针对QPS进行限流 - Qps = 0, - /// 针对并发数进行限流 - Concurrency = 1, - } - impl Resource { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Resource::Qps => "QPS", - Resource::Concurrency => "CONCURRENCY", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "QPS" => Some(Self::Qps), - "CONCURRENCY" => Some(Self::Concurrency), - _ => None, - } - } - } - /// 限流类型 - /// global全局限流(默认)或者local单机限流 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Type { - Global = 0, - Local = 1, - } - impl Type { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Type::Global => "GLOBAL", - Type::Local => "LOCAL", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "GLOBAL" => Some(Self::Global), - "LOCAL" => Some(Self::Local), - _ => None, - } - } - } - /// 限流阈值模 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum AmountMode { - /// 总体阈值 - GlobalTotal = 0, - /// 单机均摊阈值 - ShareEqually = 1, - } - impl AmountMode { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - AmountMode::GlobalTotal => "GLOBAL_TOTAL", - AmountMode::ShareEqually => "SHARE_EQUALLY", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "GLOBAL_TOTAL" => Some(Self::GlobalTotal), - "SHARE_EQUALLY" => Some(Self::ShareEqually), - _ => None, - } - } - } - /// 与限流集群连接失败时降级模式 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum FailoverType { - /// 降级成本地阈值 - FailoverLocal = 0, - /// 降级成直接通过 - FailoverPass = 1, - } - impl FailoverType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - FailoverType::FailoverLocal => "FAILOVER_LOCAL", - FailoverType::FailoverPass => "FAILOVER_PASS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "FAILOVER_LOCAL" => Some(Self::FailoverLocal), - "FAILOVER_PASS" => Some(Self::FailoverPass), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MatchArgument { - #[prost(enumeration = "match_argument::Type", tag = "1")] - pub r#type: i32, - /// header key or query key - #[prost(string, tag = "2")] - pub key: ::prost::alloc::string::String, - /// header value or query value - #[prost(message, optional, tag = "3")] - pub value: ::core::option::Option, -} -/// Nested message and enum types in `MatchArgument`. -pub mod match_argument { - /// label type for gateway request - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Type { - /// custom arguments - Custom = 0, - /// method, match the http post/get/put/delete or grpc method - Method = 1, - /// header, match the http header, dubbo attachment, grpc header - Header = 2, - /// query, match the http query, dubbo argument - Query = 3, - /// caller service - CallerService = 4, - /// caller host ip - CallerIp = 5, - } - impl Type { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Type::Custom => "CUSTOM", - Type::Method => "METHOD", - Type::Header => "HEADER", - Type::Query => "QUERY", - Type::CallerService => "CALLER_SERVICE", - Type::CallerIp => "CALLER_IP", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CUSTOM" => Some(Self::Custom), - "METHOD" => Some(Self::Method), - "HEADER" => Some(Self::Header), - "QUERY" => Some(Self::Query), - "CALLER_SERVICE" => Some(Self::CallerService), - "CALLER_IP" => Some(Self::CallerIp), - _ => None, - } - } - } -} -/// 分布式限流服务集群 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RateLimitCluster { - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - /// 限流规则所属命名空间 - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, -} -/// 限流配额 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Amount { - /// 时间周期内的最大配额数 - #[prost(message, optional, tag = "1")] - pub max_amount: ::core::option::Option, - /// 配额生效的时间周期,必须大于等于1s - #[prost(message, optional, tag = "2")] - pub valid_duration: ::core::option::Option<::prost_types::Duration>, - /// 请求统计精度 - #[prost(message, optional, tag = "3")] - pub precision: ::core::option::Option, - /// 可选,起始限流阈值,爬坡起始值 - #[prost(message, optional, tag = "4")] - pub start_amount: ::core::option::Option, - /// 可选,最小限流阈值,降低时最小值 - #[prost(message, optional, tag = "5")] - pub min_amount: ::core::option::Option, -} -/// 限流上报方式 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Report { - /// 配额固定上报周期,单位毫秒 - #[prost(message, optional, tag = "1")] - pub interval: ::core::option::Option<::prost_types::Duration>, - /// 使用了百分之多少配额后启动一次实时上报,值范围(0,100] - #[prost(message, optional, tag = "2")] - pub amount_percent: ::core::option::Option, -} -/// 配额调整算法 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AmountAdjuster { - #[prost(message, optional, tag = "1")] - pub climb: ::core::option::Option, -} -/// 限流调整算法Climb相关配置 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ClimbConfig { - /// 是否开启 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 限流数据统计配置 - #[prost(message, optional, tag = "2")] - pub metric: ::core::option::Option, - /// 触发调整策略 - #[prost(message, optional, tag = "3")] - pub policy: ::core::option::Option, - /// 限流调整相关参数 - #[prost(message, optional, tag = "4")] - pub throttling: ::core::option::Option, -} -/// Nested message and enum types in `ClimbConfig`. -pub mod climb_config { - /// 限流数据统计配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct MetricConfig { - /// 限流数据度量周期,默认60s - #[prost(message, optional, tag = "1")] - pub window: ::core::option::Option<::prost_types::Duration>, - /// 数据统计精度,决定数据度量的最小周期,度量滑窗的步长=window/precision - #[prost(message, optional, tag = "2")] - pub precision: ::core::option::Option, - /// 上报周期,默认20s - #[prost(message, optional, tag = "3")] - pub report_interval: ::core::option::Option<::prost_types::Duration>, - } - /// 触发调整的策略 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct TriggerPolicy { - /// 按错误率阈值调整 - #[prost(message, optional, tag = "1")] - pub error_rate: ::core::option::Option, - /// 慢调用进行触发调整 - #[prost(message, optional, tag = "2")] - pub slow_rate: ::core::option::Option, - } - /// Nested message and enum types in `TriggerPolicy`. - pub mod trigger_policy { - /// 错误率触发调整配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ErrorRate { - /// 是否开启 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 触发限流调整的最小的请求数 - #[prost(message, optional, tag = "2")] - pub request_volume_threshold: ::core::option::Option, - /// 触发限流的错误率配置 - #[prost(message, optional, tag = "3")] - pub error_rate: ::core::option::Option, - /// 针对部分错误码,使用额外的错误率统计,可设置多组特殊规则 - #[prost(message, repeated, tag = "4")] - pub specials: ::prost::alloc::vec::Vec, - } - /// Nested message and enum types in `ErrorRate`. - pub mod error_rate { - /// 特殊错误码触发调整配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct SpecialConfig { - /// 自定义错误类型 - #[prost(message, optional, tag = "1")] - pub r#type: ::core::option::Option<::prost::alloc::string::String>, - /// 特定规则针对的错误码 - #[prost(message, repeated, tag = "2")] - pub error_codes: ::prost::alloc::vec::Vec, - /// 特定规则错误率 - #[prost(message, optional, tag = "3")] - pub error_rate: ::core::option::Option, - } - } - /// 慢调用触发调整配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct SlowRate { - /// 是否开启 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 最大响应时间,超过该响应时间属于慢调用 - #[prost(message, optional, tag = "2")] - pub max_rt: ::core::option::Option<::prost_types::Duration>, - /// 慢请求率阈值,达到该阈值进行限流 - #[prost(message, optional, tag = "3")] - pub slow_rate: ::core::option::Option, - } - } - /// 爬坡调整相关参数 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ClimbThrottling { - /// 冷水位以下区间的下调百分比 - #[prost(message, optional, tag = "1")] - pub cold_below_tune_down_rate: ::core::option::Option, - /// 冷水位以下区间的上调百分比 - #[prost(message, optional, tag = "2")] - pub cold_below_tune_up_rate: ::core::option::Option, - /// 冷水位以上区间的下调百分比 - #[prost(message, optional, tag = "3")] - pub cold_above_tune_down_rate: ::core::option::Option, - /// 冷水位以上区间的上调百分比 - #[prost(message, optional, tag = "4")] - pub cold_above_tune_up_rate: ::core::option::Option, - /// 冷水位以上,超过该百分的请求被限流后进行阈值上调 - #[prost(message, optional, tag = "5")] - pub limit_threshold_to_tune_up: ::core::option::Option, - /// 阈值调整规则的决策间隔 - #[prost(message, optional, tag = "6")] - pub judge_duration: ::core::option::Option<::prost_types::Duration>, - /// 阈值上调周期数,连续N个决策间隔都为上调,才执行上调 - #[prost(message, optional, tag = "7")] - pub tune_up_period: ::core::option::Option, - /// 阈值下调周期数,连续N个决策间隔都为下调,才执行下调 - #[prost(message, optional, tag = "8")] - pub tune_down_period: ::core::option::Option, - } -} -/// 单个熔断规则定义 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CircuitBreaker { - /// deprecated - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - /// 规则版本 - /// deprecated - #[prost(message, optional, tag = "2")] - pub version: ::core::option::Option<::prost::alloc::string::String>, - /// 规则名 - /// deprecated - #[prost(message, optional, tag = "3")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - /// 规则命名空间 - /// deprecated - #[prost(message, optional, tag = "4")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 规则所属服务 - #[prost(message, optional, tag = "5")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub service_namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 熔断规则可以分为被调规则和主调规则 - /// 被调规则针对所有的指定主调生效,假如不指定则对所有的主调生效 - /// 主调规则为当前主调方的规则,假如不指定则针对所有被调生效 - /// deprecated - #[prost(message, repeated, tag = "7")] - pub inbounds: ::prost::alloc::vec::Vec, - /// deprecated - #[prost(message, repeated, tag = "8")] - pub outbounds: ::prost::alloc::vec::Vec, - /// deprecated - #[prost(message, optional, tag = "9")] - pub token: ::core::option::Option<::prost::alloc::string::String>, - /// deprecated - #[prost(message, optional, tag = "10")] - pub owners: ::core::option::Option<::prost::alloc::string::String>, - /// 业务 - /// deprecated - #[prost(message, optional, tag = "11")] - pub business: ::core::option::Option<::prost::alloc::string::String>, - /// 部门 - /// deprecated - #[prost(message, optional, tag = "12")] - pub department: ::core::option::Option<::prost::alloc::string::String>, - /// 规则描述 - /// deprecated - #[prost(message, optional, tag = "13")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - /// deprecated - #[prost(message, optional, tag = "14")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - /// deprecated - #[prost(message, optional, tag = "15")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "16")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - /// circuitbreaker rules for current service - #[prost(message, repeated, tag = "21")] - pub rules: ::prost::alloc::vec::Vec, -} -/// 主调匹配规则 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SourceMatcher { - /// 主调命名空间以及服务名,可以为*,代表全匹配 - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 可选,主调业务标签,用于匹配是否使用该熔断规则,可放置用户的接口信息等 - #[prost(map = "string, message", tag = "3")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, -} -/// 熔断恢复配置 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RecoverConfig { - /// 触发熔断后到半开状态之间的等待间隔 - #[prost(message, optional, tag = "1")] - pub sleep_window: ::core::option::Option<::prost_types::Duration>, - /// 半开后,最多重试多少次恢复 - #[prost(message, optional, tag = "2")] - pub max_retry_after_half_open: ::core::option::Option, - /// 半开后放量的最大百分比 - #[prost(message, repeated, tag = "3")] - pub request_rate_after_half_open: ::prost::alloc::vec::Vec, - /// 熔断器半开到关闭所必须的最少成功率,默认100% - #[prost(message, optional, tag = "4")] - pub success_rate_to_close: ::core::option::Option, - /// 半开后最大放量数(用户不配置最大百分比时默认使用该配置) - #[prost(message, optional, tag = "5")] - pub request_count_after_half_open: ::core::option::Option, - #[prost(enumeration = "recover_config::OutlierDetectWhen", tag = "6")] - pub outlier_detect_when: i32, -} -/// Nested message and enum types in `RecoverConfig`. -pub mod recover_config { - /// 主动探测配置 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum OutlierDetectWhen { - /// 不开启监控探测 - Never = 0, - /// 只有在熔断恢复时才开启健康探测 - OnRecover = 1, - /// 一直开启健康探测 - Always = 2, - } - impl OutlierDetectWhen { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - OutlierDetectWhen::Never => "NEVER", - OutlierDetectWhen::OnRecover => "ON_RECOVER", - OutlierDetectWhen::Always => "ALWAYS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "NEVER" => Some(Self::Never), - "ON_RECOVER" => Some(Self::OnRecover), - "ALWAYS" => Some(Self::Always), - _ => None, - } - } - } -} -/// 熔断策略 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CbPolicy { - #[prost(message, optional, tag = "1")] - pub error_rate: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub slow_rate: ::core::option::Option, - /// 熔断的决策周期,多久触发一次熔断决策 - #[prost(message, optional, tag = "3")] - pub judge_duration: ::core::option::Option<::prost_types::Duration>, - /// 最大熔断比例,超过多少比例后不会继续熔断 - #[prost(message, optional, tag = "4")] - pub max_ejection_percent: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub consecutive: ::core::option::Option, -} -/// Nested message and enum types in `CbPolicy`. -pub mod cb_policy { - /// 错误率熔断配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ErrRateConfig { - /// 是否启用错误率配置 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 触发错误率熔断的最低请求阈值 - #[prost(message, optional, tag = "2")] - pub request_volume_threshold: ::core::option::Option, - /// 可选。触发保持状态的错误率阈值,假如不配置,则默认不会进入Preserved状态 - #[prost(message, optional, tag = "3")] - pub error_rate_to_preserved: ::core::option::Option, - /// 触发熔断的错误率阈值 - #[prost(message, optional, tag = "4")] - pub error_rate_to_open: ::core::option::Option, - #[prost(message, repeated, tag = "5")] - pub specials: ::prost::alloc::vec::Vec, - } - /// Nested message and enum types in `ErrRateConfig`. - pub mod err_rate_config { - /// 错误码相关特定配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct SpecialConfig { - /// 熔断关心的错误类型,用户可以自己定义 - #[prost(message, optional, tag = "1")] - pub r#type: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub error_codes: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "3")] - pub error_rate_to_preserved: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub error_rate_to_open: ::core::option::Option, - } - } - /// 慢调用率熔断策略配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct SlowRateConfig { - /// 是否启用慢调用率配置 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 最大响应时间,超过该时间属于慢调用请求 - #[prost(message, optional, tag = "2")] - pub max_rt: ::core::option::Option<::prost_types::Duration>, - /// 可选。触发保持状态的超时率阈值,假如不配置,则默认不会进入Preserved状态 - #[prost(message, optional, tag = "3")] - pub slow_rate_to_preserved: ::core::option::Option, - /// 触发熔断的超时率阈值 - #[prost(message, optional, tag = "4")] - pub slow_rate_to_open: ::core::option::Option, - } - /// 连续错误数熔断配置 - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ConsecutiveErrConfig { - /// 是否启用连续错误数配置 - #[prost(message, optional, tag = "1")] - pub enable: ::core::option::Option, - /// 连续错误数阈值,进入Preserved状态 - #[prost(message, optional, tag = "2")] - pub consecutive_error_to_preserved: ::core::option::Option, - /// 连续错误数阈值,进入Open状态 - #[prost(message, optional, tag = "3")] - pub consecutive_error_to_open: ::core::option::Option, - } -} -/// 目标set的规则 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DestinationSet { - /// 被调命名空间以及服务名,可以为*,代表全匹配 - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - /// 可选,SUBSET标识 - #[prost(map = "string, message", tag = "3")] - pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, - #[prost(enumeration = "destination_set::Resource", tag = "4")] - pub resource: i32, - #[prost(enumeration = "destination_set::Type", tag = "5")] - pub r#type: i32, - #[prost(enumeration = "destination_set::Scope", tag = "6")] - pub scope: i32, - /// 熔断数据度量周期 - /// 所有的阈值指标按此周期进行统计 - #[prost(message, optional, tag = "7")] - pub metric_window: ::core::option::Option<::prost_types::Duration>, - /// 熔断数据统计精度,决定数据度量的最小周期 - /// 度量滑窗的步长=window/precision - #[prost(message, optional, tag = "8")] - pub metric_precision: ::core::option::Option, - /// 熔断数据上报周期,对分布式熔断有效 - #[prost(message, optional, tag = "9")] - pub update_interval: ::core::option::Option<::prost_types::Duration>, - /// 触发熔断后恢复配置 - #[prost(message, optional, tag = "10")] - pub recover: ::core::option::Option, - /// 熔断策略 - #[prost(message, optional, tag = "11")] - pub policy: ::core::option::Option, - /// 被调的接口信息,指定哪些接口会使用该规则 - #[prost(message, optional, tag = "12")] - pub method: ::core::option::Option, - /// 返回码,指定哪些返回码会使用该规则 - #[prost(message, repeated, tag = "13")] - pub error_codes: ::prost::alloc::vec::Vec, -} -/// Nested message and enum types in `DestinationSet`. -pub mod destination_set { - /// 需要进行熔断的资源 - /// 支持SUBSET(子集群),以及INSTANCE(单个实例),默认为SUBSET - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Resource { - /// 针对实例分组进行熔断 - Subset = 0, - /// 针对实例进行熔断 - Instance = 1, - } - impl Resource { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Resource::Subset => "SUBSET", - Resource::Instance => "INSTANCE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "SUBSET" => Some(Self::Subset), - "INSTANCE" => Some(Self::Instance), - _ => None, - } - } - } - /// 熔断决策类型,支持GLOBAL(分布式决策)以及LOCAL(本地决策),默认GLOBAL - /// 当指定为GLOBAL时,则会定期上报统计数据并根据汇总数据进行熔断决策 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Type { - Global = 0, - Local = 1, - } - impl Type { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Type::Global => "GLOBAL", - Type::Local => "LOCAL", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "GLOBAL" => Some(Self::Global), - "LOCAL" => Some(Self::Local), - _ => None, - } - } - } - /// 熔断范围,是否扩散针对相同服务下所有接口进行熔断 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Scope { - /// 触发熔断条件,扩散熔断所有接口 - All = 0, - /// 触发熔断条件,只熔断当前接口 - Current = 1, - } - impl Scope { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Scope::All => "ALL", - Scope::Current => "CURRENT", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "ALL" => Some(Self::All), - "CURRENT" => Some(Self::Current), - _ => None, - } - } - } -} -/// 具体熔断规则 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CbRule { - /// 如果匹配Source规则,按照Destination进行熔断 - /// 多个Source之间的关系为或 - #[prost(message, repeated, tag = "1")] - pub sources: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub destinations: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RuleMatcher { - #[prost(message, optional, tag = "1")] - pub source: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub destination: ::core::option::Option, -} -/// Nested message and enum types in `RuleMatcher`. -pub mod rule_matcher { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct SourceService { - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - } - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct DestinationService { - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub method: ::core::option::Option, - } -} -/// new specific rule for circuitbreaker config -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CircuitBreakerRule { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// rule name - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// namespace of rule - #[prost(string, tag = "3")] - pub namespace: ::prost::alloc::string::String, - /// enable this router - #[prost(bool, tag = "4")] - pub enable: bool, - /// revision routing version - #[prost(string, tag = "5")] - pub revision: ::prost::alloc::string::String, - /// ctime create time of the rules - #[prost(string, tag = "6")] - pub ctime: ::prost::alloc::string::String, - /// mtime modify time of the rules - #[prost(string, tag = "7")] - pub mtime: ::prost::alloc::string::String, - /// etime enable time of the rules - #[prost(string, tag = "8")] - pub etime: ::prost::alloc::string::String, - /// description simple description rules - #[prost(string, tag = "9")] - pub description: ::prost::alloc::string::String, - /// the circuitbreaking level - #[prost(enumeration = "Level", tag = "21")] - pub level: i32, - /// match condition for this rule - #[prost(message, optional, tag = "22")] - pub rule_matcher: ::core::option::Option, - /// error conditions to judge an invocation as an error - #[prost(message, repeated, tag = "23")] - pub error_conditions: ::prost::alloc::vec::Vec, - /// trigger condition to trigger circuitbreaking - #[prost(message, repeated, tag = "24")] - pub trigger_condition: ::prost::alloc::vec::Vec, - /// the maximum % of an upstream cluster that can be ejected - #[prost(uint32, tag = "25")] - pub max_ejection_percent: u32, - /// recover condition to make resource open to close - #[prost(message, optional, tag = "26")] - pub recover_condition: ::core::option::Option, - /// fault detection enable config - #[prost(message, optional, tag = "27")] - pub fault_detect_config: ::core::option::Option, - /// fall back configuration - #[prost(message, optional, tag = "28")] - pub fallback_config: ::core::option::Option, -} -/// the condition to judge an input invocation as an error -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ErrorCondition { - #[prost(enumeration = "error_condition::InputType", tag = "1")] - pub input_type: i32, - #[prost(message, optional, tag = "2")] - pub condition: ::core::option::Option, -} -/// Nested message and enum types in `ErrorCondition`. -pub mod error_condition { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum InputType { - Unknown = 0, - RetCode = 1, - Delay = 2, - } - impl InputType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - InputType::Unknown => "UNKNOWN", - InputType::RetCode => "RET_CODE", - InputType::Delay => "DELAY", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "RET_CODE" => Some(Self::RetCode), - "DELAY" => Some(Self::Delay), - _ => None, - } - } - } -} -/// the error condition to trigger circuitbreaking -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TriggerCondition { - #[prost(enumeration = "trigger_condition::TriggerType", tag = "1")] - pub trigger_type: i32, - #[prost(uint32, tag = "2")] - pub error_count: u32, - #[prost(uint32, tag = "3")] - pub error_percent: u32, - #[prost(uint32, tag = "4")] - pub interval: u32, - #[prost(uint32, tag = "5")] - pub minimum_request: u32, -} -/// Nested message and enum types in `TriggerCondition`. -pub mod trigger_condition { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum TriggerType { - Unknown = 0, - ErrorRate = 1, - ConsecutiveError = 2, - } - impl TriggerType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - TriggerType::Unknown => "UNKNOWN", - TriggerType::ErrorRate => "ERROR_RATE", - TriggerType::ConsecutiveError => "CONSECUTIVE_ERROR", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "ERROR_RATE" => Some(Self::ErrorRate), - "CONSECUTIVE_ERROR" => Some(Self::ConsecutiveError), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RecoverCondition { - /// seconds from open to half-open - #[prost(uint32, tag = "1")] - pub sleep_window: u32, - /// consecutive success request to recover - #[prost(uint32, tag = "2")] - pub consecutive_success: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FaultDetectConfig { - #[prost(bool, tag = "1")] - pub enable: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FallbackConfig { - #[prost(bool, tag = "1")] - pub enable: bool, - #[prost(message, optional, tag = "2")] - pub response: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FallbackResponse { - #[prost(int32, tag = "1")] - pub code: i32, - #[prost(message, repeated, tag = "2")] - pub headers: ::prost::alloc::vec::Vec, - #[prost(string, tag = "3")] - pub body: ::prost::alloc::string::String, -} -/// Nested message and enum types in `FallbackResponse`. -pub mod fallback_response { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct MessageHeader { - #[prost(string, tag = "1")] - pub key: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub value: ::prost::alloc::string::String, - } -} -/// circuitbreaking level -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum Level { - Unknown = 0, - /// service level circuitbreaking - Service = 1, - /// method level circuitbreaking - Method = 2, - /// group level circuitbreaking - Group = 3, - /// instance level circuitbreaking - Instance = 4, -} -impl Level { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Level::Unknown => "UNKNOWN", - Level::Service => "SERVICE", - Level::Method => "METHOD", - Level::Group => "GROUP", - Level::Instance => "INSTANCE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "SERVICE" => Some(Self::Service), - "METHOD" => Some(Self::Method), - "GROUP" => Some(Self::Group), - "INSTANCE" => Some(Self::Instance), - _ => None, - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigRelease { - #[prost(message, optional, tag = "1")] - pub service: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub circuit_breaker: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigWithService { - #[prost(message, repeated, tag = "1")] - pub services: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "2")] - pub circuit_breaker: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FaultDetector { - /// fault detect rules for current service - #[prost(message, repeated, tag = "1")] - pub rules: ::prost::alloc::vec::Vec, - /// total revision for the fault detect rules - #[prost(string, tag = "2")] - pub revision: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FaultDetectRule { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// rule name - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// namespace of rule - #[prost(string, tag = "3")] - pub namespace: ::prost::alloc::string::String, - /// revision routing version - #[prost(string, tag = "4")] - pub revision: ::prost::alloc::string::String, - /// ctime create time of the rules - #[prost(string, tag = "5")] - pub ctime: ::prost::alloc::string::String, - /// mtime modify time of the rules - #[prost(string, tag = "6")] - pub mtime: ::prost::alloc::string::String, - /// description simple description rules - #[prost(string, tag = "7")] - pub description: ::prost::alloc::string::String, - /// detect target - #[prost(message, optional, tag = "21")] - pub target_service: ::core::option::Option, - /// detect interval - #[prost(uint32, tag = "22")] - pub interval: u32, - /// detect timeout - #[prost(uint32, tag = "23")] - pub timeout: u32, - /// detect port - #[prost(uint32, tag = "24")] - pub port: u32, - #[prost(enumeration = "fault_detect_rule::Protocol", tag = "25")] - pub protocol: i32, - /// http detect config - #[prost(message, optional, tag = "26")] - pub http_config: ::core::option::Option, - /// tcp detect config - #[prost(message, optional, tag = "27")] - pub tcp_config: ::core::option::Option, - /// udp detect config - #[prost(message, optional, tag = "28")] - pub udp_config: ::core::option::Option, -} -/// Nested message and enum types in `FaultDetectRule`. -pub mod fault_detect_rule { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct DestinationService { - #[prost(string, tag = "1")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub namespace: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub method: ::core::option::Option, - } - /// detect protocol - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum Protocol { - Unknown = 0, - Http = 1, - Tcp = 2, - Udp = 3, - } - impl Protocol { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Protocol::Unknown => "UNKNOWN", - Protocol::Http => "HTTP", - Protocol::Tcp => "TCP", - Protocol::Udp => "UDP", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "HTTP" => Some(Self::Http), - "TCP" => Some(Self::Tcp), - "UDP" => Some(Self::Udp), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HttpProtocolConfig { - #[prost(string, tag = "1")] - pub method: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub url: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "3")] - pub headers: ::prost::alloc::vec::Vec, - #[prost(string, tag = "4")] - pub body: ::prost::alloc::string::String, -} -/// Nested message and enum types in `HttpProtocolConfig`. -pub mod http_protocol_config { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct MessageHeader { - #[prost(string, tag = "1")] - pub key: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub value: ::prost::alloc::string::String, - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TcpProtocolConfig { - #[prost(string, tag = "1")] - pub send: ::prost::alloc::string::String, - #[prost(string, repeated, tag = "2")] - pub receive: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UdpProtocolConfig { - #[prost(string, tag = "1")] - pub send: ::prost::alloc::string::String, - #[prost(string, repeated, tag = "2")] - pub receive: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LoginRequest { - #[prost(message, optional, tag = "1")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub password: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LoginResponse { - #[prost(message, optional, tag = "1")] - pub user_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub role: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub owner_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub token: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct User { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub password: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub source: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub auth_token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub token_enable: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "10")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub user_type: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub mobile: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "13")] - pub email: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModifyUserPassword { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub old_password: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub new_password: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UserGroupRelation { - #[prost(message, optional, tag = "1")] - pub group_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub users: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UserGroup { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub auth_token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub token_enable: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub relation: ::core::option::Option, - #[prost(message, optional, tag = "10")] - pub user_count: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModifyUserGroup { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub auth_token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub token_enable: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub add_relations: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub remove_relations: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Principal { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Principals { - #[prost(message, repeated, tag = "1")] - pub users: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "2")] - pub groups: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StrategyResourceEntry { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub name: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StrategyResources { - #[prost(message, optional, tag = "1")] - pub strategy_id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub namespaces: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "3")] - pub services: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub config_groups: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AuthStrategy { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub principals: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub resources: ::core::option::Option, - #[prost(enumeration = "AuthAction", tag = "5")] - pub action: i32, - #[prost(message, optional, tag = "6")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub ctime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub mtime: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "10")] - pub auth_token: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub default_strategy: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ModifyAuthStrategy { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub add_principals: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub remove_principals: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub add_resources: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub remove_resources: ::core::option::Option, - #[prost(enumeration = "AuthAction", tag = "7")] - pub action: i32, - #[prost(message, optional, tag = "8")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum AuthAction { - OnlyRead = 0, - ReadWrite = 1, -} -impl AuthAction { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - AuthAction::OnlyRead => "ONLY_READ", - AuthAction::ReadWrite => "READ_WRITE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "ONLY_READ" => Some(Self::OnlyRead), - "READ_WRITE" => Some(Self::ReadWrite), - _ => None, - } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ResourceType { - Namespaces = 0, - Services = 1, - ConfigGroups = 2, -} -impl ResourceType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ResourceType::Namespaces => "Namespaces", - ResourceType::Services => "Services", - ResourceType::ConfigGroups => "ConfigGroups", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "Namespaces" => Some(Self::Namespaces), - "Services" => Some(Self::Services), - "ConfigGroups" => Some(Self::ConfigGroups), - _ => None, - } - } -} -/// 流量入口 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TrafficEntry { - /// 标记流量入口类型 - /// type == "polarismesh.cn/gateway/spring-cloud-gateway", 则 selector 为 ServiceGatewaySelector - /// type == "polarismesh.cn/service, 则 selector 为 ServiceSelector - #[prost(string, tag = "1")] - pub r#type: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub selector: ::core::option::Option<::prost_types::Any>, -} -/// 微服务网关入口定义 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ServiceGatewaySelector { - #[prost(string, tag = "1")] - pub namespace: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub service: ::prost::alloc::string::String, - /// 决定要不要部份 - #[prost(map = "string, message", tag = "3")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, -} -/// 普通服务入口定义 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ServiceSelector { - #[prost(string, tag = "1")] - pub namespace: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub service: ::prost::alloc::string::String, - /// 决定要不要部份 - #[prost(map = "string, message", tag = "3")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, MatchString>, -} -/// 泳道组实体定义 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LaneGroup { - /// 泳道组 ID - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// 泳道组名称 - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// 泳道组内的流量入口信息 - #[prost(message, repeated, tag = "3")] - pub entries: ::prost::alloc::vec::Vec, - /// 在泳道组内的服务列表信息 - #[prost(message, repeated, tag = "4")] - pub destinations: ::prost::alloc::vec::Vec, - /// 泳道组描述信息 - #[prost(string, tag = "7")] - pub revision: ::prost::alloc::string::String, - /// 泳道组描述信息 - #[prost(string, tag = "8")] - pub description: ::prost::alloc::string::String, - /// 泳道组的创建时间 - #[prost(string, tag = "9")] - pub ctime: ::prost::alloc::string::String, - /// 泳道组的更新时间 - #[prost(string, tag = "10")] - pub mtime: ::prost::alloc::string::String, - /// 泳道组内的流量入口信息 - #[prost(message, repeated, tag = "11")] - pub rules: ::prost::alloc::vec::Vec, -} -/// TrafficMatchRule 流量匹配规则 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TrafficMatchRule { - /// 流量匹配规则,判断哪些流量需要进入泳道 - #[prost(message, repeated, tag = "4")] - pub arguments: ::prost::alloc::vec::Vec, - #[prost(enumeration = "traffic_match_rule::TrafficMatchMode", tag = "14")] - pub match_mode: i32, -} -/// Nested message and enum types in `TrafficMatchRule`. -pub mod traffic_match_rule { - /// 多个 SourceMatch 之间的判断关系 - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum TrafficMatchMode { - /// 与模式 - And = 0, - /// 或模式 - Or = 1, - } - impl TrafficMatchMode { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - TrafficMatchMode::And => "AND", - TrafficMatchMode::Or => "OR", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "AND" => Some(Self::And), - "OR" => Some(Self::Or), - _ => None, - } - } - } -} -/// 泳道规则 -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LaneRule { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub name: ::prost::alloc::string::String, - /// 所属泳道组的名称 - #[prost(string, tag = "3")] - pub group_name: ::prost::alloc::string::String, - /// 流量匹配规则 - #[prost(message, optional, tag = "4")] - pub traffic_match_rule: ::core::option::Option, - /// 保存这个泳道的默认实例标签 - #[prost(string, tag = "5")] - pub default_label_value: ::prost::alloc::string::String, - /// 泳道规则是否启用 - #[prost(bool, tag = "6")] - pub enable: bool, - #[prost(enumeration = "lane_rule::LaneMatchMode", tag = "7")] - pub match_mode: i32, - /// revision routing version - #[prost(string, tag = "8")] - pub revision: ::prost::alloc::string::String, - /// ctime create time of the rules - #[prost(string, tag = "9")] - pub ctime: ::prost::alloc::string::String, - /// mtime modify time of the rules - #[prost(string, tag = "10")] - pub mtime: ::prost::alloc::string::String, - /// etime enable time of the rules - #[prost(string, tag = "11")] - pub etime: ::prost::alloc::string::String, - /// priority rules priority - #[prost(uint32, tag = "12")] - pub priority: u32, - /// description simple description rules - #[prost(string, tag = "13")] - pub description: ::prost::alloc::string::String, -} -/// Nested message and enum types in `LaneRule`. -pub mod lane_rule { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum LaneMatchMode { - /// 严格匹配模式 - Strict = 0, - /// 宽松匹配模式 - Permissive = 1, - } - impl LaneMatchMode { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - LaneMatchMode::Strict => "STRICT", - LaneMatchMode::Permissive => "PERMISSIVE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "STRICT" => Some(Self::Strict), - "PERMISSIVE" => Some(Self::Permissive), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Response { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub client: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub namespace: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub service: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub instance: ::core::option::Option, - #[prost(message, optional, tag = "7")] - pub routing: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub alias: ::core::option::Option, - #[prost(message, optional, tag = "9")] - pub rate_limit: ::core::option::Option, - #[prost(message, optional, tag = "10")] - pub circuit_breaker: ::core::option::Option, - #[prost(message, optional, tag = "11")] - pub config_release: ::core::option::Option, - #[prost(message, optional, tag = "19")] - pub user: ::core::option::Option, - #[prost(message, optional, tag = "20")] - pub user_group: ::core::option::Option, - #[prost(message, optional, tag = "21")] - pub auth_strategy: ::core::option::Option, - #[prost(message, optional, tag = "22")] - pub relation: ::core::option::Option, - #[prost(message, optional, tag = "23")] - pub login_response: ::core::option::Option, - #[prost(message, optional, tag = "24")] - pub modify_auth_strategy: ::core::option::Option, - #[prost(message, optional, tag = "25")] - pub modify_user_group: ::core::option::Option, - #[prost(message, optional, tag = "26")] - pub resources: ::core::option::Option, - #[prost(message, optional, tag = "27")] - pub option_switch: ::core::option::Option, - #[prost(message, optional, tag = "28")] - pub instance_labels: ::core::option::Option, - #[prost(message, optional, tag = "29")] - pub data: ::core::option::Option<::prost_types::Any>, - #[prost(message, optional, tag = "30")] - pub service_contract: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BatchWriteResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub size: ::core::option::Option, - #[prost(message, repeated, tag = "4")] - pub responses: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BatchQueryResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub amount: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub size: ::core::option::Option, - #[prost(message, repeated, tag = "5")] - pub namespaces: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "6")] - pub services: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "7")] - pub instances: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "8")] - pub routings: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "9")] - pub aliases: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "10")] - pub rate_limits: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "11")] - pub config_with_services: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "18")] - pub users: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "19")] - pub user_groups: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "20")] - pub auth_strategies: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "21")] - pub clients: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "22")] - pub data: ::prost::alloc::vec::Vec<::prost_types::Any>, - #[prost(message, optional, tag = "23")] - pub summary: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DiscoverResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(enumeration = "discover_response::DiscoverResponseType", tag = "3")] - pub r#type: i32, - #[prost(message, optional, tag = "4")] - pub service: ::core::option::Option, - #[prost(message, repeated, tag = "5")] - pub instances: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "6")] - pub routing: ::core::option::Option, - #[prost(message, optional, tag = "7")] - pub rate_limit: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub circuit_breaker: ::core::option::Option, - #[prost(message, repeated, tag = "9")] - pub services: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "10")] - pub namespaces: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "11")] - pub fault_detector: ::core::option::Option, - #[prost(message, optional, tag = "21")] - pub alias_for: ::core::option::Option, - #[prost(message, repeated, tag = "22")] - pub lanes: ::prost::alloc::vec::Vec, -} -/// Nested message and enum types in `DiscoverResponse`. -pub mod discover_response { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum DiscoverResponseType { - Unknown = 0, - Instance = 1, - Cluster = 2, - Routing = 3, - RateLimit = 4, - CircuitBreaker = 5, - Services = 6, - Namespaces = 12, - FaultDetector = 13, - Lane = 100, - } - impl DiscoverResponseType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - DiscoverResponseType::Unknown => "UNKNOWN", - DiscoverResponseType::Instance => "INSTANCE", - DiscoverResponseType::Cluster => "CLUSTER", - DiscoverResponseType::Routing => "ROUTING", - DiscoverResponseType::RateLimit => "RATE_LIMIT", - DiscoverResponseType::CircuitBreaker => "CIRCUIT_BREAKER", - DiscoverResponseType::Services => "SERVICES", - DiscoverResponseType::Namespaces => "NAMESPACES", - DiscoverResponseType::FaultDetector => "FAULT_DETECTOR", - DiscoverResponseType::Lane => "LANE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "INSTANCE" => Some(Self::Instance), - "CLUSTER" => Some(Self::Cluster), - "ROUTING" => Some(Self::Routing), - "RATE_LIMIT" => Some(Self::RateLimit), - "CIRCUIT_BREAKER" => Some(Self::CircuitBreaker), - "SERVICES" => Some(Self::Services), - "NAMESPACES" => Some(Self::Namespaces), - "FAULT_DETECTOR" => Some(Self::FaultDetector), - "LANE" => Some(Self::Lane), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OptionSwitch { - #[prost(map = "string, string", tag = "1")] - pub options: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InstanceLabels { - #[prost(map = "string, message", tag = "1")] - pub labels: ::std::collections::HashMap<::prost::alloc::string::String, StringList>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HeartbeatRecord { - #[prost(string, tag = "1")] - pub instance_id: ::prost::alloc::string::String, - #[prost(int64, tag = "6")] - pub last_heartbeat_sec: i64, - #[prost(bool, tag = "7")] - pub exist: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InstanceHeartbeat { - #[prost(string, tag = "1")] - pub instance_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub service: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub namespace: ::prost::alloc::string::String, - #[prost(string, tag = "4")] - pub host: ::prost::alloc::string::String, - #[prost(uint32, tag = "5")] - pub port: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HeartbeatsRequest { - #[prost(message, repeated, tag = "1")] - pub heartbeats: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HeartbeatsResponse {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetHeartbeatsRequest { - #[prost(string, repeated, tag = "1")] - pub instance_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetHeartbeatsResponse { - #[prost(message, repeated, tag = "1")] - pub records: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DelHeartbeatsRequest { - #[prost(string, repeated, tag = "1")] - pub instance_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DelHeartbeatsResponse { - #[prost(uint32, tag = "1")] - pub code: u32, - #[prost(string, tag = "2")] - pub info: ::prost::alloc::string::String, -} -/// Generated client implementations. -pub mod polaris_grpc_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct PolarisGrpcClient { - inner: tonic::client::Grpc, - } - impl PolarisGrpcClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl PolarisGrpcClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> PolarisGrpcClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - PolarisGrpcClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// 客户端上报 - pub async fn report_client( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisGRPC/ReportClient"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisGRPC", "ReportClient")); - self.inner.unary(req, path, codec).await - } - /// 被调方注册服务实例 - pub async fn register_instance( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisGRPC/RegisterInstance"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisGRPC", "RegisterInstance")); - self.inner.unary(req, path, codec).await - } - /// 被调方反注册服务实例 - pub async fn deregister_instance( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisGRPC/DeregisterInstance"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisGRPC", "DeregisterInstance")); - self.inner.unary(req, path, codec).await - } - /// 统一发现接口 - pub async fn discover( - &mut self, - request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisGRPC/Discover"); - let mut req = request.into_streaming_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisGRPC", "Discover")); - self.inner.streaming(req, path, codec).await - } - /// 被调方上报心跳 - pub async fn heartbeat( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisGRPC/Heartbeat"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisGRPC", "Heartbeat")); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated client implementations. -pub mod polaris_heartbeat_grpc_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct PolarisHeartbeatGrpcClient { - inner: tonic::client::Grpc, - } - impl PolarisHeartbeatGrpcClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl PolarisHeartbeatGrpcClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> PolarisHeartbeatGrpcClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - PolarisHeartbeatGrpcClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// 被调方批量上报心跳 - pub async fn batch_heartbeat( - &mut self, - request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisHeartbeatGRPC/BatchHeartbeat"); - let mut req = request.into_streaming_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisHeartbeatGRPC", "BatchHeartbeat")); - self.inner.streaming(req, path, codec).await - } - /// 批量获取心跳记录 - pub async fn batch_get_heartbeat( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisHeartbeatGRPC/BatchGetHeartbeat"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisHeartbeatGRPC", - "BatchGetHeartbeat", - )); - self.inner.unary(req, path, codec).await - } - /// 批量删除心跳记录 - pub async fn batch_del_heartbeat( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisHeartbeatGRPC/BatchDelHeartbeat"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisHeartbeatGRPC", - "BatchDelHeartbeat", - )); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated client implementations. -pub mod polaris_service_contract_grpc_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct PolarisServiceContractGrpcClient { - inner: tonic::client::Grpc, - } - impl PolarisServiceContractGrpcClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl PolarisServiceContractGrpcClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> PolarisServiceContractGrpcClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - PolarisServiceContractGrpcClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// 上报服务契约 - pub async fn report_service_contract( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/v1.PolarisServiceContractGRPC/ReportServiceContract", - ); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisServiceContractGRPC", - "ReportServiceContract", - )); - self.inner.unary(req, path, codec).await - } - /// 查询服务契约 - pub async fn get_service_contract( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/v1.PolarisServiceContractGRPC/GetServiceContract", - ); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisServiceContractGRPC", - "GetServiceContract", - )); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated server implementations. -pub mod polaris_grpc_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PolarisGrpcServer. - #[async_trait] - pub trait PolarisGrpc: Send + Sync + 'static { - /// 客户端上报 - async fn report_client( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 被调方注册服务实例 - async fn register_instance( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 被调方反注册服务实例 - async fn deregister_instance( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Server streaming response type for the Discover method. - type DiscoverStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + Send - + 'static; - /// 统一发现接口 - async fn discover( - &self, - request: tonic::Request>, - ) -> std::result::Result, tonic::Status>; - /// 被调方上报心跳 - async fn heartbeat( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct PolarisGrpcServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl PolarisGrpcServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for PolarisGrpcServer - where - T: PolarisGrpc, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - "/v1.PolarisGRPC/ReportClient" => { - #[allow(non_camel_case_types)] - struct ReportClientSvc(pub Arc); - impl tonic::server::UnaryService for ReportClientSvc { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::report_client(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = ReportClientSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisGRPC/RegisterInstance" => { - #[allow(non_camel_case_types)] - struct RegisterInstanceSvc(pub Arc); - impl tonic::server::UnaryService for RegisterInstanceSvc { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::register_instance(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = RegisterInstanceSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisGRPC/DeregisterInstance" => { - #[allow(non_camel_case_types)] - struct DeregisterInstanceSvc(pub Arc); - impl tonic::server::UnaryService for DeregisterInstanceSvc { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::deregister_instance(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = DeregisterInstanceSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisGRPC/Discover" => { - #[allow(non_camel_case_types)] - struct DiscoverSvc(pub Arc); - impl tonic::server::StreamingService for DiscoverSvc { - type Response = super::DiscoverResponse; - type ResponseStream = T::DiscoverStream; - type Future = - BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request>, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = - async move { ::discover(&inner, request).await }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = DiscoverSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.streaming(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisGRPC/Heartbeat" => { - #[allow(non_camel_case_types)] - struct HeartbeatSvc(pub Arc); - impl tonic::server::UnaryService for HeartbeatSvc { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = - async move { ::heartbeat(&inner, request).await }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = HeartbeatSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => Box::pin(async move { - Ok(http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap()) - }), - } - } - } - impl Clone for PolarisGrpcServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService for PolarisGrpcServer { - const NAME: &'static str = "v1.PolarisGRPC"; - } -} -/// Generated server implementations. -pub mod polaris_heartbeat_grpc_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PolarisHeartbeatGrpcServer. - #[async_trait] - pub trait PolarisHeartbeatGrpc: Send + Sync + 'static { - /// Server streaming response type for the BatchHeartbeat method. - type BatchHeartbeatStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + Send - + 'static; - /// 被调方批量上报心跳 - async fn batch_heartbeat( - &self, - request: tonic::Request>, - ) -> std::result::Result, tonic::Status>; - /// 批量获取心跳记录 - async fn batch_get_heartbeat( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 批量删除心跳记录 - async fn batch_del_heartbeat( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct PolarisHeartbeatGrpcServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl PolarisHeartbeatGrpcServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for PolarisHeartbeatGrpcServer - where - T: PolarisHeartbeatGrpc, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - "/v1.PolarisHeartbeatGRPC/BatchHeartbeat" => { - #[allow(non_camel_case_types)] - struct BatchHeartbeatSvc(pub Arc); - impl - tonic::server::StreamingService - for BatchHeartbeatSvc - { - type Response = super::HeartbeatsResponse; - type ResponseStream = T::BatchHeartbeatStream; - type Future = - BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request>, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::batch_heartbeat(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = BatchHeartbeatSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.streaming(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisHeartbeatGRPC/BatchGetHeartbeat" => { - #[allow(non_camel_case_types)] - struct BatchGetHeartbeatSvc(pub Arc); - impl - tonic::server::UnaryService - for BatchGetHeartbeatSvc - { - type Response = super::GetHeartbeatsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::batch_get_heartbeat(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = BatchGetHeartbeatSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisHeartbeatGRPC/BatchDelHeartbeat" => { - #[allow(non_camel_case_types)] - struct BatchDelHeartbeatSvc(pub Arc); - impl - tonic::server::UnaryService - for BatchDelHeartbeatSvc - { - type Response = super::DelHeartbeatsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::batch_del_heartbeat(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = BatchDelHeartbeatSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => Box::pin(async move { - Ok(http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap()) - }), - } - } - } - impl Clone for PolarisHeartbeatGrpcServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService for PolarisHeartbeatGrpcServer { - const NAME: &'static str = "v1.PolarisHeartbeatGRPC"; - } -} -/// Generated server implementations. -pub mod polaris_service_contract_grpc_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PolarisServiceContractGrpcServer. - #[async_trait] - pub trait PolarisServiceContractGrpc: Send + Sync + 'static { - /// 上报服务契约 - async fn report_service_contract( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 查询服务契约 - async fn get_service_contract( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct PolarisServiceContractGrpcServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl PolarisServiceContractGrpcServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for PolarisServiceContractGrpcServer - where - T: PolarisServiceContractGrpc, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - "/v1.PolarisServiceContractGRPC/ReportServiceContract" => { - #[allow(non_camel_case_types)] - struct ReportServiceContractSvc(pub Arc); - impl - tonic::server::UnaryService - for ReportServiceContractSvc - { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::report_service_contract( - &inner, request, - ) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = ReportServiceContractSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisServiceContractGRPC/GetServiceContract" => { - #[allow(non_camel_case_types)] - struct GetServiceContractSvc(pub Arc); - impl - tonic::server::UnaryService - for GetServiceContractSvc - { - type Response = super::Response; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_service_contract( - &inner, request, - ) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = GetServiceContractSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => Box::pin(async move { - Ok(http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap()) - }), - } - } - } - impl Clone for PolarisServiceContractGrpcServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService - for PolarisServiceContractGrpcServer - { - const NAME: &'static str = "v1.PolarisServiceContractGRPC"; - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileGroup { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub create_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub modify_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub file_count: ::core::option::Option, - #[prost(message, repeated, tag = "10")] - pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "11")] - pub group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "13")] - pub remove_user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "14")] - pub remove_group_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub editable: ::core::option::Option, - #[prost(message, optional, tag = "16")] - pub owner: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "17")] - pub business: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "18")] - pub department: ::core::option::Option<::prost::alloc::string::String>, - #[prost(map = "string, string", tag = "19")] - pub metadata: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFile { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub group: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub format: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub status: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "9")] - pub tags: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "10")] - pub create_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub modify_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "13")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "14")] - pub release_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub release_by: ::core::option::Option<::prost::alloc::string::String>, - /// 是否为加密配置文件 - #[prost(message, optional, tag = "16")] - pub encrypted: ::core::option::Option, - /// 加密算法 - #[prost(message, optional, tag = "17")] - pub encrypt_algo: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileTag { - #[prost(message, optional, tag = "1")] - pub key: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub value: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileRelease { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub group: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub file_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub md5: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub version: ::core::option::Option, - #[prost(message, optional, tag = "10")] - pub create_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "12")] - pub modify_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "13")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "14")] - pub tags: ::prost::alloc::vec::Vec, - /// 当前生效配置 - #[prost(message, optional, tag = "15")] - pub active: ::core::option::Option, - #[prost(message, optional, tag = "16")] - pub format: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "17")] - pub release_description: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "18")] - pub release_type: ::core::option::Option<::prost::alloc::string::String>, - /// 配置灰度发布时需要匹配的客户端标签信息 - #[prost(message, repeated, tag = "19")] - pub beta_labels: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileReleaseHistory { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub group: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub file_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub format: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub md5: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "10")] - pub r#type: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub status: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "12")] - pub tags: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "13")] - pub create_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "14")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "15")] - pub modify_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "16")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, - /// 配置发布失败的原因 - #[prost(message, optional, tag = "17")] - pub reason: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "18")] - pub release_description: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileTemplate { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub format: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub create_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub modify_time: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "9")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ClientConfigFileInfo { - #[prost(message, optional, tag = "1")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub group: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub file_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub version: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub md5: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "7")] - pub tags: ::prost::alloc::vec::Vec, - /// 是否为加密配置文件 - #[prost(message, optional, tag = "8")] - pub encrypted: ::core::option::Option, - /// 公钥,用于加密数据密钥 - #[prost(message, optional, tag = "9")] - pub public_key: ::core::option::Option<::prost::alloc::string::String>, - /// 配置文件版本名称 - #[prost(message, optional, tag = "10")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - /// 配置文件的发布时间 - #[prost(message, optional, tag = "11")] - pub release_time: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ClientWatchConfigFileRequest { - #[prost(message, optional, tag = "1")] - pub client_ip: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub service_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "3")] - pub watch_files: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileExportRequest { - #[prost(message, optional, tag = "1")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub groups: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "3")] - pub names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFilePublishInfo { - #[prost(message, optional, tag = "1")] - pub release_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub namespace: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub group: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "4")] - pub file_name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "5")] - pub content: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "6")] - pub comment: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "7")] - pub format: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "8")] - pub release_description: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "11")] - pub create_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "13")] - pub modify_by: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "14")] - pub tags: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "15")] - pub md5: ::core::option::Option<::prost::alloc::string::String>, - /// 是否为加密配置文件 - #[prost(message, optional, tag = "16")] - pub encrypted: ::core::option::Option, - /// 加密算法 - #[prost(message, optional, tag = "17")] - pub encrypt_algo: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigFileGroupRequest { - #[prost(message, optional, tag = "1")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "2")] - pub config_file_group: ::core::option::Option, - /// 配置标签 - #[prost(map = "string, string", tag = "12")] - pub client_labels: - ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigDiscoverRequest { - #[prost( - enumeration = "config_discover_request::ConfigDiscoverRequestType", - tag = "1" - )] - pub r#type: i32, - #[prost(message, optional, tag = "2")] - pub config_file: ::core::option::Option, - #[prost(string, tag = "3")] - pub revision: ::prost::alloc::string::String, -} -/// Nested message and enum types in `ConfigDiscoverRequest`. -pub mod config_discover_request { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum ConfigDiscoverRequestType { - Unknown = 0, - ConfigFile = 1, - ConfigFileNames = 2, - ConfigFileGroups = 3, - } - impl ConfigDiscoverRequestType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ConfigDiscoverRequestType::Unknown => "UNKNOWN", - ConfigDiscoverRequestType::ConfigFile => "CONFIG_FILE", - ConfigDiscoverRequestType::ConfigFileNames => "CONFIG_FILE_Names", - ConfigDiscoverRequestType::ConfigFileGroups => "CONFIG_FILE_GROUPS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "CONFIG_FILE" => Some(Self::ConfigFile), - "CONFIG_FILE_Names" => Some(Self::ConfigFileNames), - "CONFIG_FILE_GROUPS" => Some(Self::ConfigFileGroups), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigDiscoverResponse { - #[prost(uint32, tag = "1")] - pub code: u32, - #[prost(string, tag = "2")] - pub info: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub revision: ::prost::alloc::string::String, - #[prost( - enumeration = "config_discover_response::ConfigDiscoverResponseType", - tag = "4" - )] - pub r#type: i32, - #[prost(message, optional, tag = "5")] - pub config_file: ::core::option::Option, - #[prost(message, repeated, tag = "6")] - pub config_file_names: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "7")] - pub config_file_groups: ::prost::alloc::vec::Vec, -} -/// Nested message and enum types in `ConfigDiscoverResponse`. -pub mod config_discover_response { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] - #[repr(i32)] - pub enum ConfigDiscoverResponseType { - Unknown = 0, - ConfigFile = 1, - ConfigFileNames = 2, - ConfigFileGroups = 3, - } - impl ConfigDiscoverResponseType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ConfigDiscoverResponseType::Unknown => "UNKNOWN", - ConfigDiscoverResponseType::ConfigFile => "CONFIG_FILE", - ConfigDiscoverResponseType::ConfigFileNames => "CONFIG_FILE_Names", - ConfigDiscoverResponseType::ConfigFileGroups => "CONFIG_FILE_GROUPS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN" => Some(Self::Unknown), - "CONFIG_FILE" => Some(Self::ConfigFile), - "CONFIG_FILE_Names" => Some(Self::ConfigFileNames), - "CONFIG_FILE_GROUPS" => Some(Self::ConfigFileGroups), - _ => None, - } - } - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigSimpleResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub config_file_group: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub config_file: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub config_file_release: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub config_file_release_history: ::core::option::Option, - #[prost(message, optional, tag = "7")] - pub config_file_template: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigBatchWriteResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub total: ::core::option::Option, - #[prost(message, repeated, tag = "4")] - pub responses: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigBatchQueryResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub total: ::core::option::Option, - #[prost(message, repeated, tag = "4")] - pub config_file_groups: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub config_files: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "6")] - pub config_file_releases: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "7")] - pub config_file_release_histories: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "8")] - pub config_file_templates: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigClientResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub config_file: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigImportResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "3")] - pub create_config_files: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub skip_config_files: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub overwrite_config_files: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigExportResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub data: ::core::option::Option<::prost::alloc::vec::Vec>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigEncryptAlgorithmResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "3")] - pub algorithms: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConfigClientListResponse { - #[prost(message, optional, tag = "1")] - pub code: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub info: ::core::option::Option<::prost::alloc::string::String>, - #[prost(message, optional, tag = "3")] - pub revision: ::core::option::Option<::prost::alloc::string::String>, - #[prost(string, tag = "4")] - pub namespace: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub group: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "6")] - pub config_file_infos: ::prost::alloc::vec::Vec, -} -/// Generated client implementations. -pub mod polaris_config_grpc_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct PolarisConfigGrpcClient { - inner: tonic::client::Grpc, - } - impl PolarisConfigGrpcClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl PolarisConfigGrpcClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> PolarisConfigGrpcClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + Send + Sync, - { - PolarisConfigGrpcClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// 拉取配置 - pub async fn get_config_file( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/GetConfigFile"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "GetConfigFile")); - self.inner.unary(req, path, codec).await - } - /// 创建配置 - pub async fn create_config_file( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/CreateConfigFile"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "CreateConfigFile")); - self.inner.unary(req, path, codec).await - } - /// 更新配置 - pub async fn update_config_file( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/UpdateConfigFile"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "UpdateConfigFile")); - self.inner.unary(req, path, codec).await - } - /// 发布配置 - pub async fn publish_config_file( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/PublishConfigFile"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "PublishConfigFile")); - self.inner.unary(req, path, codec).await - } - /// 发布配置 - pub async fn upsert_and_publish_config_file( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/v1.PolarisConfigGRPC/UpsertAndPublishConfigFile", - ); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisConfigGRPC", - "UpsertAndPublishConfigFile", - )); - self.inner.unary(req, path, codec).await - } - /// 订阅配置变更 - pub async fn watch_config_files( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/WatchConfigFiles"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "WatchConfigFiles")); - self.inner.unary(req, path, codec).await - } - /// 拉取指定配置分组下的配置文件列表 - pub async fn get_config_file_metadata_list( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/v1.PolarisConfigGRPC/GetConfigFileMetadataList", - ); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new( - "v1.PolarisConfigGRPC", - "GetConfigFileMetadataList", - )); - self.inner.unary(req, path, codec).await - } - /// 统一发现接口 - pub async fn discover( - &mut self, - request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/v1.PolarisConfigGRPC/Discover"); - let mut req = request.into_streaming_request(); - req.extensions_mut() - .insert(GrpcMethod::new("v1.PolarisConfigGRPC", "Discover")); - self.inner.streaming(req, path, codec).await - } - } -} -/// Generated server implementations. -pub mod polaris_config_grpc_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PolarisConfigGrpcServer. - #[async_trait] - pub trait PolarisConfigGrpc: Send + Sync + 'static { - /// 拉取配置 - async fn get_config_file( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 创建配置 - async fn create_config_file( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 更新配置 - async fn update_config_file( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 发布配置 - async fn publish_config_file( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 发布配置 - async fn upsert_and_publish_config_file( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 订阅配置变更 - async fn watch_config_files( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// 拉取指定配置分组下的配置文件列表 - async fn get_config_file_metadata_list( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Server streaming response type for the Discover method. - type DiscoverStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + Send - + 'static; - /// 统一发现接口 - async fn discover( - &self, - request: tonic::Request>, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct PolarisConfigGrpcServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl PolarisConfigGrpcServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for PolarisConfigGrpcServer - where - T: PolarisConfigGrpc, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - "/v1.PolarisConfigGRPC/GetConfigFile" => { - #[allow(non_camel_case_types)] - struct GetConfigFileSvc(pub Arc); - impl - tonic::server::UnaryService - for GetConfigFileSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_config_file(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = GetConfigFileSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/CreateConfigFile" => { - #[allow(non_camel_case_types)] - struct CreateConfigFileSvc(pub Arc); - impl tonic::server::UnaryService - for CreateConfigFileSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::create_config_file(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = CreateConfigFileSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/UpdateConfigFile" => { - #[allow(non_camel_case_types)] - struct UpdateConfigFileSvc(pub Arc); - impl tonic::server::UnaryService - for UpdateConfigFileSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::update_config_file(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = UpdateConfigFileSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/PublishConfigFile" => { - #[allow(non_camel_case_types)] - struct PublishConfigFileSvc(pub Arc); - impl tonic::server::UnaryService - for PublishConfigFileSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::publish_config_file(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = PublishConfigFileSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/UpsertAndPublishConfigFile" => { - #[allow(non_camel_case_types)] - struct UpsertAndPublishConfigFileSvc(pub Arc); - impl - tonic::server::UnaryService - for UpsertAndPublishConfigFileSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::upsert_and_publish_config_file( - &inner, request, - ) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = UpsertAndPublishConfigFileSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/WatchConfigFiles" => { - #[allow(non_camel_case_types)] - struct WatchConfigFilesSvc(pub Arc); - impl - tonic::server::UnaryService - for WatchConfigFilesSvc - { - type Response = super::ConfigClientResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::watch_config_files(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = WatchConfigFilesSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/GetConfigFileMetadataList" => { - #[allow(non_camel_case_types)] - struct GetConfigFileMetadataListSvc(pub Arc); - impl - tonic::server::UnaryService - for GetConfigFileMetadataListSvc - { - type Response = super::ConfigClientListResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_config_file_metadata_list( - &inner, request, - ) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = GetConfigFileMetadataListSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/v1.PolarisConfigGRPC/Discover" => { - #[allow(non_camel_case_types)] - struct DiscoverSvc(pub Arc); - impl - tonic::server::StreamingService - for DiscoverSvc - { - type Response = super::ConfigDiscoverResponse; - type ResponseStream = T::DiscoverStream; - type Future = - BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request>, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::discover(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let inner = inner.0; - let method = DiscoverSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.streaming(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => Box::pin(async move { - Ok(http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap()) - }), - } - } - } - impl Clone for PolarisConfigGrpcServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService for PolarisConfigGrpcServer { - const NAME: &'static str = "v1.PolarisConfigGRPC"; - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum Code { - /// base module status codes - Unknown = 0, - ExecuteSuccess = 200000, - DataNoChange = 200001, - NoNeedUpdate = 200002, - BadRequest = 400000, - ParseException = 400001, - EmptyRequest = 400002, - BatchSizeOverLimit = 400003, - InvalidDiscoverResource = 400004, - InvalidRequestId = 400100, - InvalidUserName = 400101, - InvalidUserToken = 400102, - InvalidParameter = 400103, - EmptyQueryParameter = 400104, - InvalidQueryInsParameter = 400105, - InvalidNamespaceName = 400110, - InvalidNamespaceOwners = 400111, - InvalidNamespaceToken = 400112, - InvalidServiceName = 400120, - InvalidServiceOwners = 400121, - InvalidServiceToken = 400122, - InvalidServiceMetadata = 400123, - InvalidServicePorts = 400124, - InvalidServiceBusiness = 400125, - InvalidServiceDepartment = 400126, - InvalidServiceCmdb = 400127, - InvalidServiceComment = 400128, - InvalidServiceAliasComment = 400129, - InvalidInstanceId = 400130, - InvalidInstanceHost = 400131, - InvalidInstancePort = 400132, - InvalidServiceAlias = 400133, - InvalidNamespaceWithAlias = 400134, - InvalidServiceAliasOwners = 400135, - InvalidInstanceProtocol = 400136, - InvalidInstanceVersion = 400137, - InvalidInstanceLogicSet = 400138, - InvalidInstanceIsolate = 400139, - HealthCheckNotOpen = 400140, - HeartbeatOnDisabledIns = 400141, - HeartbeatExceedLimit = 400142, - HeartbeatTypeNotFound = 400143, - InvalidMetadata = 400150, - InvalidRateLimitId = 400151, - InvalidRateLimitLabels = 400152, - InvalidRateLimitAmounts = 400153, - InvalidRateLimitName = 400154, - InvalidCircuitBreakerId = 400160, - InvalidCircuitBreakerVersion = 400161, - InvalidCircuitBreakerName = 400162, - InvalidCircuitBreakerNamespace = 400163, - InvalidCircuitBreakerOwners = 400164, - InvalidCircuitBreakerToken = 400165, - InvalidCircuitBreakerBusiness = 400166, - InvalidCircuitBreakerDepartment = 400167, - InvalidCircuitBreakerComment = 400168, - CircuitBreakerRuleExisted = 400169, - InvalidRoutingId = 400700, - InvalidRoutingPolicy = 400701, - InvalidRoutingName = 400702, - InvalidRoutingPriority = 400703, - InvalidFaultDetectId = 400900, - InvalidFaultDetectName = 400901, - InvalidFaultDetectNamespace = 400902, - FaultDetectRuleExisted = 400903, - InvalidMatchRule = 400904, - /// network relative codes - ServicesExistedMesh = 400170, - ResourcesExistedMesh = 400171, - InvalidMeshParameter = 400172, - /// platform relative codes - InvalidPlatformId = 400180, - InvalidPlatformName = 400181, - InvalidPlatformDomain = 400182, - InvalidPlatformQps = 400183, - InvalidPlatformToken = 400184, - InvalidPlatformOwner = 400185, - InvalidPlatformDepartment = 400186, - InvalidPlatformComment = 400187, - NotFoundPlatform = 400188, - /// flux relative codes - InvalidFluxRateLimitId = 400190, - InvalidFluxRateLimitQps = 400191, - InvalidFluxRateLimitSetKey = 400192, - ExistedResource = 400201, - NotFoundResource = 400202, - NamespaceExistedServices = 400203, - ServiceExistedInstances = 400204, - ServiceExistedRoutings = 400205, - ServiceExistedRateLimits = 400206, - ExistReleasedConfig = 400207, - SameInstanceRequest = 400208, - ServiceExistedCircuitBreakers = 400209, - ServiceExistedAlias = 400210, - NamespaceExistedMeshResources = 400211, - NamespaceExistedCircuitBreakers = 400212, - ServiceSubscribedByMeshes = 400213, - ServiceExistedFluxRateLimits = 400214, - NamespaceExistedConfigGroups = 400219, - NotFoundService = 400301, - NotFoundRouting = 400302, - NotFoundInstance = 400303, - NotFoundServiceAlias = 400304, - NotFoundNamespace = 400305, - NotFoundSourceService = 400306, - NotFoundRateLimit = 400307, - NotFoundCircuitBreaker = 400308, - NotFoundMasterConfig = 400309, - NotFoundTagConfig = 400310, - NotFoundTagConfigOrService = 400311, - ClientApiNotOpen = 400401, - NotAllowBusinessService = 400402, - NotAllowAliasUpdate = 400501, - NotAllowAliasCreateInstance = 400502, - NotAllowAliasCreateRouting = 400503, - NotAllowCreateAliasForAlias = 400504, - NotAllowAliasCreateRateLimit = 400505, - NotAllowAliasBindRule = 400506, - NotAllowDifferentNamespaceBindRule = 400507, - Unauthorized = 401000, - NotAllowedAccess = 401001, - CmdbNotFindHost = 404001, - DataConflict = 409000, - InstanceTooManyRequests = 429001, - IpRateLimit = 429002, - ApiRateLimit = 403003, - ExecuteException = 500000, - StoreLayerException = 500001, - CmdbPluginException = 500002, - ParseRoutingException = 500004, - ParseRateLimitException = 500005, - ParseCircuitBreakerException = 500006, - HeartbeatException = 500007, - InstanceRegisTimeout = 500008, - /// config center status codes - InvalidConfigFileGroupName = 400801, - InvalidConfigFileName = 400802, - InvalidConfigFileContentLength = 400803, - InvalidConfigFileFormat = 400804, - InvalidConfigFileTags = 400805, - InvalidWatchConfigFileFormat = 400806, - NotFoundResourceConfigFile = 400807, - InvalidConfigFileTemplateName = 400808, - EncryptConfigFileException = 400809, - DecryptConfigFileException = 400810, - /// auth codes - InvalidUserOwners = 400410, - InvalidUserId = 400411, - InvalidUserPassword = 400412, - InvalidUserMobile = 400413, - InvalidUserEmail = 400414, - InvalidUserGroupOwners = 400420, - InvalidUserGroupId = 400421, - InvalidAuthStrategyOwners = 400430, - InvalidAuthStrategyName = 400431, - InvalidAuthStrategyId = 400432, - InvalidPrincipalType = 400440, - UserExisted = 400215, - UserGroupExisted = 400216, - AuthStrategyRuleExisted = 400217, - SubAccountExisted = 400218, - NotFoundUser = 400312, - NotFoundOwnerUser = 400313, - NotFoundUserGroup = 400314, - NotFoundAuthStrategyRule = 400315, - NotAllowModifyDefaultStrategyPrincipal = 400508, - NotAllowModifyOwnerDefaultStrategy = 400509, - EmptyAutToken = 401002, - TokenDisabled = 401003, - TokenNotExisted = 401004, - AuthTokenForbidden = 403001, - OperationRoleForbidden = 403002, -} -impl Code { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Code::Unknown => "Unknown", - Code::ExecuteSuccess => "ExecuteSuccess", - Code::DataNoChange => "DataNoChange", - Code::NoNeedUpdate => "NoNeedUpdate", - Code::BadRequest => "BadRequest", - Code::ParseException => "ParseException", - Code::EmptyRequest => "EmptyRequest", - Code::BatchSizeOverLimit => "BatchSizeOverLimit", - Code::InvalidDiscoverResource => "InvalidDiscoverResource", - Code::InvalidRequestId => "InvalidRequestID", - Code::InvalidUserName => "InvalidUserName", - Code::InvalidUserToken => "InvalidUserToken", - Code::InvalidParameter => "InvalidParameter", - Code::EmptyQueryParameter => "EmptyQueryParameter", - Code::InvalidQueryInsParameter => "InvalidQueryInsParameter", - Code::InvalidNamespaceName => "InvalidNamespaceName", - Code::InvalidNamespaceOwners => "InvalidNamespaceOwners", - Code::InvalidNamespaceToken => "InvalidNamespaceToken", - Code::InvalidServiceName => "InvalidServiceName", - Code::InvalidServiceOwners => "InvalidServiceOwners", - Code::InvalidServiceToken => "InvalidServiceToken", - Code::InvalidServiceMetadata => "InvalidServiceMetadata", - Code::InvalidServicePorts => "InvalidServicePorts", - Code::InvalidServiceBusiness => "InvalidServiceBusiness", - Code::InvalidServiceDepartment => "InvalidServiceDepartment", - Code::InvalidServiceCmdb => "InvalidServiceCMDB", - Code::InvalidServiceComment => "InvalidServiceComment", - Code::InvalidServiceAliasComment => "InvalidServiceAliasComment", - Code::InvalidInstanceId => "InvalidInstanceID", - Code::InvalidInstanceHost => "InvalidInstanceHost", - Code::InvalidInstancePort => "InvalidInstancePort", - Code::InvalidServiceAlias => "InvalidServiceAlias", - Code::InvalidNamespaceWithAlias => "InvalidNamespaceWithAlias", - Code::InvalidServiceAliasOwners => "InvalidServiceAliasOwners", - Code::InvalidInstanceProtocol => "InvalidInstanceProtocol", - Code::InvalidInstanceVersion => "InvalidInstanceVersion", - Code::InvalidInstanceLogicSet => "InvalidInstanceLogicSet", - Code::InvalidInstanceIsolate => "InvalidInstanceIsolate", - Code::HealthCheckNotOpen => "HealthCheckNotOpen", - Code::HeartbeatOnDisabledIns => "HeartbeatOnDisabledIns", - Code::HeartbeatExceedLimit => "HeartbeatExceedLimit", - Code::HeartbeatTypeNotFound => "HeartbeatTypeNotFound", - Code::InvalidMetadata => "InvalidMetadata", - Code::InvalidRateLimitId => "InvalidRateLimitID", - Code::InvalidRateLimitLabels => "InvalidRateLimitLabels", - Code::InvalidRateLimitAmounts => "InvalidRateLimitAmounts", - Code::InvalidRateLimitName => "InvalidRateLimitName", - Code::InvalidCircuitBreakerId => "InvalidCircuitBreakerID", - Code::InvalidCircuitBreakerVersion => "InvalidCircuitBreakerVersion", - Code::InvalidCircuitBreakerName => "InvalidCircuitBreakerName", - Code::InvalidCircuitBreakerNamespace => "InvalidCircuitBreakerNamespace", - Code::InvalidCircuitBreakerOwners => "InvalidCircuitBreakerOwners", - Code::InvalidCircuitBreakerToken => "InvalidCircuitBreakerToken", - Code::InvalidCircuitBreakerBusiness => "InvalidCircuitBreakerBusiness", - Code::InvalidCircuitBreakerDepartment => "InvalidCircuitBreakerDepartment", - Code::InvalidCircuitBreakerComment => "InvalidCircuitBreakerComment", - Code::CircuitBreakerRuleExisted => "CircuitBreakerRuleExisted", - Code::InvalidRoutingId => "InvalidRoutingID", - Code::InvalidRoutingPolicy => "InvalidRoutingPolicy", - Code::InvalidRoutingName => "InvalidRoutingName", - Code::InvalidRoutingPriority => "InvalidRoutingPriority", - Code::InvalidFaultDetectId => "InvalidFaultDetectID", - Code::InvalidFaultDetectName => "InvalidFaultDetectName", - Code::InvalidFaultDetectNamespace => "InvalidFaultDetectNamespace", - Code::FaultDetectRuleExisted => "FaultDetectRuleExisted", - Code::InvalidMatchRule => "InvalidMatchRule", - Code::ServicesExistedMesh => "ServicesExistedMesh", - Code::ResourcesExistedMesh => "ResourcesExistedMesh", - Code::InvalidMeshParameter => "InvalidMeshParameter", - Code::InvalidPlatformId => "InvalidPlatformID", - Code::InvalidPlatformName => "InvalidPlatformName", - Code::InvalidPlatformDomain => "InvalidPlatformDomain", - Code::InvalidPlatformQps => "InvalidPlatformQPS", - Code::InvalidPlatformToken => "InvalidPlatformToken", - Code::InvalidPlatformOwner => "InvalidPlatformOwner", - Code::InvalidPlatformDepartment => "InvalidPlatformDepartment", - Code::InvalidPlatformComment => "InvalidPlatformComment", - Code::NotFoundPlatform => "NotFoundPlatform", - Code::InvalidFluxRateLimitId => "InvalidFluxRateLimitId", - Code::InvalidFluxRateLimitQps => "InvalidFluxRateLimitQps", - Code::InvalidFluxRateLimitSetKey => "InvalidFluxRateLimitSetKey", - Code::ExistedResource => "ExistedResource", - Code::NotFoundResource => "NotFoundResource", - Code::NamespaceExistedServices => "NamespaceExistedServices", - Code::ServiceExistedInstances => "ServiceExistedInstances", - Code::ServiceExistedRoutings => "ServiceExistedRoutings", - Code::ServiceExistedRateLimits => "ServiceExistedRateLimits", - Code::ExistReleasedConfig => "ExistReleasedConfig", - Code::SameInstanceRequest => "SameInstanceRequest", - Code::ServiceExistedCircuitBreakers => "ServiceExistedCircuitBreakers", - Code::ServiceExistedAlias => "ServiceExistedAlias", - Code::NamespaceExistedMeshResources => "NamespaceExistedMeshResources", - Code::NamespaceExistedCircuitBreakers => "NamespaceExistedCircuitBreakers", - Code::ServiceSubscribedByMeshes => "ServiceSubscribedByMeshes", - Code::ServiceExistedFluxRateLimits => "ServiceExistedFluxRateLimits", - Code::NamespaceExistedConfigGroups => "NamespaceExistedConfigGroups", - Code::NotFoundService => "NotFoundService", - Code::NotFoundRouting => "NotFoundRouting", - Code::NotFoundInstance => "NotFoundInstance", - Code::NotFoundServiceAlias => "NotFoundServiceAlias", - Code::NotFoundNamespace => "NotFoundNamespace", - Code::NotFoundSourceService => "NotFoundSourceService", - Code::NotFoundRateLimit => "NotFoundRateLimit", - Code::NotFoundCircuitBreaker => "NotFoundCircuitBreaker", - Code::NotFoundMasterConfig => "NotFoundMasterConfig", - Code::NotFoundTagConfig => "NotFoundTagConfig", - Code::NotFoundTagConfigOrService => "NotFoundTagConfigOrService", - Code::ClientApiNotOpen => "ClientAPINotOpen", - Code::NotAllowBusinessService => "NotAllowBusinessService", - Code::NotAllowAliasUpdate => "NotAllowAliasUpdate", - Code::NotAllowAliasCreateInstance => "NotAllowAliasCreateInstance", - Code::NotAllowAliasCreateRouting => "NotAllowAliasCreateRouting", - Code::NotAllowCreateAliasForAlias => "NotAllowCreateAliasForAlias", - Code::NotAllowAliasCreateRateLimit => "NotAllowAliasCreateRateLimit", - Code::NotAllowAliasBindRule => "NotAllowAliasBindRule", - Code::NotAllowDifferentNamespaceBindRule => "NotAllowDifferentNamespaceBindRule", - Code::Unauthorized => "Unauthorized", - Code::NotAllowedAccess => "NotAllowedAccess", - Code::CmdbNotFindHost => "CMDBNotFindHost", - Code::DataConflict => "DataConflict", - Code::InstanceTooManyRequests => "InstanceTooManyRequests", - Code::IpRateLimit => "IPRateLimit", - Code::ApiRateLimit => "APIRateLimit", - Code::ExecuteException => "ExecuteException", - Code::StoreLayerException => "StoreLayerException", - Code::CmdbPluginException => "CMDBPluginException", - Code::ParseRoutingException => "ParseRoutingException", - Code::ParseRateLimitException => "ParseRateLimitException", - Code::ParseCircuitBreakerException => "ParseCircuitBreakerException", - Code::HeartbeatException => "HeartbeatException", - Code::InstanceRegisTimeout => "InstanceRegisTimeout", - Code::InvalidConfigFileGroupName => "InvalidConfigFileGroupName", - Code::InvalidConfigFileName => "InvalidConfigFileName", - Code::InvalidConfigFileContentLength => "InvalidConfigFileContentLength", - Code::InvalidConfigFileFormat => "InvalidConfigFileFormat", - Code::InvalidConfigFileTags => "InvalidConfigFileTags", - Code::InvalidWatchConfigFileFormat => "InvalidWatchConfigFileFormat", - Code::NotFoundResourceConfigFile => "NotFoundResourceConfigFile", - Code::InvalidConfigFileTemplateName => "InvalidConfigFileTemplateName", - Code::EncryptConfigFileException => "EncryptConfigFileException", - Code::DecryptConfigFileException => "DecryptConfigFileException", - Code::InvalidUserOwners => "InvalidUserOwners", - Code::InvalidUserId => "InvalidUserID", - Code::InvalidUserPassword => "InvalidUserPassword", - Code::InvalidUserMobile => "InvalidUserMobile", - Code::InvalidUserEmail => "InvalidUserEmail", - Code::InvalidUserGroupOwners => "InvalidUserGroupOwners", - Code::InvalidUserGroupId => "InvalidUserGroupID", - Code::InvalidAuthStrategyOwners => "InvalidAuthStrategyOwners", - Code::InvalidAuthStrategyName => "InvalidAuthStrategyName", - Code::InvalidAuthStrategyId => "InvalidAuthStrategyID", - Code::InvalidPrincipalType => "InvalidPrincipalType", - Code::UserExisted => "UserExisted", - Code::UserGroupExisted => "UserGroupExisted", - Code::AuthStrategyRuleExisted => "AuthStrategyRuleExisted", - Code::SubAccountExisted => "SubAccountExisted", - Code::NotFoundUser => "NotFoundUser", - Code::NotFoundOwnerUser => "NotFoundOwnerUser", - Code::NotFoundUserGroup => "NotFoundUserGroup", - Code::NotFoundAuthStrategyRule => "NotFoundAuthStrategyRule", - Code::NotAllowModifyDefaultStrategyPrincipal => { - "NotAllowModifyDefaultStrategyPrincipal" - } - Code::NotAllowModifyOwnerDefaultStrategy => "NotAllowModifyOwnerDefaultStrategy", - Code::EmptyAutToken => "EmptyAutToken", - Code::TokenDisabled => "TokenDisabled", - Code::TokenNotExisted => "TokenNotExisted", - Code::AuthTokenForbidden => "AuthTokenForbidden", - Code::OperationRoleForbidden => "OperationRoleForbidden", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "Unknown" => Some(Self::Unknown), - "ExecuteSuccess" => Some(Self::ExecuteSuccess), - "DataNoChange" => Some(Self::DataNoChange), - "NoNeedUpdate" => Some(Self::NoNeedUpdate), - "BadRequest" => Some(Self::BadRequest), - "ParseException" => Some(Self::ParseException), - "EmptyRequest" => Some(Self::EmptyRequest), - "BatchSizeOverLimit" => Some(Self::BatchSizeOverLimit), - "InvalidDiscoverResource" => Some(Self::InvalidDiscoverResource), - "InvalidRequestID" => Some(Self::InvalidRequestId), - "InvalidUserName" => Some(Self::InvalidUserName), - "InvalidUserToken" => Some(Self::InvalidUserToken), - "InvalidParameter" => Some(Self::InvalidParameter), - "EmptyQueryParameter" => Some(Self::EmptyQueryParameter), - "InvalidQueryInsParameter" => Some(Self::InvalidQueryInsParameter), - "InvalidNamespaceName" => Some(Self::InvalidNamespaceName), - "InvalidNamespaceOwners" => Some(Self::InvalidNamespaceOwners), - "InvalidNamespaceToken" => Some(Self::InvalidNamespaceToken), - "InvalidServiceName" => Some(Self::InvalidServiceName), - "InvalidServiceOwners" => Some(Self::InvalidServiceOwners), - "InvalidServiceToken" => Some(Self::InvalidServiceToken), - "InvalidServiceMetadata" => Some(Self::InvalidServiceMetadata), - "InvalidServicePorts" => Some(Self::InvalidServicePorts), - "InvalidServiceBusiness" => Some(Self::InvalidServiceBusiness), - "InvalidServiceDepartment" => Some(Self::InvalidServiceDepartment), - "InvalidServiceCMDB" => Some(Self::InvalidServiceCmdb), - "InvalidServiceComment" => Some(Self::InvalidServiceComment), - "InvalidServiceAliasComment" => Some(Self::InvalidServiceAliasComment), - "InvalidInstanceID" => Some(Self::InvalidInstanceId), - "InvalidInstanceHost" => Some(Self::InvalidInstanceHost), - "InvalidInstancePort" => Some(Self::InvalidInstancePort), - "InvalidServiceAlias" => Some(Self::InvalidServiceAlias), - "InvalidNamespaceWithAlias" => Some(Self::InvalidNamespaceWithAlias), - "InvalidServiceAliasOwners" => Some(Self::InvalidServiceAliasOwners), - "InvalidInstanceProtocol" => Some(Self::InvalidInstanceProtocol), - "InvalidInstanceVersion" => Some(Self::InvalidInstanceVersion), - "InvalidInstanceLogicSet" => Some(Self::InvalidInstanceLogicSet), - "InvalidInstanceIsolate" => Some(Self::InvalidInstanceIsolate), - "HealthCheckNotOpen" => Some(Self::HealthCheckNotOpen), - "HeartbeatOnDisabledIns" => Some(Self::HeartbeatOnDisabledIns), - "HeartbeatExceedLimit" => Some(Self::HeartbeatExceedLimit), - "HeartbeatTypeNotFound" => Some(Self::HeartbeatTypeNotFound), - "InvalidMetadata" => Some(Self::InvalidMetadata), - "InvalidRateLimitID" => Some(Self::InvalidRateLimitId), - "InvalidRateLimitLabels" => Some(Self::InvalidRateLimitLabels), - "InvalidRateLimitAmounts" => Some(Self::InvalidRateLimitAmounts), - "InvalidRateLimitName" => Some(Self::InvalidRateLimitName), - "InvalidCircuitBreakerID" => Some(Self::InvalidCircuitBreakerId), - "InvalidCircuitBreakerVersion" => Some(Self::InvalidCircuitBreakerVersion), - "InvalidCircuitBreakerName" => Some(Self::InvalidCircuitBreakerName), - "InvalidCircuitBreakerNamespace" => Some(Self::InvalidCircuitBreakerNamespace), - "InvalidCircuitBreakerOwners" => Some(Self::InvalidCircuitBreakerOwners), - "InvalidCircuitBreakerToken" => Some(Self::InvalidCircuitBreakerToken), - "InvalidCircuitBreakerBusiness" => Some(Self::InvalidCircuitBreakerBusiness), - "InvalidCircuitBreakerDepartment" => Some(Self::InvalidCircuitBreakerDepartment), - "InvalidCircuitBreakerComment" => Some(Self::InvalidCircuitBreakerComment), - "CircuitBreakerRuleExisted" => Some(Self::CircuitBreakerRuleExisted), - "InvalidRoutingID" => Some(Self::InvalidRoutingId), - "InvalidRoutingPolicy" => Some(Self::InvalidRoutingPolicy), - "InvalidRoutingName" => Some(Self::InvalidRoutingName), - "InvalidRoutingPriority" => Some(Self::InvalidRoutingPriority), - "InvalidFaultDetectID" => Some(Self::InvalidFaultDetectId), - "InvalidFaultDetectName" => Some(Self::InvalidFaultDetectName), - "InvalidFaultDetectNamespace" => Some(Self::InvalidFaultDetectNamespace), - "FaultDetectRuleExisted" => Some(Self::FaultDetectRuleExisted), - "InvalidMatchRule" => Some(Self::InvalidMatchRule), - "ServicesExistedMesh" => Some(Self::ServicesExistedMesh), - "ResourcesExistedMesh" => Some(Self::ResourcesExistedMesh), - "InvalidMeshParameter" => Some(Self::InvalidMeshParameter), - "InvalidPlatformID" => Some(Self::InvalidPlatformId), - "InvalidPlatformName" => Some(Self::InvalidPlatformName), - "InvalidPlatformDomain" => Some(Self::InvalidPlatformDomain), - "InvalidPlatformQPS" => Some(Self::InvalidPlatformQps), - "InvalidPlatformToken" => Some(Self::InvalidPlatformToken), - "InvalidPlatformOwner" => Some(Self::InvalidPlatformOwner), - "InvalidPlatformDepartment" => Some(Self::InvalidPlatformDepartment), - "InvalidPlatformComment" => Some(Self::InvalidPlatformComment), - "NotFoundPlatform" => Some(Self::NotFoundPlatform), - "InvalidFluxRateLimitId" => Some(Self::InvalidFluxRateLimitId), - "InvalidFluxRateLimitQps" => Some(Self::InvalidFluxRateLimitQps), - "InvalidFluxRateLimitSetKey" => Some(Self::InvalidFluxRateLimitSetKey), - "ExistedResource" => Some(Self::ExistedResource), - "NotFoundResource" => Some(Self::NotFoundResource), - "NamespaceExistedServices" => Some(Self::NamespaceExistedServices), - "ServiceExistedInstances" => Some(Self::ServiceExistedInstances), - "ServiceExistedRoutings" => Some(Self::ServiceExistedRoutings), - "ServiceExistedRateLimits" => Some(Self::ServiceExistedRateLimits), - "ExistReleasedConfig" => Some(Self::ExistReleasedConfig), - "SameInstanceRequest" => Some(Self::SameInstanceRequest), - "ServiceExistedCircuitBreakers" => Some(Self::ServiceExistedCircuitBreakers), - "ServiceExistedAlias" => Some(Self::ServiceExistedAlias), - "NamespaceExistedMeshResources" => Some(Self::NamespaceExistedMeshResources), - "NamespaceExistedCircuitBreakers" => Some(Self::NamespaceExistedCircuitBreakers), - "ServiceSubscribedByMeshes" => Some(Self::ServiceSubscribedByMeshes), - "ServiceExistedFluxRateLimits" => Some(Self::ServiceExistedFluxRateLimits), - "NamespaceExistedConfigGroups" => Some(Self::NamespaceExistedConfigGroups), - "NotFoundService" => Some(Self::NotFoundService), - "NotFoundRouting" => Some(Self::NotFoundRouting), - "NotFoundInstance" => Some(Self::NotFoundInstance), - "NotFoundServiceAlias" => Some(Self::NotFoundServiceAlias), - "NotFoundNamespace" => Some(Self::NotFoundNamespace), - "NotFoundSourceService" => Some(Self::NotFoundSourceService), - "NotFoundRateLimit" => Some(Self::NotFoundRateLimit), - "NotFoundCircuitBreaker" => Some(Self::NotFoundCircuitBreaker), - "NotFoundMasterConfig" => Some(Self::NotFoundMasterConfig), - "NotFoundTagConfig" => Some(Self::NotFoundTagConfig), - "NotFoundTagConfigOrService" => Some(Self::NotFoundTagConfigOrService), - "ClientAPINotOpen" => Some(Self::ClientApiNotOpen), - "NotAllowBusinessService" => Some(Self::NotAllowBusinessService), - "NotAllowAliasUpdate" => Some(Self::NotAllowAliasUpdate), - "NotAllowAliasCreateInstance" => Some(Self::NotAllowAliasCreateInstance), - "NotAllowAliasCreateRouting" => Some(Self::NotAllowAliasCreateRouting), - "NotAllowCreateAliasForAlias" => Some(Self::NotAllowCreateAliasForAlias), - "NotAllowAliasCreateRateLimit" => Some(Self::NotAllowAliasCreateRateLimit), - "NotAllowAliasBindRule" => Some(Self::NotAllowAliasBindRule), - "NotAllowDifferentNamespaceBindRule" => Some(Self::NotAllowDifferentNamespaceBindRule), - "Unauthorized" => Some(Self::Unauthorized), - "NotAllowedAccess" => Some(Self::NotAllowedAccess), - "CMDBNotFindHost" => Some(Self::CmdbNotFindHost), - "DataConflict" => Some(Self::DataConflict), - "InstanceTooManyRequests" => Some(Self::InstanceTooManyRequests), - "IPRateLimit" => Some(Self::IpRateLimit), - "APIRateLimit" => Some(Self::ApiRateLimit), - "ExecuteException" => Some(Self::ExecuteException), - "StoreLayerException" => Some(Self::StoreLayerException), - "CMDBPluginException" => Some(Self::CmdbPluginException), - "ParseRoutingException" => Some(Self::ParseRoutingException), - "ParseRateLimitException" => Some(Self::ParseRateLimitException), - "ParseCircuitBreakerException" => Some(Self::ParseCircuitBreakerException), - "HeartbeatException" => Some(Self::HeartbeatException), - "InstanceRegisTimeout" => Some(Self::InstanceRegisTimeout), - "InvalidConfigFileGroupName" => Some(Self::InvalidConfigFileGroupName), - "InvalidConfigFileName" => Some(Self::InvalidConfigFileName), - "InvalidConfigFileContentLength" => Some(Self::InvalidConfigFileContentLength), - "InvalidConfigFileFormat" => Some(Self::InvalidConfigFileFormat), - "InvalidConfigFileTags" => Some(Self::InvalidConfigFileTags), - "InvalidWatchConfigFileFormat" => Some(Self::InvalidWatchConfigFileFormat), - "NotFoundResourceConfigFile" => Some(Self::NotFoundResourceConfigFile), - "InvalidConfigFileTemplateName" => Some(Self::InvalidConfigFileTemplateName), - "EncryptConfigFileException" => Some(Self::EncryptConfigFileException), - "DecryptConfigFileException" => Some(Self::DecryptConfigFileException), - "InvalidUserOwners" => Some(Self::InvalidUserOwners), - "InvalidUserID" => Some(Self::InvalidUserId), - "InvalidUserPassword" => Some(Self::InvalidUserPassword), - "InvalidUserMobile" => Some(Self::InvalidUserMobile), - "InvalidUserEmail" => Some(Self::InvalidUserEmail), - "InvalidUserGroupOwners" => Some(Self::InvalidUserGroupOwners), - "InvalidUserGroupID" => Some(Self::InvalidUserGroupId), - "InvalidAuthStrategyOwners" => Some(Self::InvalidAuthStrategyOwners), - "InvalidAuthStrategyName" => Some(Self::InvalidAuthStrategyName), - "InvalidAuthStrategyID" => Some(Self::InvalidAuthStrategyId), - "InvalidPrincipalType" => Some(Self::InvalidPrincipalType), - "UserExisted" => Some(Self::UserExisted), - "UserGroupExisted" => Some(Self::UserGroupExisted), - "AuthStrategyRuleExisted" => Some(Self::AuthStrategyRuleExisted), - "SubAccountExisted" => Some(Self::SubAccountExisted), - "NotFoundUser" => Some(Self::NotFoundUser), - "NotFoundOwnerUser" => Some(Self::NotFoundOwnerUser), - "NotFoundUserGroup" => Some(Self::NotFoundUserGroup), - "NotFoundAuthStrategyRule" => Some(Self::NotFoundAuthStrategyRule), - "NotAllowModifyDefaultStrategyPrincipal" => { - Some(Self::NotAllowModifyDefaultStrategyPrincipal) - } - "NotAllowModifyOwnerDefaultStrategy" => Some(Self::NotAllowModifyOwnerDefaultStrategy), - "EmptyAutToken" => Some(Self::EmptyAutToken), - "TokenDisabled" => Some(Self::TokenDisabled), - "TokenNotExisted" => Some(Self::TokenNotExisted), - "AuthTokenForbidden" => Some(Self::AuthTokenForbidden), - "OperationRoleForbidden" => Some(Self::OperationRoleForbidden), - _ => None, - } - } -} diff --git a/src/core/model/router.rs b/src/core/model/router.rs index c227269..9ffd3d7 100644 --- a/src/core/model/router.rs +++ b/src/core/model/router.rs @@ -13,41 +13,101 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use std::iter::Map; +use std::collections::HashMap; -use super::loadbalance::Criteria; +use super::{ + naming::{ServiceInstances, ServiceKey}, + ArgumentType, TrafficArgument, +}; -#[derive(Clone)] -enum MetadataFailoverType { +pub static DEFAULT_ROUTER_ISOLATED: &str = "isolatedRouter"; + +pub static DEFAULT_ROUTER_RECOVER: &str = "recoverRouter"; + +pub static DEFAULT_ROUTER_METADATA: &str = "metadataRouter"; + +pub static DEFAULT_ROUTER_RULE: &str = "ruleBasedRouter"; + +pub static DEFAULT_ROUTER_NEARBY: &str = "nearbyBasedRouter"; + +pub static DEFAULT_ROUTER_SET: &str = "setRouter"; + +pub static DEFAULT_ROUTER_CANARY: &str = "canaryRouter"; + +pub static DEFAULT_ROUTER_LANE: &str = "laneRouter"; + +pub static DEFAULT_ROUTER_NAMESPACE: &str = "namespaceRouter"; + +#[derive(Clone, Debug)] +pub enum MetadataFailoverType { MetadataFailoverNone, MetadataFailoverAll, MetadataFailoverNoKey, } -enum TrafficLabel { - Header, - Cookie, - Query, - Method, - Path, - CallerIp, +pub enum RouteState { + Next, + Retry, } -pub struct Argument { - pub traffic_label: TrafficLabel, - pub key: String, - pub value: String, +pub struct RouteResult { + pub state: RouteState, + pub instances: ServiceInstances, } -#[derive(Clone)] -pub struct CallerInfo { - pub namespace: String, - pub service: String, - pub metadata: Map, +fn default_traffic_label_provider(_: ArgumentType, _: &str) -> Option { + None +} + +fn default_external_parameter_supplier(key: &str) -> Option { + match std::env::var(key) { + Ok(v) => Some(v), + Err(_) => None, + } +} + +#[derive(Clone, Debug)] +pub struct RouteInfo { + // 主调服务数据信息 + pub caller: ServiceKey, + // 被调服务数据信息 + pub callee: ServiceKey, + // 路由链 + pub chain: RouterChain, + // 用于元数据路由 + pub metadata: HashMap, pub metadata_failover: MetadataFailoverType, - pub criteria: Criteria, + // traffic_label_provider 流量标签提供者 + pub traffic_label_provider: fn(ArgumentType, &str) -> Option, + // 北极星内部治理规则执行时,会识别规则中的参数来源类别,如果发现规则中的参数来源指定为外部数据源时,会调用本接口进行获取 + pub external_parameter_supplier: fn(&str) -> Option, +} + +impl Default for RouteInfo { + fn default() -> Self { + Self { + caller: Default::default(), + callee: Default::default(), + chain: Default::default(), + metadata: HashMap::::new(), + metadata_failover: MetadataFailoverType::MetadataFailoverNone, + external_parameter_supplier: default_external_parameter_supplier, + traffic_label_provider: default_traffic_label_provider, + } + } +} + +#[derive(Clone, Default, Debug)] +pub struct RouterChain { + pub before: Vec, + pub core: Vec, + pub after: Vec, } -pub struct CalleeInfo { - pub traffic_labels: Vec, +impl RouterChain { + pub fn exist_route(&self, n: &str) -> bool { + self.before.iter().any(|x| x == n) + || self.core.iter().any(|x| x == n) + || self.after.iter().any(|x| x == n) + } } diff --git a/src/core/plugin/cache.rs b/src/core/plugin/cache.rs index 58d4947..b8da5d5 100644 --- a/src/core/plugin/cache.rs +++ b/src/core/plugin/cache.rs @@ -13,7 +13,7 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use crate::core::config::config::Configuration; +use crate::core::config::global::LocalCacheConfig; use crate::core::model::cache::{ EventType, ResourceEventKey, ServerEvent, ServiceInstancesCacheItem, }; @@ -21,6 +21,7 @@ use crate::core::model::config::{ConfigFile, ConfigGroup}; use crate::core::model::error::PolarisError; use crate::core::model::naming::{ServiceRule, Services}; use crate::core::plugin::plugins::Plugin; +use polaris_specification::v1::{ConfigDiscoverResponse, DiscoverResponse}; use std::sync::Arc; use std::time::Duration; @@ -55,7 +56,7 @@ pub trait ResourceListener: Send + Sync { } pub struct InitResourceCacheOption { - pub conf: Arc, + pub conf: LocalCacheConfig, pub runtime: Arc, pub server_connector: Arc>, } @@ -63,6 +64,7 @@ pub struct InitResourceCacheOption { /// 资源缓存 #[async_trait::async_trait] pub trait ResourceCache: Plugin { + fn set_failover_provider(&mut self, failover: Arc); // 加载服务规则 async fn load_service_rule(&self, filter: Filter) -> Result; // 加载服务 @@ -80,6 +82,23 @@ pub trait ResourceCache: Plugin { async fn register_resource_listener(&self, listener: Arc); } +#[async_trait::async_trait] +pub trait ResourceCacheFailover: Send + Sync { + // failover_naming_load 兜底加载 + async fn failover_naming_load(&self, filter: Filter) -> Result; + // save_naming_failover 保存容灾数据 + async fn save_naming_failover(&self, value: DiscoverResponse) -> Result<(), PolarisError>; + + // failover_config_load 兜底加载 + async fn failover_config_load( + &self, + filter: Filter, + ) -> Result; + // save_config_failover 保存容灾数据 + async fn save_config_failover(&self, value: ConfigDiscoverResponse) + -> Result<(), PolarisError>; +} + #[derive(Default)] pub struct NoopResourceCache {} @@ -99,6 +118,10 @@ impl Plugin for NoopResourceCache { #[async_trait::async_trait] impl ResourceCache for NoopResourceCache { + fn set_failover_provider(&mut self, failover: Arc) { + todo!() + } + async fn load_service_rule(&self, filter: Filter) -> Result { todo!() } diff --git a/src/core/plugin/circuitbreaker.rs b/src/core/plugin/circuitbreaker.rs new file mode 100644 index 0000000..6c849bd --- /dev/null +++ b/src/core/plugin/circuitbreaker.rs @@ -0,0 +1,30 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::model::circuitbreaker::{Resource, ResourceStat}; +use crate::core::model::{circuitbreaker::CircuitBreakerStatus, error::PolarisError}; + +use crate::core::plugin::plugins::Plugin; + +#[async_trait::async_trait] +pub trait CircuitBreaker: Plugin { + /// check_resource 检查资源 + async fn check_resource( + &self, + resource: Resource, + ) -> Result; + /// report_stat 上报统计信息 + async fn report_stat(&self, stat: ResourceStat) -> Result<(), PolarisError>; +} diff --git a/src/core/plugin/connector.rs b/src/core/plugin/connector.rs index 43f56d7..350f235 100644 --- a/src/core/plugin/connector.rs +++ b/src/core/plugin/connector.rs @@ -21,7 +21,10 @@ use crate::core::config::config::Configuration; use crate::core::model::cache::{RemoteData, ResourceEventKey}; use crate::core::model::config::{ConfigFileRequest, ConfigPublishRequest, ConfigReleaseRequest}; use crate::core::model::error::PolarisError; -use crate::core::model::naming::{InstanceRequest, InstanceResponse}; +use crate::core::model::naming::{ + InstanceRequest, InstanceResponse, ServiceContract, ServiceContractRequest, +}; +use crate::core::model::{ClientContext, ReportClientRequest}; use crate::core::plugin::plugins::Plugin; use super::filter::DiscoverFilter; @@ -37,10 +40,11 @@ pub trait ResourceHandler: Send + Sync { #[derive(Clone)] pub struct InitConnectorOption { pub runtime: Arc, - pub client_id: String, pub conf: Arc, // config_filters pub config_filters: Arc>>, + // client_ctx: 客户端数据上下文 + pub client_ctx: Arc, } #[async_trait::async_trait] @@ -64,13 +68,19 @@ pub trait Connector: Plugin { async fn heartbeat_instance(&self, req: InstanceRequest) -> Result; /// report_client 上报客户端信息 - async fn report_client(&self) -> Result; + async fn report_client(&self, req: ReportClientRequest) -> Result; /// report_service_contract 上报服务契约 - async fn report_service_contract(&self) -> Result; + async fn report_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result; /// get_service_contract 获取服务契约 - async fn get_service_contract(&self) -> Result; + async fn get_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result; /// create_config_file 创建配置文件 async fn create_config_file(&self, req: ConfigFileRequest) -> Result; @@ -129,15 +139,21 @@ impl Connector for NoopConnector { todo!() } - async fn report_client(&self) -> Result { + async fn report_client(&self, req: ReportClientRequest) -> Result { todo!() } - async fn report_service_contract(&self) -> Result { + async fn report_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result { todo!() } - async fn get_service_contract(&self) -> Result { + async fn get_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result { todo!() } diff --git a/src/core/plugin/location.rs b/src/core/plugin/location.rs index 17c7cc7..f88ce9d 100644 --- a/src/core/plugin/location.rs +++ b/src/core/plugin/location.rs @@ -53,7 +53,7 @@ impl LocationType { /// LocationProvider 位置信息提供者, 位置获取优先顺序 本地 > http pub struct LocationProvider { - chain: Vec>, + pub chain: Vec>, } pub fn new_location_provider(opt: &LocationConfig) -> Result { diff --git a/src/core/plugin/lossless.rs b/src/core/plugin/lossless.rs index 78f8b9f..5c68754 100644 --- a/src/core/plugin/lossless.rs +++ b/src/core/plugin/lossless.rs @@ -16,14 +16,15 @@ use crate::core::plugin::plugins::Plugin; use crate::discovery::req::{BaseInstance, InstanceProperties}; +#[async_trait::async_trait] pub trait LosslessPolicy: Plugin { fn build_instance_properties(&self, instance_properties: InstanceProperties); - fn lossless_register( + async fn lossless_register( &self, instance: dyn BaseInstance, instance_properties: InstanceProperties, ); - fn lossless_deregister(&self, instance: dyn BaseInstance); + async fn lossless_deregister(&self, instance: dyn BaseInstance); } diff --git a/src/core/plugin/mod.rs b/src/core/plugin/mod.rs index 7a9f376..5ea9021 100644 --- a/src/core/plugin/mod.rs +++ b/src/core/plugin/mod.rs @@ -14,12 +14,14 @@ // specific language governing permissions and limitations under the License. pub mod cache; +pub mod circuitbreaker; pub mod connector; pub mod filter; pub mod loadbalance; pub mod location; pub mod lossless; pub mod plugins; +pub mod ratelimit; pub mod router; pub mod server; pub mod stat; diff --git a/src/core/plugin/plugins.rs b/src/core/plugin/plugins.rs index 57241eb..cebea4f 100644 --- a/src/core/plugin/plugins.rs +++ b/src/core/plugin/plugins.rs @@ -15,30 +15,46 @@ use crate::core::config::config::Configuration; use crate::core::config::config_file::ConfigFilter; -use crate::core::config::global::{LocalCacheConfig, ServerConnectorConfig}; +use crate::core::config::consumer::{ServiceRouterConfig, ServiceRouterPluginConfig}; +use crate::core::config::global::{LocalCacheConfig, LocationConfig, ServerConnectorConfig}; use crate::core::model::error::{ErrorCode, PolarisError}; +use crate::core::model::ClientContext; use crate::core::plugin::cache::ResourceCache; use crate::core::plugin::connector::Connector; use crate::core::plugin::router::ServiceRouter; use crate::plugins::cache::memory::memory::MemoryCache; +use crate::plugins::circuitbreaker::composite::circuitbreaker::CompositeCircuitBreaker; use crate::plugins::connector::grpc::connector::GrpcConnector; use crate::plugins::filter::configcrypto::crypto::ConfigFileCryptoFilter; use crate::plugins::loadbalance::random::random::WeightRandomLoadbalancer; use crate::plugins::loadbalance::ringhash::ringhash::ConsistentHashLoadBalancer; use crate::plugins::loadbalance::roundrobin::roundrobin::WeightedRoundRobinBalancer; +use crate::plugins::location::local::local::LocalLocationSupplier; +use crate::plugins::location::remotehttp::remotehttp::RemoteHttpLocationSupplier; +use crate::plugins::ratelimit::concurrency::concurrency::ConcurrencyLimiter; +use crate::plugins::router::health::health::HealthRouter; +use crate::plugins::router::lane::lane::LaneRouter; +use crate::plugins::router::metadata::metadata::MetadataRouter; +use crate::plugins::router::nearby::nearby::NearbyRouter; +use crate::plugins::router::rule::rule::RuleRouter; +use once_cell::sync::Lazy; use std::collections::HashMap; use std::fmt::Display; use std::hash::Hash; use std::net::{IpAddr, ToSocketAddrs}; use std::sync::atomic::AtomicU64; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use std::{env, fmt}; use tokio::runtime::Runtime; -use super::cache::InitResourceCacheOption; +use super::cache::{InitResourceCacheOption, ResourceCacheFailover}; +use super::circuitbreaker::CircuitBreaker; use super::connector::InitConnectorOption; use super::filter::DiscoverFilter; use super::loadbalance::LoadBalancer; +use super::location::{LocationProvider, LocationSupplier, LocationType}; +use super::ratelimit::ServiceRateLimiter; +use super::router::RouterContainer; static SEQ: AtomicU64 = AtomicU64::new(1); @@ -75,44 +91,120 @@ pub struct Extensions where Self: Send + Sync, { - pub plugin_container: Arc, - pub runtime: Arc, - pub client_id: String, + // conf: SDK 配置信息 pub conf: Arc, - // config_filters + // runtime: 内部线程池 + pub runtime: Arc, + // client_ctx: 客户端数据上下文 + pub client_ctx: Arc, + // config_filters: 配置文件过滤器 pub config_filters: Option>>>, - // server_connector - pub server_connector: Option>>, + // server_connector: 服务端连接器 + server_connector: Option>>, + // resource_cache 资源缓存 + resource_cache: Option>>, + // locatin_provider: 位置信息提供器 + locatin_provider: Option>, + // circuit_breaker: 熔断器 + pub circuit_breaker: Option>>, + // service_routers 服务路由插件 + pub service_routers: Option>, + // load_balancers 负载均衡器 + pub load_balancers: Arc>>>>, } impl Extensions { pub fn build( - client_id: String, + client_ctx: Arc, conf: Arc, runetime: Arc, ) -> Result { - let mut containers = PluginContainer::default(); - // 初始化所有的插件 - let start_time = std::time::Instant::now(); - containers.register_all_plugin(); - tracing::info!("register_all_plugin cost: {:?}", start_time.elapsed()); - - let arc_container = Arc::new(containers); - - Ok(Self { - plugin_container: arc_container, + let mut extension = Self { + client_ctx: client_ctx, runtime: runetime, - client_id, - conf, + conf: conf.clone(), config_filters: None, server_connector: None, - }) + locatin_provider: None, + circuit_breaker: None, + resource_cache: None, + service_routers: None, + load_balancers: Arc::new(tokio::sync::RwLock::new(HashMap::new())), + }; + + let ret = extension.load_all_plugins(conf.clone()); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + Ok(extension) + } + + fn load_all_plugins(&mut self, conf: Arc) -> Result<(), PolarisError> { + let ret = self.load_config_file_filters(&conf.config.config_filter); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + // 初始化 server_connector + let ret = self.load_server_connector(&conf.global.server_connectors); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + // 初始化 local_cache + let ret = self.load_resource_cache(&conf.consumer.local_cache); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + // 初始化 location_provider + let ret = self.load_location_providers(&conf.global.location); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + // 初始化 service_routers + let ret = self.load_service_routers(&conf.consumer.service_router); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + // 初始化 loadbalancers + let ret = self.load_loadbalancers(); + if ret.is_err() { + return Err(ret.err().unwrap()); + } + + Ok(()) + } + + pub fn get_server_connector(&self) -> Arc> { + self.server_connector.clone().unwrap() + } + + pub fn get_resource_cache(&self) -> Arc> { + self.resource_cache.clone().unwrap() + } + + pub fn get_loadbalancers( + &self, + ) -> Arc>>>> { + self.load_balancers.clone() + } + + pub fn get_location_provider(&self) -> Arc { + self.locatin_provider.clone().unwrap() } - pub fn load_server_connector( + pub fn get_router_container(&self) -> Arc { + self.service_routers.clone().unwrap() + } + + fn load_server_connector( &mut self, connector_opt: &ServerConnectorConfig, - ) -> Result>, PolarisError> { + ) -> Result<(), PolarisError> { if connector_opt.addresses.is_empty() { return Err(PolarisError::new( ErrorCode::InvalidConfig, @@ -121,51 +213,65 @@ impl Extensions { } let protocol = connector_opt.get_protocol(); - let supplier = self.plugin_container.get_connector_supplier(&protocol); + let supplier = CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .get_connector_supplier(&protocol); let mut active_connector = supplier(InitConnectorOption { + client_ctx: self.client_ctx.clone(), runtime: self.runtime.clone(), conf: self.conf.clone(), - client_id: self.client_id.clone(), config_filters: self.config_filters.clone().unwrap().clone(), }); active_connector.init(); let active_connector = Arc::new(active_connector); - self.server_connector = Some(active_connector.clone()); - Ok(active_connector) + self.server_connector = Some(active_connector); + Ok(()) } - pub fn load_resource_cache( - &mut self, - cache_opt: &LocalCacheConfig, - ) -> Result, PolarisError> { + fn load_resource_cache(&mut self, cache_opt: &LocalCacheConfig) -> Result<(), PolarisError> { let cache_name = cache_opt.name.clone(); if cache_name.is_empty() { return Err(PolarisError::new(ErrorCode::InvalidConfig, "".to_string())); } - let supplier = self.plugin_container.get_cache_supplier(&cache_name); + let supplier = CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .get_cache_supplier(&cache_name); let mut active_cache = supplier(InitResourceCacheOption { runtime: self.runtime.clone(), - conf: self.conf.clone(), + conf: cache_opt.clone(), server_connector: self.server_connector.clone().unwrap().clone(), }); + active_cache.init(); - Ok(active_cache) + if let Some(failover) = CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .custom_cache_failover + .clone() + { + active_cache.set_failover_provider(failover); + } + + self.resource_cache = Some(Arc::new(active_cache)); + Ok(()) } - pub fn load_config_file_filters( - &mut self, - filter_conf: &ConfigFilter, - ) -> Result<(), PolarisError> { + fn load_config_file_filters(&mut self, filter_conf: &ConfigFilter) -> Result<(), PolarisError> { let mut filters = Vec::>::new(); if filter_conf.enable { for (_i, name) in filter_conf.chain.iter().enumerate() { if name == "crypto" { let plugin_opt = filter_conf.plugin.get(name).unwrap(); - let supplier = self.plugin_container.get_discover_filter_supplier(name); + let supplier = CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .get_discover_filter_supplier(name); let filter = supplier(plugin_opt.clone()); if filter.is_err() { return Err(filter.err().unwrap()); @@ -178,24 +284,119 @@ impl Extensions { Ok(()) } - pub fn load_loadbalancers(&mut self) -> HashMap>> { + fn load_service_routers( + &mut self, + route_conf: &ServiceRouterConfig, + ) -> Result<(), PolarisError> { + let mut container = RouterContainer::new(); + for (name, supplier) in CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .service_routers + .iter() + { + for (_i, router_conf) in route_conf.before_chain.iter().enumerate() { + if router_conf.name == name.to_string() { + let router = supplier(router_conf); + container + .before_routers + .insert(name.clone(), Arc::new(router)); + } + } + for (_i, router_conf) in route_conf.core_chain.iter().enumerate() { + if router_conf.name == name.to_string() { + let router = supplier(router_conf); + container + .core_routers + .insert(name.clone(), Arc::new(router)); + } + } + + for (_i, router_conf) in route_conf.after_chain.iter().enumerate() { + if router_conf.name == name.to_string() { + let router = supplier(router_conf); + container + .after_routers + .insert(name.clone(), Arc::new(router)); + } + } + } + + self.service_routers = Some(Arc::new(container)); + Ok(()) + } + + fn load_loadbalancers(&mut self) -> Result<(), PolarisError> { let mut loadbalancers = HashMap::>>::new(); - for (name, supplier) in self.plugin_container.load_balancers.iter() { + for (name, supplier) in CLIENT_PLUGIN_CONTAINER + .read() + .unwrap() + .load_balancers + .iter() + { let lb = supplier(); loadbalancers.insert(name.clone(), Arc::new(lb)); } - loadbalancers + self.load_balancers = Arc::new(tokio::sync::RwLock::new(loadbalancers)); + Ok(()) + } + + fn load_location_providers(&mut self, opt: &LocationConfig) -> Result<(), PolarisError> { + let mut chain = Vec::>::new(); + let providers = opt.clone().providers; + if providers.is_none() { + return Err(PolarisError::new( + ErrorCode::ApiInvalidArgument, + "".to_string(), + )); + } + + providers.unwrap().iter().for_each(|provider| { + let name: String = provider.name.clone(); + match LocationType::parse(name.as_str()) { + LocationType::Local => { + chain.push(Box::new(LocalLocationSupplier::new(provider.clone()))); + } + LocationType::Http => { + chain.push(Box::new(RemoteHttpLocationSupplier::new(provider.clone()))); + } + LocationType::Service => {} + } + }); + + let ret = Arc::new(LocationProvider { chain: chain }); + self.locatin_provider = Some(ret.clone()); + return Ok(()); } } +static CLIENT_PLUGIN_CONTAINER: Lazy>> = Lazy::new(|| { + let mut container = PluginContainer::default(); + container.register_all_plugin(); + Arc::new(RwLock::new(container)) +}); + #[derive(Default)] pub struct PluginContainer { + /// ------- SDK 内部运行时插件 ------- + // connectors: 连接器 connectors: HashMap Box>, - routers: HashMap Box>, + // caches: 缓存 caches: HashMap Box>, + // discover_filters: 发现过滤器 discover_filters: HashMap Result, PolarisError>>, + /// ------- 治理规则相关插件 ------- + // service_routers: 路由器 + service_routers: HashMap Box>, + // load_balancers: 负载均衡器 load_balancers: HashMap Box>, + // circuit_breakers: 熔断器 + circuit_breakers: HashMap Box>, + // ratelimiter: 限流器 + ratelimiter: HashMap Box>, + // custom_cache_failover 用户自定义缓存容灾实现 + custom_cache_failover: Option>, } impl PluginContainer { @@ -203,7 +404,10 @@ impl PluginContainer { self.register_resource_cache(); self.register_connector(); self.register_discover_filter(); + self.register_service_routers(); self.register_load_balancer(); + self.register_circuit_breaker(); + self.register_service_ratelimiter(); } fn register_connector(&mut self) { @@ -222,6 +426,20 @@ impl PluginContainer { } } + fn register_service_routers(&mut self) { + let vec = vec![ + HealthRouter::builder, + LaneRouter::builder, + MetadataRouter::builder, + NearbyRouter::builder, + RuleRouter::builder, + ]; + for c in vec { + let (supplier, name) = c(); + self.service_routers.insert(name, supplier); + } + } + fn register_discover_filter(&mut self) { let vec = vec![ConfigFileCryptoFilter::builder]; for c in vec { @@ -242,6 +460,22 @@ impl PluginContainer { } } + fn register_circuit_breaker(&mut self) { + let vec = vec![CompositeCircuitBreaker::builder]; + for c in vec { + let (supplier, name) = c(); + self.circuit_breakers.insert(name, supplier); + } + } + + fn register_service_ratelimiter(&mut self) { + let vec = vec![ConcurrencyLimiter::builder]; + for c in vec { + let (supplier, name) = c(); + self.ratelimiter.insert(name, supplier); + } + } + fn get_connector_supplier( &self, name: &str, @@ -262,21 +496,64 @@ impl PluginContainer { ) -> fn(serde_yaml::Value) -> Result, PolarisError> { *self.discover_filters.get(name).unwrap() } + + fn get_ratelimiter_supplier(&self, name: &str) -> fn() -> Box { + *self.ratelimiter.get(name).unwrap() + } + + /// register_custom_service_router 注册自定义的服务路由 + pub fn register_custom_service_router( + &mut self, + name: String, + supplier: fn(&ServiceRouterPluginConfig) -> Box, + ) { + self.service_routers.insert(name, supplier); + } + + /// register_custom_load_balancer 注册自定义的负载均衡器 + pub fn register_custom_load_balancer( + &mut self, + name: String, + supplier: fn() -> Box, + ) { + self.load_balancers.insert(name, supplier); + } + + /// register_custom_cache_failover 注册自定义的缓存容灾 + pub fn register_custom_cache_failover(&mut self, failover: Arc) { + self.custom_cache_failover = Some(failover); + } } -pub fn acquire_client_id(conf: Arc) -> String { - // 读取本地域名 HOSTNAME,如果存在,则客户端 ID 标识为 {HOSTNAME}_{进程 PID}_{单进程全局自增数字} - // 不满足1的情况下,读取本地 IP,如果存在,则客户端 ID 标识为 {LOCAL_IP}_{进程 PID}_{单进程全局自增数字} - // 不满足上述情况,使用UUID作为客户端ID。 - let seq = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed); - if env::var("HOSTNAME").is_ok() { - return format!( - "{}_{}_{}", - env::var("HOSTNAME").unwrap(), - std::process::id(), - seq - ); +pub fn acquire_client_context(conf: Arc) -> ClientContext { + let mut client_id = conf.global.client.id.clone(); + let self_ip = acquire_client_self_ip(conf.clone()); + + if conf.global.client.id.is_empty() { + // 读取本地域名 HOSTNAME,如果存在,则客户端 ID 标识为 {HOSTNAME}_{进程 PID}_{单进程全局自增数字} + // 不满足1的情况下,读取本地 IP,如果存在,则客户端 ID 标识为 {LOCAL_IP}_{进程 PID}_{单进程全局自增数字} + // 不满足上述情况,使用UUID作为客户端ID。 + let seq = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if env::var("HOSTNAME").is_ok() { + client_id = format!( + "{}_{}_{}", + env::var("HOSTNAME").unwrap(), + std::process::id(), + seq + ); + } else { + // 和北极星服务端做一个 TCP connect 连接获取 本地 IP 地址 + if self_ip == "127.0.0.1".to_string() { + client_id = uuid::Uuid::new_v4().to_string(); + } else { + client_id = format!("{}_{}_{}", self_ip, std::process::id(), seq); + } + } } + ClientContext::new(client_id, self_ip, &conf.global.client) +} + +pub fn acquire_client_self_ip(conf: Arc) -> String { // 和北极星服务端做一个 TCP connect 连接获取 本地 IP 地址 let host = conf.global.server_connectors.addresses.first(); @@ -287,16 +564,17 @@ pub fn acquire_client_id(conf: Arc) -> String { Ok(mut addr_iter) => { if let Some(addr) = addr_iter.next() { if let IpAddr::V4(ipv4) = addr.ip() { - format!("{}_{}_{}", ipv4, std::process::id(), seq) + return format!("{}", ipv4); } else if let IpAddr::V6(ipv6) = addr.ip() { - return format!("{}_{}_{}", ipv6, std::process::id(), seq); - } else { - return uuid::Uuid::new_v4().to_string(); + return format!("{}", ipv6); } - } else { - uuid::Uuid::new_v4().to_string() } + crate::error!("acquire_client_self_ip not ipv4 or ipv6, impossible run here"); + "127.0.0.1".to_string() + } + Err(_err) => { + crate::error!("acquire_client_self_ip error: {:?}", _err); + "127.0.0.1".to_string() } - Err(_err) => uuid::Uuid::new_v4().to_string(), } } diff --git a/src/core/plugin/ratelimit.rs b/src/core/plugin/ratelimit.rs new file mode 100644 index 0000000..50f8e70 --- /dev/null +++ b/src/core/plugin/ratelimit.rs @@ -0,0 +1,33 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::model::error::PolarisError; + +use super::plugins::Plugin; + +/// ServiceRateLimiter 服务速率限制器 +#[async_trait::async_trait] +pub trait ServiceRateLimiter: Plugin { + // allocate_quota 申请配额 + async fn allocate_quota(&self) -> Result<(), PolarisError>; + // return_quota 归还配额 + async fn return_quota(&self) -> Result<(), PolarisError>; + // on_remote_update 远程更新 + async fn on_remote_update(&self) -> Result<(), PolarisError>; + // fetch_local_usage 获取本地使用情况 + async fn fetch_local_usage(&self) -> Result<(), PolarisError>; + // get_amount 获取数量 + async fn get_amount(&self) -> Result<(), PolarisError>; +} diff --git a/src/core/plugin/router.rs b/src/core/plugin/router.rs index e444825..a481c01 100644 --- a/src/core/plugin/router.rs +++ b/src/core/plugin/router.rs @@ -13,6 +13,51 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -use crate::core::plugin::plugins::Plugin; +use std::{collections::HashMap, sync::Arc}; -pub trait ServiceRouter: Plugin {} +use crate::core::{ + model::{ + error::PolarisError, + naming::ServiceInstances, + router::{RouteInfo, RouteResult}, + }, + plugin::plugins::Plugin, +}; + +use super::plugins::Extensions; + +#[derive(Clone)] +pub struct RouterContainer { + pub before_routers: HashMap>>, + pub core_routers: HashMap>>, + pub after_routers: HashMap>>, +} + +impl RouterContainer { + pub fn new() -> Self { + RouterContainer { + before_routers: HashMap::new(), + core_routers: HashMap::new(), + after_routers: HashMap::new(), + } + } +} + +#[derive(Clone)] +pub struct RouteContext { + pub route_info: RouteInfo, + pub extensions: Option>, +} + +#[async_trait::async_trait] +pub trait ServiceRouter: Plugin { + /// choose_instances 实例路由 + async fn choose_instances( + &self, + route_info: RouteContext, + instances: ServiceInstances, + ) -> Result; + + /// enable 是否启用 + async fn enable(&self, route_info: RouteContext, instances: ServiceInstances) -> bool; +} diff --git a/src/discovery/api.rs b/src/discovery/api.rs index 59534ac..135df30 100644 --- a/src/discovery/api.rs +++ b/src/discovery/api.rs @@ -24,21 +24,18 @@ use crate::discovery::req::*; pub fn new_provider_api() -> Result { let start_time = std::time::Instant::now(); let context_ret = SDKContext::default(); - tracing::info!("create sdk context cost: {:?}", start_time.elapsed()); + crate::info!("create sdk context cost: {:?}", start_time.elapsed()); if context_ret.is_err() { return Err(context_ret.err().unwrap()); } - Ok(DefaultProviderAPI::new( - Arc::new(context_ret.unwrap()), - true, - )) + Ok(DefaultProviderAPI::new_raw(context_ret.unwrap())) } pub fn new_provider_api_by_context( context: Arc, ) -> Result { - Ok(DefaultProviderAPI::new(context, false)) + Ok(DefaultProviderAPI::new(context)) } /// ProviderAPI 负责服务提供者的生命周期管理 @@ -76,7 +73,7 @@ pub fn new_consumer_api() -> Result { return Err(context_ret.err().unwrap()); } - Ok(DefaultConsumerAPI::new(Arc::new(context_ret.unwrap()))) + Ok(DefaultConsumerAPI::new_raw(context_ret.unwrap())) } pub fn new_consumer_api_by_context( @@ -125,6 +122,7 @@ where async fn report_service_call(&self, req: ServiceCallResult); } +/// new_lossless_api 创建优雅上下线客户端实例 pub(crate) fn new_lossless_api() -> Result { let context_ret = SDKContext::default(); if context_ret.is_err() { @@ -134,12 +132,14 @@ pub(crate) fn new_lossless_api() -> Result { Ok(DefaultLosslessAPI::new(context_ret.unwrap())) } +/// new_lossless_api_by_context 创建优雅上下线客户端实例 pub(crate) fn new_lossless_api_by_context( context: SDKContext, ) -> Result, PolarisError> { Ok(Arc::new(DefaultLosslessAPI::new(context))) } +/// LosslessAPI 负责优雅上下线客户端的生命周期管理 pub(crate) trait LosslessAPI { fn set_action_provider( &self, diff --git a/src/discovery/default.rs b/src/discovery/default.rs index 5d7dfdb..82895ca 100644 --- a/src/discovery/default.rs +++ b/src/discovery/default.rs @@ -14,7 +14,7 @@ // specific language governing permissions and limitations under the License. use std::collections::HashMap; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::Arc; use tokio::sync::RwLock; @@ -22,7 +22,7 @@ use tokio::task::JoinHandle; use crate::core::context::SDKContext; use crate::core::model::error::PolarisError; -use crate::core::model::naming::ServiceInstancesChangeEvent; +use crate::core::model::naming::{ServiceInstancesChangeEvent, ServiceKey}; use crate::core::plugin::cache::ResourceListener; use crate::discovery::api::{ConsumerAPI, LosslessAPI, ProviderAPI}; use crate::discovery::req::{ @@ -41,9 +41,21 @@ struct InstanceWatcher { req: WatchInstanceRequest, } -struct InstanceResourceListener { +pub struct InstanceResourceListener { + // watcher_id: 监听 listener key 的唯一标识 + watcher_id: Arc, // watchers: namespace#service -> InstanceWatcher - watchers: Arc>>>, + watchers: Arc>>>, +} + +impl InstanceResourceListener { + pub async fn cancel_watch(&self, watch_key: &str, watch_id: u64) { + let mut watchers = self.watchers.write().await; + let items = watchers.get_mut(watch_key); + if let Some(vals) = items { + vals.remove(&watch_id); + } + } } #[async_trait::async_trait] @@ -65,7 +77,7 @@ impl ResourceListener for InstanceResourceListener { match ins_cache_opt { Some(ins_cache_val) => { for watcher in watchers { - (watcher.req.call_back)(ServiceInstancesChangeEvent { + (watcher.1.req.call_back)(ServiceInstancesChangeEvent { service: ins_cache_val.get_service_info(), instances: ins_cache_val.list_instances(false).await, }) @@ -85,6 +97,7 @@ impl ResourceListener for InstanceResourceListener { /// DefaultConsumerAPI pub struct DefaultConsumerAPI { + manage_sdk: bool, context: Arc, router_api: Box, // watchers: namespace#service -> InstanceWatcher @@ -94,11 +107,27 @@ pub struct DefaultConsumerAPI { } impl DefaultConsumerAPI { + pub fn new_raw(context: SDKContext) -> Self { + let ctx = Arc::new(context); + Self { + manage_sdk: true, + context: ctx.clone(), + router_api: Box::new(DefaultRouterAPI::new(ctx)), + watchers: Arc::new(InstanceResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), + watchers: Arc::new(RwLock::new(HashMap::new())), + }), + register_resource_watcher: AtomicBool::new(false), + } + } + pub fn new(context: Arc) -> Self { Self { + manage_sdk: true, context: context.clone(), router_api: Box::new(DefaultRouterAPI::new(context.clone())), watchers: Arc::new(InstanceResourceListener { + watcher_id: Arc::new(AtomicU64::new(0)), watchers: Arc::new(RwLock::new(HashMap::new())), }), register_resource_watcher: AtomicBool::new(false), @@ -106,6 +135,25 @@ impl DefaultConsumerAPI { } } +impl Drop for DefaultConsumerAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} + #[async_trait::async_trait] impl ConsumerAPI for DefaultConsumerAPI { async fn get_one_instance( @@ -128,18 +176,24 @@ impl ConsumerAPI for DefaultConsumerAPI { ) .await; + // 重新设置被调服务数据信息 + let mut route_info = req.route_info; + route_info.callee = ServiceKey{ + namespace: req.namespace.clone(), + name: req.service.clone(), + }; + match rsp { Ok(rsp) => { let instances = rsp.instances; - let criteria = req.caller_info.clone().criteria; + let criteria = req.criteria; // 执行路由逻辑 let route_ret = self .router_api .router(ProcessRouteRequest { service_instances: instances, - caller_info: req.caller_info, - callee_info: req.callee_info, + route_info: route_info, }) .await; @@ -224,10 +278,15 @@ impl ConsumerAPI for DefaultConsumerAPI { let mut watchers = self.watchers.watchers.write().await; let watch_key = req.get_key(); - let items = watchers.entry(watch_key.clone()).or_insert_with(Vec::new); - - items.push(InstanceWatcher { req }); - Ok(WatchInstanceResponse {}) + let items = watchers.entry(watch_key.clone()).or_insert(HashMap::new()); + let watch_id = self.watchers.watcher_id.fetch_add(1, Ordering::Relaxed); + + items.insert(watch_id, InstanceWatcher { req }); + Ok(WatchInstanceResponse::new( + watch_id, + watch_key, + self.watchers.clone(), + )) } async fn get_service_rule( @@ -248,21 +307,48 @@ pub struct DefaultProviderAPI where Self: Send + Sync, { - _manage_sdk: bool, + manage_sdk: bool, context: Arc, beat_tasks: Arc>>>, } impl DefaultProviderAPI { - pub fn new(context: Arc, manage_sdk: bool) -> Self { + pub fn new_raw(context: SDKContext) -> Self { + Self { + context: Arc::new(context), + manage_sdk: true, + beat_tasks: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub fn new(context: Arc) -> Self { Self { context, - _manage_sdk: manage_sdk, + manage_sdk: false, beat_tasks: Arc::new(RwLock::new(HashMap::new())), } } } +impl Drop for DefaultProviderAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} + #[async_trait::async_trait] impl ProviderAPI for DefaultProviderAPI { async fn register( @@ -272,12 +358,12 @@ impl ProviderAPI for DefaultProviderAPI { let auto_heartbeat = req.auto_heartbeat; let ttl = req.ttl; let beat_req = req.to_heartbeat_request(); - tracing::info!("[polaris][discovery][provider] register instance request: {req:?}"); + crate::info!("[polaris][discovery][provider] register instance request: {req:?}"); let rsp = self.context.get_engine().register_instance(req).await; let engine = self.context.get_engine(); if rsp.is_ok() && auto_heartbeat { let task_key = beat_req.beat_key(); - tracing::info!( + crate::info!( "[polaris][discovery][heartbeat] add one auto_beat task={} duration={}s", task_key, ttl, @@ -287,12 +373,12 @@ impl ProviderAPI for DefaultProviderAPI { let handler = engine.get_executor().spawn(async move { loop { tokio::time::sleep(tokio::time::Duration::from_secs(u64::from(ttl))).await; - tracing::debug!( + crate::debug!( "[polaris][discovery][heartbeat] start to auto_beat instance: {beat_req:?}" ); let beat_ret = beat_engine.instance_heartbeat(beat_req.clone()).await; if let Err(e) = beat_ret { - tracing::error!( + crate::error!( "[polaris][discovery][heartbeat] auto_beat instance to server fail: {e}" ); } @@ -308,7 +394,7 @@ impl ProviderAPI for DefaultProviderAPI { let task_key = beat_req.beat_key(); let wait_remove_task = self.beat_tasks.write().await.remove(&task_key); if let Some(task) = wait_remove_task { - tracing::info!( + crate::info!( "[polaris][discovery][heartbeat] remove one auto_beat task={}", task_key, ); diff --git a/src/discovery/req.rs b/src/discovery/req.rs index b7a3be3..ec78b03 100644 --- a/src/discovery/req.rs +++ b/src/discovery/req.rs @@ -17,14 +17,18 @@ use prost::Message; use crate::core::model::cache::EventType; use crate::core::model::error::{ErrorCode, PolarisError}; +use crate::core::model::loadbalance::Criteria; use crate::core::model::naming::{ - Instance, Location, ServiceInstances, ServiceInstancesChangeEvent, + Instance, Location, ServiceContract, ServiceInstances, ServiceInstancesChangeEvent, }; -use crate::core::model::router::{CalleeInfo, CallerInfo}; +use crate::core::model::router::RouteInfo; +use std::any::Any; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; +use super::default::InstanceResourceListener; + #[derive(Clone, Debug)] pub struct InstanceRegisterRequest { pub flow_id: String, @@ -193,7 +197,11 @@ impl InstanceHeartbeatRequest { } } -pub struct ReportServiceContractRequest {} +pub struct ReportServiceContractRequest { + pub flow_id: String, + pub timeout: Duration, + pub contract: ServiceContract, +} // ConsumerAPI request and response definition @@ -202,8 +210,10 @@ pub struct GetOneInstanceRequest { pub timeout: Duration, pub service: String, pub namespace: String, - pub caller_info: CallerInfo, - pub callee_info: CalleeInfo, + // 用于负载均衡 + pub criteria: Criteria, + // 用于路由 + pub route_info: RouteInfo, } impl GetOneInstanceRequest { @@ -319,7 +329,27 @@ impl WatchInstanceRequest { } } -pub struct WatchInstanceResponse {} +pub struct WatchInstanceResponse { + pub watch_id: u64, + watch_key: String, + owner: Arc, +} + +impl WatchInstanceResponse { + pub fn new(watch_id: u64, watch_key: String, owner: Arc) -> Self { + WatchInstanceResponse { + watch_id, + watch_key, + owner, + } + } + + pub async fn cancel_watch(&self) { + self.owner + .cancel_watch(&self.watch_key, self.watch_id) + .await; + } +} pub struct ServiceCallResult {} @@ -351,7 +381,7 @@ pub struct GetServiceRuleRequest { } pub struct ServiceRuleResponse { - pub rules: Vec>, + pub rules: Vec>, } // LossLessAPI request and response definition diff --git a/src/lib.rs b/src/lib.rs index a48c70b..cf23cd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,8 @@ pub mod discovery; pub mod plugins; pub mod ratelimit; pub mod router; +#[macro_use] +mod macros; #[cfg(test)] mod tests { @@ -57,10 +59,10 @@ mod tests { setup_log(); let start_time = std::time::Instant::now(); let provider_ret = new_provider_api(); - tracing::info!("create provider cost: {:?}", start_time.elapsed()); + info!("create provider cost: {:?}", start_time.elapsed()); match provider_ret { Err(err) => { - tracing::error!("create provider fail: {}", err.to_string()); + error!("create provider fail: {}", err.to_string()); } Ok(provier) => { let metadata = HashMap::new(); @@ -93,7 +95,7 @@ mod tests { let _ret = provier.register(req).await; match _ret { Err(err) => { - tracing::error!("register fail: {}", err.to_string()); + error!("register fail: {}", err.to_string()); } Ok(_) => {} } @@ -135,7 +137,7 @@ mod tests { let _ret = arc_provider.clone().deregister(deregister_req).await; match _ret { Err(err) => { - tracing::error!("deregister fail: {}", err.to_string()); + error!("deregister fail: {}", err.to_string()); } Ok(_) => {} } diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..c0eae4f --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,50 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#[macro_export] +macro_rules! trace { + ($($arg:tt)*) => {{ + $crate::core::logger::logger::log(tracing::Level::TRACE, &format!($($arg)*)); + }} +} + +#[macro_export] +macro_rules! debug { + ($($arg:tt)*) => {{ + $crate::core::logger::logger::log(tracing::Level::DEBUG, &format!($($arg)*)); + }} +} + +#[macro_export] +macro_rules! info { + ($($arg:tt)*) => {{ + $crate::core::logger::logger::log(tracing::Level::INFO, &format!($($arg)*)); + }} +} + +#[macro_export] +macro_rules! warn { + ($($arg:tt)*) => {{ + $crate::core::logger::logger::log(tracing::Level::WARN,&format!($($arg)*)); + }} +} + +#[macro_export] +macro_rules! error { + ($($arg:tt)*) => {{ + $crate::core::logger::logger::log(tracing::Level::ERROR, &format!($($arg)*)); + }} +} + diff --git a/src/plugins/cache/memory/failover.rs b/src/plugins/cache/memory/failover.rs new file mode 100644 index 0000000..91fb679 --- /dev/null +++ b/src/plugins/cache/memory/failover.rs @@ -0,0 +1,292 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use polaris_specification::v1::{ + config_discover_response::ConfigDiscoverResponseType, discover_response::DiscoverResponseType, + ConfigDiscoverResponse, DiscoverResponse, +}; +use prost::Message; +use tokio::{ + fs::File, + io::{AsyncReadExt, AsyncWriteExt}, +}; + +use crate::core::{ + config::global::LocalCacheConfig, + model::{ + cache::EventType, + error::{ErrorCode, PolarisError}, + }, + plugin::cache::{Filter, ResourceCacheFailover}, +}; + +pub struct DiskCacheFailover { + conf: LocalCacheConfig, +} + +impl DiskCacheFailover { + pub fn new(conf: LocalCacheConfig) -> Self { + Self { conf } + } +} + +#[async_trait::async_trait] +impl ResourceCacheFailover for DiskCacheFailover { + // failover_naming_load 兜底加载 + async fn failover_naming_load(&self, filter: Filter) -> Result { + let mut persist_file = self.conf.persist_dir.clone(); + let event_type = filter.get_event_type(); + let resource_key = filter.resource_key; + match event_type { + EventType::Service => { + persist_file = format!( + "{}/svc#{}#services.data", + persist_file, + resource_key.namespace.clone(), + ); + } + EventType::Instance + | EventType::RouterRule + | EventType::LaneRule + | EventType::CircuitBreakerRule + | EventType::FaultDetectRule + | EventType::RateLimitRule => { + persist_file = format!( + "{}/svc#{}#{}#{}", + persist_file, + resource_key.namespace.clone(), + resource_key.filter["service"].clone(), + event_type.to_persist_file(), + ); + } + _ => { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("unsupported event type"), + )); + } + } + + let ret = File::open(persist_file.clone()).await; + match ret { + Ok(mut file) => { + let mut buf = Vec::new(); + let ret = file.read_to_end(&mut buf).await; + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("read file:{:?} error: {:?}", persist_file, e), + )); + } + let ret = DiscoverResponse::decode(buf.as_slice()); + match ret { + Ok(value) => Ok(value), + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("decode file:{:?} error: {:?}", persist_file, e), + )), + } + } + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("open file:{:?} error: {:?}", persist_file, e), + )), + } + } + + // save_failover 保存容灾数据 + async fn save_naming_failover(&self, value: DiscoverResponse) -> Result<(), PolarisError> { + let mut buf = Vec::new(); + let mut persist_file = self.conf.persist_dir.clone(); + let svc = value.service.clone().unwrap(); + + match value.r#type().clone() { + polaris_specification::v1::discover_response::DiscoverResponseType::Services => { + persist_file = format!( + "{}/svc#{}#services.data", + persist_file, + svc.namespace.clone().unwrap() + ); + } + DiscoverResponseType::Instance + | DiscoverResponseType::Routing + | DiscoverResponseType::RateLimit + | DiscoverResponseType::CircuitBreaker + | DiscoverResponseType::FaultDetector + | DiscoverResponseType::Lane => { + persist_file = format!( + "{}/svc#{}#{}#{}", + persist_file, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap(), + EventType::naming_spec_to_persist_file(value.r#type().clone()) + ); + } + _ => { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("unsupported discover response type"), + )); + } + } + + let ret = DiscoverResponse::encode(&value, &mut buf); + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("encode discover response error: {:?}", e), + )); + } + + match File::create(persist_file).await { + Ok(mut file) => { + let ret = file.write_all(buf.as_slice()).await; + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("write file error: {:?}", e), + )); + } + Ok(()) + } + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("create file error: {:?}", e), + )), + } + } + + // failover_config_load 兜底加载 + async fn failover_config_load( + &self, + filter: Filter, + ) -> Result { + let mut persist_file = self.conf.persist_dir.clone(); + let event_type = filter.get_event_type(); + let resource_key = filter.resource_key; + match event_type { + EventType::ConfigFile => { + persist_file = format!( + "{}/config#{}#{}#{}#config_file.data", + persist_file, + resource_key.namespace.clone(), + resource_key.filter["group"].clone(), + resource_key.filter["file"].clone(), + ); + } + EventType::ConfigGroup => { + persist_file = format!( + "{}/config#{}#{}#config_group.data", + persist_file, + resource_key.namespace.clone(), + resource_key.filter["group"].clone(), + ); + } + _ => { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("unsupported event type"), + )); + } + } + + let ret = File::open(persist_file.clone()).await; + match ret { + Ok(mut file) => { + let mut buf = Vec::new(); + let ret = file.read_to_end(&mut buf).await; + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("read file:{:?} error: {:?}", persist_file, e), + )); + } + let ret = ConfigDiscoverResponse::decode(buf.as_slice()); + match ret { + Ok(value) => Ok(value), + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("decode file:{:?} error: {:?}", persist_file, e), + )), + } + } + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("open file:{:?} error: {:?}", persist_file, e), + )), + } + } + + // save_config_failover 保存容灾数据 + async fn save_config_failover( + &self, + value: ConfigDiscoverResponse, + ) -> Result<(), PolarisError> { + let mut buf = Vec::new(); + let mut persist_file = self.conf.persist_dir.clone(); + let conf = value.config_file.clone().unwrap(); + + match value.r#type().clone() { + ConfigDiscoverResponseType::ConfigFile => { + persist_file = format!( + "{}/config#{}#{}#{}#config_file.data", + persist_file, + conf.namespace.clone().unwrap(), + conf.group.clone().unwrap(), + conf.file_name.clone().unwrap(), + ); + } + ConfigDiscoverResponseType::ConfigFileNames => { + persist_file = format!( + "{}/config#{}#{}#config_group.data", + persist_file, + conf.namespace.clone().unwrap(), + conf.group.clone().unwrap(), + ); + } + _ => { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("unsupported config response type"), + )); + } + } + + let ret = ConfigDiscoverResponse::encode(&value, &mut buf); + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("encode config response error: {:?}", e), + )); + } + + match File::create(persist_file).await { + Ok(mut file) => { + let ret = file.write_all(buf.as_slice()).await; + if let Err(e) = ret { + return Err(PolarisError::new( + ErrorCode::InternalError, + format!("write file error: {:?}", e), + )); + } + Ok(()) + } + Err(e) => Err(PolarisError::new( + ErrorCode::InternalError, + format!("create file error: {:?}", e), + )), + } + } +} diff --git a/src/plugins/cache/memory/memory.rs b/src/plugins/cache/memory/memory.rs index 36b93f9..a3326bb 100644 --- a/src/plugins/cache/memory/memory.rs +++ b/src/plugins/cache/memory/memory.rs @@ -27,14 +27,20 @@ use crate::core::model::config::{ConfigFile, ConfigGroup}; use crate::core::model::error::{ErrorCode, PolarisError}; use crate::core::model::naming::{Instance, ServiceRule, Services}; use crate::core::plugin::cache::{ - Action, Filter, InitResourceCacheOption, ResourceCache, ResourceListener, + Action, Filter, InitResourceCacheOption, ResourceCache, ResourceCacheFailover, ResourceListener, }; use crate::core::plugin::connector::{Connector, ResourceHandler}; use crate::core::plugin::plugins::Plugin; +use std::any::Any; use std::collections::HashMap; use std::sync::Arc; +use crate::{error, info}; +use super::failover::DiskCacheFailover; + +static MEMORY_CACHE_NAME: &str = "memory"; struct MemoryResourceHandler { + failover: Option>, // 资源类型变化监听 listeners: Arc>>>>, // services 服务列表缓存 @@ -61,6 +67,8 @@ pub struct MemoryCache { server_connector: Arc>, handler: Arc, remote_sender: UnboundedSender, + // + failover: Option>, } impl MemoryCache { @@ -68,7 +76,7 @@ impl MemoryCache { fn(InitResourceCacheOption) -> Box, String, ) { - (new_resource_cache, "memory".to_string()) + (new_resource_cache, MEMORY_CACHE_NAME.to_string()) } async fn run_remote_data_recive( @@ -88,7 +96,7 @@ impl MemoryCache { fn submit_resource_watch(&self, event_type: EventType, resource_key: ResourceEventKey) { let search_namespace = resource_key.namespace.clone(); - tracing::info!( + info!( "[polaris][resource_cache][memory] load remote resource: {:?}", resource_key ); @@ -107,7 +115,7 @@ impl MemoryCache { ))) .await; if register_ret.is_err() { - tracing::error!( + error!( "[polaris][resource_cache][memory] register resource handler failed: {}, err: {}", resource_key.namespace.clone(), register_ret.err().unwrap() @@ -117,7 +125,7 @@ impl MemoryCache { } async fn on_spec_event(handler: Arc, event: RemoteData) { - tracing::info!( + info!( "[polaris][resource_cache][memory] on spec event: {:?}", event ); @@ -130,6 +138,8 @@ impl MemoryCache { let event_type = event_key.event_type; let filter = event_key.filter; + let copy_event = event.clone(); + match event_type { EventType::Service => {} EventType::Instance => { @@ -145,7 +155,7 @@ impl MemoryCache { .as_str(), ); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] service_instance cache not found: namespace={} service={}", svc.namespace.unwrap(), svc.name.unwrap() @@ -178,7 +188,7 @@ impl MemoryCache { .as_str(), ); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] router_rule cache not found: namespace={} service={}", svc.namespace.unwrap(), svc.name.unwrap() @@ -208,7 +218,7 @@ impl MemoryCache { .as_str(), ); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] circuit_breaker cache not found: namespace={} service={}", svc.namespace.unwrap(), svc.name.unwrap() @@ -237,7 +247,7 @@ impl MemoryCache { .as_str(), ); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] ratelimit cache not found: namespace={} service={}", svc.namespace.unwrap(), svc.name.unwrap() @@ -266,7 +276,7 @@ impl MemoryCache { .as_str(), ); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] fault_detect cache not found: namespace={} service={}", svc.namespace.unwrap(), svc.name.unwrap() @@ -293,7 +303,7 @@ impl MemoryCache { let mut safe_map = handler.config_files.write().await; let cache_val_opt = safe_map.get_mut(search_key.as_str()); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] config_file cache not found: namespace={} group={} file={}", event_key.namespace.clone(), filter.get("group").unwrap(), @@ -321,7 +331,7 @@ impl MemoryCache { let mut safe_map = handler.config_groups.write().await; let cache_val_opt = safe_map.get_mut(search_key.as_str()); if cache_val_opt.is_none() { - tracing::error!( + error!( "[polaris][resource_cache][memory] config_group cache not found: namespace={} group={}", event_key.namespace.clone(), filter.get("group").unwrap() @@ -343,6 +353,24 @@ impl MemoryCache { _ => {} } + // 容灾调用 + if copy_event.discover_value.is_some() { + let _ = handler + .failover + .clone() + .unwrap() + .save_naming_failover(copy_event.discover_value.unwrap()) + .await; + } + if copy_event.config_value.is_some() { + let _ = handler + .failover + .clone() + .unwrap() + .save_config_failover(copy_event.config_value.unwrap()) + .await; + } + // 通知所有的 listener let listeners = { handler.listeners.read().await.clone() }; let expect_watcher_opt = listeners.get(&event_type); @@ -359,11 +387,13 @@ impl MemoryCache { fn new_resource_cache(opt: InitResourceCacheOption) -> Box { let (sx, mut rx) = mpsc::unbounded_channel::(); let server_connector = opt.server_connector.clone(); + let failover = Arc::new(DiskCacheFailover::new(opt.conf.clone())); let mc = MemoryCache { opt, server_connector, handler: Arc::new(MemoryResourceHandler { + failover: Some(failover.clone()), listeners: Arc::new(RwLock::new(HashMap::new())), services: Arc::new(RwLock::new(HashMap::new())), instances: Arc::new(RwLock::new(HashMap::new())), @@ -375,6 +405,8 @@ fn new_resource_cache(opt: InitResourceCacheOption) -> Box { config_files: Arc::new(RwLock::new(HashMap::new())), }), remote_sender: sx, + // 默认使用磁盘容灾 + failover: Some(failover), }; let handler = mc.handler.clone(); @@ -391,12 +423,16 @@ impl Plugin for MemoryCache { fn destroy(&self) {} fn name(&self) -> String { - "memory".to_string() + MEMORY_CACHE_NAME.to_string() } } #[async_trait::async_trait] impl ResourceCache for MemoryCache { + fn set_failover_provider(&mut self, failover: Arc) { + self.failover = Some(failover); + } + async fn load_service_rule(&self, filter: Filter) -> Result { let event_type = filter.get_event_type(); let search_namespace = filter.resource_key.namespace.clone(); @@ -436,7 +472,7 @@ impl ResourceCache for MemoryCache { let mut rules = vec![]; for (_, val) in cache_val.value.read().await.iter().enumerate() { - rules.push(Box::new(val.clone()) as Box); + rules.push(Box::new(val.clone()) as Box); } Ok(ServiceRule { rules, @@ -475,7 +511,7 @@ impl ResourceCache for MemoryCache { } Ok(ServiceRule { - rules: vec![Box::new(cache_val.value.clone()) as Box], + rules: vec![Box::new(cache_val.value.clone()) as Box], revision: cache_val.revision(), initialized: cache_val.is_initialized(), }) @@ -511,7 +547,7 @@ impl ResourceCache for MemoryCache { } Ok(ServiceRule { - rules: vec![Box::new(cache_val.value.clone()) as Box], + rules: vec![Box::new(cache_val.value.clone()) as Box], revision: cache_val.revision(), initialized: cache_val.is_initialized(), }) @@ -547,7 +583,7 @@ impl ResourceCache for MemoryCache { } Ok(ServiceRule { - rules: vec![Box::new(cache_val.value.clone()) as Box], + rules: vec![Box::new(cache_val.value.clone()) as Box], revision: cache_val.revision(), initialized: cache_val.is_initialized(), }) @@ -730,6 +766,7 @@ impl ResourceCache for MemoryCache { namespace: cache_val.namespace.clone(), group: cache_val.group.clone(), files: cache_val.files.read().await.clone(), + revision: cache_val.revision.clone(), }; Ok(ret) @@ -744,6 +781,7 @@ impl ResourceCache for MemoryCache { } } +/// MemoryResourceWatcher 用于监听远程资源变化 struct MemoryResourceWatcher { event_key: ResourceEventKey, processor: UnboundedSender, @@ -763,7 +801,7 @@ impl ResourceHandler for MemoryResourceWatcher { match self.processor.send(event) { Ok(_) => {} Err(err) => { - tracing::error!( + error!( "[polaris][resource_cache][memory] send event to processor failed: {}", err ); diff --git a/src/plugins/cache/memory/mod.rs b/src/plugins/cache/memory/mod.rs index 4a2b5be..97b0c75 100644 --- a/src/plugins/cache/memory/mod.rs +++ b/src/plugins/cache/memory/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. +pub mod failover; pub mod memory; diff --git a/src/plugins/circuitbreaker/composite/circuitbreaker.rs b/src/plugins/circuitbreaker/composite/circuitbreaker.rs new file mode 100644 index 0000000..b0d79f2 --- /dev/null +++ b/src/plugins/circuitbreaker/composite/circuitbreaker.rs @@ -0,0 +1,67 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::{ + model::{ + circuitbreaker::{CircuitBreakerStatus, Resource, ResourceStat, Status}, + error::PolarisError, + }, + plugin::{circuitbreaker::CircuitBreaker, plugins::Plugin}, +}; + +static PLUGIN_NAME: &str = "composite"; + +fn new_circuir_breaker() -> Box { + Box::new(CompositeCircuitBreaker {}) +} + +pub struct CompositeCircuitBreaker {} + +impl CompositeCircuitBreaker { + pub fn builder() -> (fn() -> Box, String) { + (new_circuir_breaker, PLUGIN_NAME.to_string()) + } +} + +impl Plugin for CompositeCircuitBreaker { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + PLUGIN_NAME.to_string() + } +} + +#[async_trait::async_trait] +impl CircuitBreaker for CompositeCircuitBreaker { + /// check_resource 检查资源 + async fn check_resource( + &self, + resource: Resource, + ) -> Result { + Ok(CircuitBreakerStatus { + status: Status::Close, + start_ms: 0, + circuit_breaker: "".to_string(), + fallback_info: None, + destroy: false, + }) + } + /// report_stat 上报统计信息 + async fn report_stat(&self, stat: ResourceStat) -> Result<(), PolarisError> { + todo!() + } +} diff --git a/src/plugins/circuitbreaker/composite/mod.rs b/src/plugins/circuitbreaker/composite/mod.rs new file mode 100644 index 0000000..88e0510 --- /dev/null +++ b/src/plugins/circuitbreaker/composite/mod.rs @@ -0,0 +1,17 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +pub mod circuitbreaker; +pub mod trigger; diff --git a/src/plugins/router/health/router.rs b/src/plugins/circuitbreaker/composite/trigger/mod.rs similarity index 100% rename from src/plugins/router/health/router.rs rename to src/plugins/circuitbreaker/composite/trigger/mod.rs diff --git a/src/plugins/circuitbreaker/mod.rs b/src/plugins/circuitbreaker/mod.rs new file mode 100644 index 0000000..43d5f5f --- /dev/null +++ b/src/plugins/circuitbreaker/mod.rs @@ -0,0 +1,16 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +pub mod composite; diff --git a/src/plugins/connector/grpc/connector.rs b/src/plugins/connector/grpc/connector.rs index 6de6aa9..accfac0 100644 --- a/src/plugins/connector/grpc/connector.rs +++ b/src/plugins/connector/grpc/connector.rs @@ -18,20 +18,23 @@ use crate::core::model::cache::{EventType, RemoteData}; use crate::core::model::config::{ConfigFileRequest, ConfigPublishRequest, ConfigReleaseRequest}; use crate::core::model::error::ErrorCode::{ServerError, ServerUserError}; use crate::core::model::error::PolarisError; -use crate::core::model::naming::{InstanceRequest, InstanceResponse}; -use crate::core::model::pb::lib::polaris_config_grpc_client::PolarisConfigGrpcClient; -use crate::core::model::pb::lib::polaris_grpc_client::PolarisGrpcClient; -use crate::core::model::pb::lib::Code::{ExecuteSuccess, ExistedResource}; -use crate::core::model::pb::lib::{ - Code, ConfigDiscoverRequest, ConfigDiscoverResponse, DiscoverRequest, DiscoverResponse, +use crate::core::model::naming::{ + InstanceRequest, InstanceResponse, ServiceContract, ServiceContractRequest, }; +use crate::core::model::ReportClientRequest; use crate::core::plugin::connector::{Connector, InitConnectorOption, ResourceHandler}; use crate::core::plugin::plugins::Plugin; +use polaris_specification::v1::polaris_config_grpc_client::PolarisConfigGrpcClient; +use polaris_specification::v1::polaris_grpc_client::PolarisGrpcClient; +use polaris_specification::v1::polaris_service_contract_grpc_client::PolarisServiceContractGrpcClient; +use polaris_specification::v1::Code::{ExecuteSuccess, ExistedResource}; +use polaris_specification::v1::{ + Code, ConfigDiscoverRequest, ConfigDiscoverResponse, DiscoverRequest, DiscoverResponse, +}; use std::cmp::PartialEq; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; -use std::thread::sleep; use std::time::Duration; use tokio::runtime::Runtime; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; @@ -44,19 +47,20 @@ use tonic::service::Interceptor; use tonic::transport::{Channel, Endpoint}; use tonic::Streaming; use tracing::Instrument; +use crate::{debug, error, info}; struct ResourceHandlerWrapper { handler: Box, revision: String, } +static PLUGIN_NAME: &str = "grpc"; + #[derive(Clone)] pub struct GrpcConnector { opt: InitConnectorOption, discover_channel: Channel, config_channel: Channel, - discover_grpc_client: PolarisGrpcClient, - config_grpc_client: PolarisConfigGrpcClient, discover_spec_sender: Arc>, config_spec_sender: Arc>, @@ -68,9 +72,6 @@ fn new_connector(opt: InitConnectorOption) -> Box { let conf = &opt.conf.global.server_connectors.clone(); let (discover_channel, config_channel) = create_channel(conf); - let discover_grpc_client = create_discover_grpc_client(discover_channel.clone()); - let config_grpc_client = create_config_grpc_client(config_channel.clone()); - let (discover_sender, mut discover_reciver) = run_discover_spec_stream(discover_channel.clone(), opt.runtime.clone()).unwrap(); @@ -81,8 +82,6 @@ fn new_connector(opt: InitConnectorOption) -> Box { opt, discover_channel: discover_channel.clone(), config_channel: config_channel.clone(), - discover_grpc_client, - config_grpc_client, discover_spec_sender: Arc::new(discover_sender), config_spec_sender: Arc::new(config_sender), @@ -102,7 +101,7 @@ fn new_connector(opt: InitConnectorOption) -> Box { } config_ret = config_reciver.recv() => { if config_ret.is_some() { - receive_c.receive_config_response(config_ret.unwrap()); + receive_c.receive_config_response(config_ret.unwrap()).await; } } } @@ -119,7 +118,7 @@ fn new_connector(opt: InitConnectorOption) -> Box { watch_resources.iter().for_each(|(_key, handler)| { let key = handler.handler.interest_resource(); let filter = key.clone().filter; - tracing::debug!( + debug!( "[polaris][discovery][connector] send discover request: {:?} filter: {:?}", key.clone(), filter.clone() @@ -135,7 +134,7 @@ fn new_connector(opt: InitConnectorOption) -> Box { } }); } - sleep(Duration::from_secs(2)); + tokio::time::sleep(Duration::from_secs(2)).await; } }); @@ -155,7 +154,7 @@ fn create_channel(conf: &ServerConnectorConfig) -> (Channel, Channel) { } } - tracing::info!( + info!( "[polaris][server_connector] discover_address: {:?} config_address: {:?}", discover_address, config_address @@ -180,27 +179,19 @@ fn create_channel(conf: &ServerConnectorConfig) -> (Channel, Channel) { (discover_channel, config_channel) } -fn create_discover_grpc_client(channel: Channel) -> PolarisGrpcClient { - PolarisGrpcClient::new(channel) -} - -fn create_config_grpc_client(channel: Channel) -> PolarisConfigGrpcClient { - PolarisConfigGrpcClient::new(channel) -} - impl Plugin for GrpcConnector { fn init(&mut self) {} fn destroy(&self) {} fn name(&self) -> String { - "grpc".to_string() + PLUGIN_NAME.to_string() } } impl GrpcConnector { pub fn builder() -> (fn(opt: InitConnectorOption) -> Box, String) { - (new_connector, "grpc".to_string()) + (new_connector, PLUGIN_NAME.to_string()) } fn create_discover_grpc_stub( @@ -234,7 +225,7 @@ impl GrpcConnector { async fn receive_discover_response(&self, resp: DiscoverResponse) { let remote_rsp = resp.clone(); if remote_rsp.code.unwrap() == Code::DataNoChange as u32 { - tracing::debug!( + debug!( "[polaris][discovery][connector] receive naming_discover no_change response: {:?}", resp ); @@ -242,7 +233,7 @@ impl GrpcConnector { } if remote_rsp.code.unwrap() != Code::ExecuteSuccess as u32 { - tracing::error!( + error!( "[polaris][discovery][connector] receive naming_discover failure response: {:?}", resp ); @@ -251,34 +242,64 @@ impl GrpcConnector { let mut watch_key = "".to_string(); match resp.r#type() { - crate::core::model::pb::lib::discover_response::DiscoverResponseType::Services => { + polaris_specification::v1::discover_response::DiscoverResponseType::Services => { watch_key = resp.service.unwrap().namespace.clone().unwrap(); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::Instance => { + } + polaris_specification::v1::discover_response::DiscoverResponseType::Instance => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::Instance, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::Routing => { + watch_key = format!( + "{:?}#{}#{}", + EventType::Instance, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + polaris_specification::v1::discover_response::DiscoverResponseType::Routing => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::RouterRule, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::RateLimit => { + watch_key = format!( + "{:?}#{}#{}", + EventType::RouterRule, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + polaris_specification::v1::discover_response::DiscoverResponseType::RateLimit => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::RateLimitRule, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::CircuitBreaker => { + watch_key = format!( + "{:?}#{}#{}", + EventType::RateLimitRule, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + polaris_specification::v1::discover_response::DiscoverResponseType::CircuitBreaker => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::CircuitBreakerRule, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::FaultDetector => { + watch_key = format!( + "{:?}#{}#{}", + EventType::CircuitBreakerRule, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + polaris_specification::v1::discover_response::DiscoverResponseType::FaultDetector => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::FaultDetectRule, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - crate::core::model::pb::lib::discover_response::DiscoverResponseType::Lane => { + watch_key = format!( + "{:?}#{}#{}", + EventType::FaultDetectRule, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + polaris_specification::v1::discover_response::DiscoverResponseType::Lane => { let svc = resp.service.unwrap().clone(); - watch_key = format!("{:?}#{}#{}", EventType::LaneRule, svc.namespace.clone().unwrap(), svc.name.clone().unwrap()); - }, - _ => {}, + watch_key = format!( + "{:?}#{}#{}", + EventType::LaneRule, + svc.namespace.clone().unwrap(), + svc.name.clone().unwrap() + ); + } + _ => {} } let mut handlers = self.watch_resources.write().await; if let Some(handle) = handlers.get_mut(watch_key.as_str()) { @@ -297,8 +318,8 @@ impl GrpcConnector { } } - fn receive_config_response(&self, mut resp: ConfigDiscoverResponse) { - tracing::info!( + async fn receive_config_response(&self, mut resp: ConfigDiscoverResponse) { + info!( "[polaris][config][connector] receive config_discover response: {:?}", resp ); @@ -313,7 +334,7 @@ impl GrpcConnector { resp = rsp.to_config_response(); } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] filter response_process fail: {}", err.to_string() ); @@ -322,11 +343,29 @@ impl GrpcConnector { } } + let remote_rsp = resp.clone(); + + let mut watch_key = "".to_string(); match resp.r#type() { - crate::core::model::pb::lib::config_discover_response::ConfigDiscoverResponseType::ConfigFile => todo!(), - crate::core::model::pb::lib::config_discover_response::ConfigDiscoverResponseType::ConfigFileNames => todo!(), - crate::core::model::pb::lib::config_discover_response::ConfigDiscoverResponseType::ConfigFileGroups => todo!(), - _ => todo!() + polaris_specification::v1::config_discover_response::ConfigDiscoverResponseType::ConfigFile => { + let ret = resp.config_file.unwrap().clone(); + watch_key = format!("{:?}#{}#{}#{}", EventType::ConfigFile, ret.namespace.clone().unwrap(), + ret.group.clone().unwrap(), ret.file_name.clone().unwrap()); + }, + polaris_specification::v1::config_discover_response::ConfigDiscoverResponseType::ConfigFileNames => { + let ret = resp.config_file.unwrap().clone(); + watch_key = format!("{:?}#{}#{}", EventType::ConfigGroup, ret.namespace.clone().unwrap(), + ret.group.clone().unwrap()); + }, + polaris_specification::v1::config_discover_response::ConfigDiscoverResponseType::ConfigFileGroups => { + error!("[polaris][config][connector] not support ConfigFileGroups"); + }, + _ => {} + } + + let mut handlers = self.watch_resources.write().await; + if let Some(handle) = handlers.get_mut(watch_key.as_str()) { + handle.revision = remote_rsp.revision.clone(); } } @@ -345,7 +384,7 @@ impl GrpcConnector { req = rsp.to_config_request(); } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] filter request_process fail: {}", err.to_string() ); @@ -353,6 +392,20 @@ impl GrpcConnector { } } } + + // 添加客户端标签,用于配置灰度发布读取 + let mut file = req.config_file.unwrap(); + let mut client_tags = Vec::::new(); + let client_labels = self.opt.client_ctx.labels.clone(); + for (k, v) in client_labels.iter() { + client_tags.push(polaris_specification::v1::ConfigFileTag { + key: Some(k.clone()), + value: Some(v.clone()), + }); + } + file.tags = client_tags; + req.config_file = Some(file); + let _ = self.config_spec_sender.send(req); } } @@ -396,7 +449,7 @@ impl Connector for GrpcConnector { self.send_config_discover_request(config_request.unwrap()); } - tracing::info!( + info!( "[polaris][discovery][connector] register resource handler: {}", watch_key_str.clone() ); @@ -407,7 +460,7 @@ impl Connector for GrpcConnector { &self, req: InstanceRequest, ) -> Result { - tracing::debug!("[polaris][discovery][connector] send register instance request={req:?}"); + debug!("[polaris][discovery][connector] send register instance request={req:?}"); let mut client = self.create_discover_grpc_stub(req.flow_id.clone()); let ret = client @@ -426,7 +479,7 @@ impl Connector for GrpcConnector { let recv_code: Code = unsafe { std::mem::transmute(rsp.code.unwrap()) }; if ExecuteSuccess.eq(&recv_code) { let ins_id = rsp.instance.unwrap().id.unwrap(); - tracing::info!( + info!( "[polaris][discovery][connector] register instance to server success id={}", ins_id.clone(), ); @@ -440,7 +493,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][discovery][connector] send register request to server fail: {}", err ); @@ -450,7 +503,7 @@ impl Connector for GrpcConnector { } async fn deregister_instance(&self, req: InstanceRequest) -> Result { - tracing::debug!("[polaris][discovery][connector] send deregister instance request={req:?}"); + debug!("[polaris][discovery][connector] send deregister instance request={req:?}"); let mut client = self.create_discover_grpc_stub(req.flow_id.clone()); let ret = client @@ -464,7 +517,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][discovery][connector] send deregister request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -472,7 +525,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][discovery][connector] send deregister request to server fail: {}", err ); @@ -482,7 +535,7 @@ impl Connector for GrpcConnector { } async fn heartbeat_instance(&self, req: InstanceRequest) -> Result { - tracing::debug!( + debug!( "[polaris][discovery][connector] send heartbeat instance request={:?}", req.convert_beat_spec() ); @@ -499,7 +552,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][discovery][connector] send heartbeat request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -507,7 +560,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][discovery][connector] send heartbeat request to server fail: {}", err ); @@ -516,20 +569,67 @@ impl Connector for GrpcConnector { }; } - async fn report_client(&self) -> Result { + async fn report_client(&self, req: ReportClientRequest) -> Result { todo!() } - async fn report_service_contract(&self) -> Result { - todo!() + async fn report_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result { + debug!( + "[polaris][discovery][connector] send report service_contract request={req:?}" + ); + + let interceptor = GrpcConnectorInterceptor { + metadata: { + let mut metadata = HashMap::new(); + metadata.insert("request-id".to_string(), req.flow_id.to_string()); + metadata + }, + }; + + let mut client = PolarisServiceContractGrpcClient::with_interceptor( + self.discover_channel.clone(), + interceptor, + ); + let ret = client + .report_service_contract(tonic::Request::new(req.contract.convert_spec())) + .in_current_span() + .await; + return match ret { + Ok(rsp) => { + let rsp = rsp.into_inner(); + let recv_code: Code = unsafe { std::mem::transmute(rsp.code.unwrap()) }; + if ExecuteSuccess.eq(&recv_code) { + return Ok(true); + } + error!( + "[polaris][discovery][connector] send report service_contract request to server receive fail: code={} info={}", + rsp.code.unwrap().clone(), + rsp.info.clone().unwrap(), + ); + Err(PolarisError::new(ServerError, rsp.info.unwrap())) + } + Err(err) => { + error!( + "[polaris][discovery][connector] send report service_contract request to server fail: {}", + err + ); + Err(PolarisError::new(ServerError, err.to_string())) + } + }; } - async fn get_service_contract(&self) -> Result { + async fn get_service_contract( + &self, + req: ServiceContractRequest, + ) -> Result { todo!() } async fn create_config_file(&self, req: ConfigFileRequest) -> Result { - tracing::debug!("[polaris][config][connector] send create config_file request={req:?}"); + debug!("[polaris][config][connector] send create config_file request={req:?}"); let mut client = self.create_config_grpc_stub(req.flow_id.clone()); let ret = client @@ -543,7 +643,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][config][connector] send create config_file request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -551,7 +651,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] send create config_file request to server fail: {}", err ); @@ -561,7 +661,7 @@ impl Connector for GrpcConnector { } async fn update_config_file(&self, req: ConfigFileRequest) -> Result { - tracing::debug!("[polaris][config][connector] send update config_file request={req:?}"); + debug!("[polaris][config][connector] send update config_file request={req:?}"); let mut client = self.create_config_grpc_stub(req.flow_id.clone()); let ret = client @@ -575,7 +675,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][config][connector] send update config_file request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -583,7 +683,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] send update config_file request to server fail: {}", err ); @@ -593,7 +693,7 @@ impl Connector for GrpcConnector { } async fn release_config_file(&self, req: ConfigReleaseRequest) -> Result { - tracing::debug!("[polaris][config][connector] send publish config_file request={req:?}"); + debug!("[polaris][config][connector] send publish config_file request={req:?}"); let mut client = self.create_config_grpc_stub(req.flow_id.clone()); let ret = client @@ -607,7 +707,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][config][connector] send publish config_file request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -615,7 +715,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] send publish config_file request to server fail: {}", err ); @@ -628,7 +728,7 @@ impl Connector for GrpcConnector { &self, req: ConfigPublishRequest, ) -> Result { - tracing::debug!( + debug!( "[polaris][config][connector] send upsert and publish config_file request={req:?}" ); @@ -644,7 +744,7 @@ impl Connector for GrpcConnector { if ExecuteSuccess.eq(&recv_code) { return Ok(true); } - tracing::error!( + error!( "[polaris][config][connector] send upsert and publish config_file request to server receive fail: code={} info={}", rsp.code.unwrap().clone(), rsp.info.clone().unwrap(), @@ -652,7 +752,7 @@ impl Connector for GrpcConnector { Err(PolarisError::new(ServerError, rsp.info.unwrap())) } Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] send upsert and publish config_file request to server fail: {}", err ); @@ -675,7 +775,7 @@ fn run_discover_spec_stream( let (discover_sender, rx) = mpsc::unbounded_channel::(); let (rsp_sender, rsp_recv) = mpsc::unbounded_channel::(); _ = executor.spawn(async move { - tracing::info!("[polaris][discovery][connector] start naming_discover grpc stream"); + info!("[polaris][discovery][connector] start naming_discover grpc stream"); let reciver = UnboundedReceiverStream::new(rx); let mut client = PolarisGrpcClient::new(channel); @@ -685,7 +785,7 @@ fn run_discover_spec_stream( let discover_rt = discover_future.await; if discover_rt.is_err() { let stream_err = discover_rt.err().unwrap(); - tracing::error!( + error!( "[polaris][discovery][connector] naming_discover stream receive err: {}", stream_err.clone().to_string() ); @@ -702,7 +802,7 @@ fn run_discover_spec_stream( match rsp_sender.send(rsp) { Ok(_) => {} Err(err) => { - tracing::error!( + error!( "[polaris][discovery][connector] send discover request receive fail: {}", err.to_string() ); @@ -710,7 +810,7 @@ fn run_discover_spec_stream( } } Err(err) => { - tracing::error!( + error!( "[polaris][discovery][connector] naming_discover stream receive err: {}", err.to_string() ); @@ -733,7 +833,7 @@ fn run_config_spec_stream( ), PolarisError, > { - tracing::info!("[polaris][config][connector] start config_discover grpc stream"); + info!("[polaris][config][connector] start config_discover grpc stream"); let (config_sender, config_reciver) = mpsc::unbounded_channel::(); let (rsp_sender, rsp_recv) = mpsc::unbounded_channel::(); _ = executor.spawn(async move { @@ -745,7 +845,7 @@ fn run_config_spec_stream( let discover_rt = discover_future.await; if discover_rt.is_err() { let stream_err = discover_rt.err().unwrap(); - tracing::error!( + error!( "[polaris][config][connector] config_discover stream receive err: {}", stream_err.clone().to_string() ); @@ -761,14 +861,14 @@ fn run_config_spec_stream( Ok(rsp) => match rsp_sender.send(rsp) { Ok(_) => {} Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] send config request receive fail: {}", err.to_string() ); } }, Err(err) => { - tracing::error!( + error!( "[polaris][config][connector] config_discover stream receive err: {}", err.to_string() ); diff --git a/src/plugins/filter/configcrypto/crypto.rs b/src/plugins/filter/configcrypto/crypto.rs index 0ff03e3..0c59aa9 100644 --- a/src/plugins/filter/configcrypto/crypto.rs +++ b/src/plugins/filter/configcrypto/crypto.rs @@ -18,13 +18,15 @@ use std::{ sync::{Arc, RwLock}, }; +use polaris_specification::v1::{ + config_discover_request::ConfigDiscoverRequestType, + config_discover_response::ConfigDiscoverResponseType, ConfigDiscoverRequest, +}; + use crate::core::{ model::{ + config::{get_encrypt_algo, get_encrypt_data_key}, error::PolarisError, - pb::lib::{ - config_discover_request::ConfigDiscoverRequestType, - config_discover_response::ConfigDiscoverResponseType, ConfigDiscoverRequest, - }, DiscoverRequestInfo, DiscoverResponseInfo, }, plugin::{filter::DiscoverFilter, plugins::Plugin}, @@ -35,6 +37,7 @@ use base64::{engine::general_purpose::STANDARD as base64_standard, Engine as _}; use block_modes::{block_padding::Pkcs7, BlockMode, Cbc}; use rsa::{pkcs1::EncodeRsaPublicKey, pkcs8::LineEnding, RsaPrivateKey, RsaPublicKey}; use serde::{Deserialize, Serialize}; +use crate::error; #[derive(Serialize, Deserialize)] pub struct CryptoConfig { @@ -75,7 +78,7 @@ fn load_cryptors(conf: CryptoConfig) -> HashMap> { repo.insert(name.to_string(), val.1); } None => { - tracing::error!( + error!( "[polaris][plugin][config_filter] crypto not found expect algo: {}", name ); @@ -162,25 +165,25 @@ impl DiscoverFilter for ConfigFileCryptoFilter { // 通过 rsa 将 data_key 解密 let encrypt_data_key = self .rsa_cryptor - .decrypt_from_base64(config_file.get_encrypt_data_key()); + .decrypt_from_base64(get_encrypt_data_key(&config_file)); let data_key: String; match encrypt_data_key { Ok(key) => { data_key = key; } Err(err) => { - tracing::error!( + error!( "[polaris][plugin][config_filter] cipher datakey use rsa decrypt fail: {}", err ); let u8_slice = base64_standard - .decode(config_file.get_encrypt_data_key()) + .decode(get_encrypt_data_key(&config_file)) .unwrap(); data_key = String::from_utf8(u8_slice).unwrap(); } } - let algo = config_file.get_encrypt_algo(); + let algo = get_encrypt_algo(&config_file); let repo = self.cryptors.read().unwrap(); let cryptor_opt = repo.get(&algo); diff --git a/src/plugins/loadbalance/random/random.rs b/src/plugins/loadbalance/random/random.rs index 627fd50..64a0290 100644 --- a/src/plugins/loadbalance/random/random.rs +++ b/src/plugins/loadbalance/random/random.rs @@ -20,12 +20,16 @@ use crate::core::{ }, plugin::{loadbalance::LoadBalancer, plugins::Plugin}, }; +use crate::debug; +static PLUGIN_NAME: &str = "weightedRandom"; + +/// WeightRandomLoadbalancer 权重随机负载均衡 pub struct WeightRandomLoadbalancer {} impl WeightRandomLoadbalancer { pub fn builder() -> (fn() -> Box, String) { - (new_instance, "weightedRandom".to_string()) + (new_instance, PLUGIN_NAME.to_string()) } } @@ -35,7 +39,7 @@ fn new_instance() -> Box { impl Plugin for WeightRandomLoadbalancer { fn name(&self) -> String { - "weightedRandom".to_string() + PLUGIN_NAME.to_string() } fn init(&mut self) {} @@ -69,7 +73,7 @@ impl LoadBalancer for WeightRandomLoadbalancer { left = right; } - tracing::debug!( + debug!( "[polaris][loadbalancer][weight_random] choose instance failed, rand_weight: {}", rand_weight ); diff --git a/src/plugins/loadbalance/ringhash/ringhash.rs b/src/plugins/loadbalance/ringhash/ringhash.rs index 4b501f5..037c6a4 100644 --- a/src/plugins/loadbalance/ringhash/ringhash.rs +++ b/src/plugins/loadbalance/ringhash/ringhash.rs @@ -24,8 +24,11 @@ use crate::core::{ plugin::{loadbalance::LoadBalancer, plugins::Plugin}, }; +static PLUGIN_NAME: &str = "ringHash"; + const DEFAULT_REPLICAS: usize = 5; +/// ConsistentHashLoadBalancer 一致性哈希负载均衡 pub struct ConsistentHashLoadBalancer { // 需要把 ring hash 进行一次缓存,避免重复构建 ring hash ring_hash_cache: Arc>>, @@ -33,7 +36,7 @@ pub struct ConsistentHashLoadBalancer { impl ConsistentHashLoadBalancer { pub fn builder() -> (fn() -> Box, String) { - (new_instance, "ringHash".to_string()) + (new_instance, PLUGIN_NAME.to_string()) } } @@ -45,7 +48,7 @@ fn new_instance() -> Box { impl Plugin for ConsistentHashLoadBalancer { fn name(&self) -> String { - "ringHash".to_string() + PLUGIN_NAME.to_string() } fn init(&mut self) {} diff --git a/src/plugins/loadbalance/roundrobin/roundrobin.rs b/src/plugins/loadbalance/roundrobin/roundrobin.rs index 31b0738..80ab05f 100644 --- a/src/plugins/loadbalance/roundrobin/roundrobin.rs +++ b/src/plugins/loadbalance/roundrobin/roundrobin.rs @@ -24,13 +24,16 @@ use crate::core::{ plugin::{loadbalance::LoadBalancer, plugins::Plugin}, }; +static PLUGIN_NAME: &str = "weightedRoundRobin"; + +/// WeightedRoundRobinBalancer 权重轮训负载均衡 pub struct WeightedRoundRobinBalancer { round_robin_cache: Arc>>, } impl WeightedRoundRobinBalancer { pub fn builder() -> (fn() -> Box, String) { - (new_instance, "weightedRoundRobin".to_string()) + (new_instance, PLUGIN_NAME.to_string()) } } @@ -42,7 +45,7 @@ fn new_instance() -> Box { impl Plugin for WeightedRoundRobinBalancer { fn name(&self) -> String { - "weightedRoundRobin".to_string() + PLUGIN_NAME.to_string() } fn init(&mut self) { diff --git a/src/plugins/location/local/local.rs b/src/plugins/location/local/local.rs index 5e0ae6c..ecdaafd 100644 --- a/src/plugins/location/local/local.rs +++ b/src/plugins/location/local/local.rs @@ -19,6 +19,8 @@ use crate::core::{ plugin::{location::LocationSupplier, plugins::Plugin}, }; +static PLUGIN_NAME: &str = "local"; + pub struct LocalLocationSupplier { loc_cache: Location, } @@ -51,7 +53,7 @@ impl Plugin for LocalLocationSupplier { fn destroy(&self) {} fn name(&self) -> String { - "local".to_string() + PLUGIN_NAME.to_string() } } diff --git a/src/plugins/location/remotehttp/remotehttp.rs b/src/plugins/location/remotehttp/remotehttp.rs index c68d2d5..d43042e 100644 --- a/src/plugins/location/remotehttp/remotehttp.rs +++ b/src/plugins/location/remotehttp/remotehttp.rs @@ -20,9 +20,12 @@ use crate::core::{ }; use reqwest::blocking::Client; +use crate::error; + +static PLUGIN_NAME: &str = "remotehttp"; pub struct RemoteHttpLocationSupplier { - opt: LocationProviderConfig, + _opt: LocationProviderConfig, access_url: Location, } @@ -48,7 +51,7 @@ impl RemoteHttpLocationSupplier { } Self { - opt, + _opt: opt, access_url: loc_ret, } } @@ -60,7 +63,7 @@ impl Plugin for RemoteHttpLocationSupplier { fn destroy(&self) {} fn name(&self) -> String { - "remotehttp".to_string() + PLUGIN_NAME.to_string() } } @@ -81,7 +84,7 @@ impl LocationSupplier for RemoteHttpLocationSupplier { ); if region.is_empty() && zone.is_empty() && campus.is_empty() { - tracing::error!("get location from remote http: all location is empty") + error!("get location from remote http: all location is empty") } Location { @@ -102,13 +105,13 @@ impl RemoteHttpLocationSupplier { match ret { Ok(body) => body, Err(e) => { - tracing::error!("get http response error: {}, label: {}", e, label); + error!("get http response error: {}, label: {}", e, label); "".to_string() } } } Err(e) => { - tracing::error!("get http response error: {}, label: {}", e, label); + error!("get http response error: {}, label: {}", e, label); "".to_string() } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ea6a59a..71a4ea6 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -14,8 +14,10 @@ // specific language governing permissions and limitations under the License. pub mod cache; +pub mod circuitbreaker; pub mod connector; pub mod filter; pub mod loadbalance; pub mod location; +pub mod ratelimit; pub mod router; diff --git a/src/plugins/ratelimit/concurrency/concurrency.rs b/src/plugins/ratelimit/concurrency/concurrency.rs new file mode 100644 index 0000000..b6e6e0c --- /dev/null +++ b/src/plugins/ratelimit/concurrency/concurrency.rs @@ -0,0 +1,66 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::{ + model::error::PolarisError, + plugin::{plugins::Plugin, ratelimit::ServiceRateLimiter}, +}; + +static PLUGIN_NAME: &str = "concurrency"; + +pub struct ConcurrencyLimiter {} + +impl ConcurrencyLimiter { + pub fn builder() -> (fn() -> Box, String) { + (new_instance, PLUGIN_NAME.to_string()) + } +} + +fn new_instance() -> Box { + Box::new(ConcurrencyLimiter {}) +} + +impl Plugin for ConcurrencyLimiter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + PLUGIN_NAME.to_string() + } +} + +#[async_trait::async_trait] +impl ServiceRateLimiter for ConcurrencyLimiter { + async fn allocate_quota(&self) -> Result<(), PolarisError> { + Ok(()) + } + + async fn return_quota(&self) -> Result<(), PolarisError> { + Ok(()) + } + + async fn on_remote_update(&self) -> Result<(), PolarisError> { + Ok(()) + } + + async fn fetch_local_usage(&self) -> Result<(), PolarisError> { + Ok(()) + } + + async fn get_amount(&self) -> Result<(), PolarisError> { + Ok(()) + } +} diff --git a/src/plugins/ratelimit/concurrency/mod.rs b/src/plugins/ratelimit/concurrency/mod.rs new file mode 100644 index 0000000..3dff673 --- /dev/null +++ b/src/plugins/ratelimit/concurrency/mod.rs @@ -0,0 +1,16 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +pub mod concurrency; \ No newline at end of file diff --git a/src/plugins/ratelimit/mod.rs b/src/plugins/ratelimit/mod.rs new file mode 100644 index 0000000..2f978d5 --- /dev/null +++ b/src/plugins/ratelimit/mod.rs @@ -0,0 +1,18 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +pub mod concurrency; +pub mod reject; +pub mod unirate; diff --git a/src/plugins/router/isolated/mod.rs b/src/plugins/ratelimit/reject/mod.rs similarity index 97% rename from src/plugins/router/isolated/mod.rs rename to src/plugins/ratelimit/reject/mod.rs index 71407cc..2cc0fd2 100644 --- a/src/plugins/router/isolated/mod.rs +++ b/src/plugins/ratelimit/reject/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; + +pub mod reject; diff --git a/src/plugins/router/metadata/router.rs b/src/plugins/ratelimit/reject/reject.rs similarity index 99% rename from src/plugins/router/metadata/router.rs rename to src/plugins/ratelimit/reject/reject.rs index 5992645..e62e40e 100644 --- a/src/plugins/router/metadata/router.rs +++ b/src/plugins/ratelimit/reject/reject.rs @@ -12,3 +12,4 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. + diff --git a/src/plugins/router/lane/router.rs b/src/plugins/ratelimit/unirate/mod.rs similarity index 97% rename from src/plugins/router/lane/router.rs rename to src/plugins/ratelimit/unirate/mod.rs index 5992645..b537f44 100644 --- a/src/plugins/router/lane/router.rs +++ b/src/plugins/ratelimit/unirate/mod.rs @@ -12,3 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. + +pub mod unirate; diff --git a/src/plugins/router/isolated/router.rs b/src/plugins/ratelimit/unirate/unirate.rs similarity index 100% rename from src/plugins/router/isolated/router.rs rename to src/plugins/ratelimit/unirate/unirate.rs diff --git a/src/plugins/router/health/health.rs b/src/plugins/router/health/health.rs new file mode 100644 index 0000000..2739e04 --- /dev/null +++ b/src/plugins/router/health/health.rs @@ -0,0 +1,113 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::{ + config::consumer::ServiceRouterPluginConfig, + flow::CircuitBreakerFlow, + model::{ + circuitbreaker::{InstanceResource, Resource}, + error::PolarisError, + naming::ServiceInstances, + router::{RouteResult, RouteState, DEFAULT_ROUTER_RECOVER}, + }, + plugin::{ + plugins::Plugin, + router::{RouteContext, ServiceRouter}, + }, +}; + +pub fn new_service_router(_conf: &ServiceRouterPluginConfig) -> Box { + Box::new(HealthRouter {}) +} + +pub struct HealthRouter {} + +impl HealthRouter { + pub fn builder() -> ( + fn(&ServiceRouterPluginConfig) -> Box, + String, + ) { + (new_service_router, DEFAULT_ROUTER_RECOVER.to_string()) + } +} + +impl Plugin for HealthRouter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + DEFAULT_ROUTER_RECOVER.to_string() + } +} + +#[async_trait::async_trait] +impl ServiceRouter for HealthRouter { + async fn choose_instances( + &self, + route_ctx: RouteContext, + instances: ServiceInstances, + ) -> Result { + let mut final_instances = Vec::with_capacity(instances.instances.len()); + + let circuit_breaker_flow = CircuitBreakerFlow::new(route_ctx.extensions.unwrap()); + let mut total_weight = 0 as u64; + + for (_, ins) in instances.instances.iter().enumerate() { + if !ins.is_available() { + continue; + } + let ret = circuit_breaker_flow + .check_resource(Resource::InstanceResource(InstanceResource {})) + .await; + match ret { + Ok(check_ret) => { + if !check_ret.pass { + continue; + } + } + Err(e) => { + return Err(e); + } + } + + total_weight += ins.weight as u64; + } + + // 重新算一次 + total_weight = 0 as u64; + for instance in instances.instances { + let weight = instance.weight as u64; + if !instance.is_available() && total_weight != 0 { + continue; + } + total_weight += weight as u64; + final_instances.push(instance); + } + + Ok(RouteResult { + instances: ServiceInstances { + service: instances.service, + instances: final_instances, + total_weight: total_weight as u64, + }, + state: RouteState::Next, + }) + } + + async fn enable(&self, route_info: RouteContext, instances: ServiceInstances) -> bool { + true + } +} diff --git a/src/plugins/router/health/mod.rs b/src/plugins/router/health/mod.rs index 71407cc..293e3ba 100644 --- a/src/plugins/router/health/mod.rs +++ b/src/plugins/router/health/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; + +pub mod health; diff --git a/src/plugins/router/lane/lane.rs b/src/plugins/router/lane/lane.rs new file mode 100644 index 0000000..d048cb3 --- /dev/null +++ b/src/plugins/router/lane/lane.rs @@ -0,0 +1,72 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use crate::core::{ + config::consumer::ServiceRouterPluginConfig, + model::{ + error::PolarisError, + naming::ServiceInstances, + router::{RouteResult, RouteState, DEFAULT_ROUTER_LANE}, + }, + plugin::{ + plugins::Plugin, + router::{RouteContext, ServiceRouter}, + }, +}; + +pub fn new_service_router(_conf: &ServiceRouterPluginConfig) -> Box { + Box::new(LaneRouter {}) +} + +pub struct LaneRouter {} + +impl LaneRouter { + pub fn builder() -> ( + fn(&ServiceRouterPluginConfig) -> Box, + String, + ) { + (new_service_router, DEFAULT_ROUTER_LANE.to_string()) + } +} + +impl Plugin for LaneRouter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + DEFAULT_ROUTER_LANE.to_string() + } +} + +#[async_trait::async_trait] +impl ServiceRouter for LaneRouter { + /// choose_instances 实例路由 + async fn choose_instances( + &self, + route_info: RouteContext, + instances: ServiceInstances, + ) -> Result { + Ok(RouteResult { + instances, + state: RouteState::Next, + }) + } + + /// enable 是否启用 + async fn enable(&self, route_info: RouteContext, instances: ServiceInstances) -> bool { + return true; + } +} diff --git a/src/plugins/router/lane/mod.rs b/src/plugins/router/lane/mod.rs index 71407cc..f7eac45 100644 --- a/src/plugins/router/lane/mod.rs +++ b/src/plugins/router/lane/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; + +pub mod lane; diff --git a/src/plugins/router/metadata/metadata.rs b/src/plugins/router/metadata/metadata.rs new file mode 100644 index 0000000..796353d --- /dev/null +++ b/src/plugins/router/metadata/metadata.rs @@ -0,0 +1,321 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::collections::HashMap; + +use crate::core::{ + config::consumer::ServiceRouterPluginConfig, + model::{ + error::PolarisError, + naming::{Instance, ServiceInfo, ServiceInstances}, + router::{ + MetadataFailoverType, RouteInfo, RouteResult, RouteState, DEFAULT_ROUTER_METADATA, + }, + }, + plugin::{ + plugins::Plugin, + router::{RouteContext, ServiceRouter}, + }, +}; + +pub fn new_service_router(_conf: &ServiceRouterPluginConfig) -> Box { + Box::new(MetadataRouter {}) +} + +static KEY_METADATA_FAILOVER: &str = "internal-metadata-failover-type"; + +/// 正常场景: 选出的实例子集不为空, 那么优先返回健康子集, 如果全部不健康则进行全死全活返回不健康子集。 +///

+/// 异常场景: 需要根据GetOneInstanceRequest的请求策略进行降级决策 +///

+/// 不降级(默认): 返回未找到实例错误 +/// 返回所有节点: 优先返回服务下的健康子集, 如果全部不健康则全死全活返回不健康子集 +/// 返回实例元数据不包含请求metadata的key的节点: 优先返回筛选出的健康子集, 如果全部不健康则返回不健康子集 +/// 例如: ip1 set=1 ; ip2 set=2 ; ip3 ; 请求时 set=0 返回的 ip3 (这个时候只判断key) +/// 降级使用指定metadata进行实例筛选。(未实现) +pub struct MetadataRouter {} + +impl MetadataRouter { + pub fn builder() -> ( + fn(&ServiceRouterPluginConfig) -> Box, + String, + ) { + (new_service_router, DEFAULT_ROUTER_METADATA.to_string()) + } +} + +impl Plugin for MetadataRouter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + DEFAULT_ROUTER_METADATA.to_string() + } +} + +#[async_trait::async_trait] +impl ServiceRouter for MetadataRouter { + /// choose_instances 实例路由 + async fn choose_instances( + &self, + route_ctx: RouteContext, + instances: ServiceInstances, + ) -> Result { + let mut failover_type = route_ctx.route_info.metadata_failover.clone(); + let svc_info = instances.service.clone(); + if let Some(_custom_failover_type) = svc_info.metadata.get(KEY_METADATA_FAILOVER) { + failover_type = paese_custom_failover_type(_custom_failover_type); + } + let req_meta = route_ctx.route_info.metadata.clone(); + let mut ret = Vec::::with_capacity(instances.instances.len()); + + let mut total_weight = 0 as u64; + + for instance in instances.instances.iter() { + let mut match_count = 0; + for (key, value) in req_meta.iter() { + if let Some(v) = instance.metadata.get(key) { + if v == value { + match_count += 1; + } else { + break; + } + } + } + if match_count != 0 && match_count == req_meta.len() { + total_weight += instance.weight as u64; + ret.push(instance.clone()); + } + } + + if !ret.is_empty() { + return Ok(RouteResult { + instances: ServiceInstances { + service: instances.service.clone(), + instances: ret, + total_weight: total_weight, + }, + state: RouteState::Next, + }); + } + + total_weight = 0; + + match failover_type { + MetadataFailoverType::MetadataFailoverAll => { + for instance in instances.instances.iter() { + total_weight += instance.weight as u64; + ret.push(instance.clone()); + } + } + MetadataFailoverType::MetadataFailoverNoKey => { + for instance in instances.instances.iter() { + let mut exist_meta = !instance.metadata.is_empty(); + for (key, _value) in req_meta.iter() { + if instance.metadata.contains_key(key) { + exist_meta = true; + break; + } + } + if !exist_meta { + total_weight += instance.weight as u64; + ret.push(instance.clone()); + } + } + } + _ => { + return Err(PolarisError::new( + crate::core::model::error::ErrorCode::MetadataMismatch, + format!( + "can not find any instance by service namespace({}) name({})", + svc_info.namespace, svc_info.name + ), + )); + } + } + + Ok(RouteResult { + instances: ServiceInstances { + service: instances.service.clone(), + instances: ret, + total_weight: total_weight, + }, + state: RouteState::Next, + }) + } + + /// enable 是否启用 + async fn enable(&self, route_info: RouteContext, instances: ServiceInstances) -> bool { + return true; + } +} + +fn paese_custom_failover_type(v: &str) -> MetadataFailoverType { + match v { + "none" => MetadataFailoverType::MetadataFailoverNone, + "all" => MetadataFailoverType::MetadataFailoverAll, + "others" => MetadataFailoverType::MetadataFailoverNoKey, + _ => MetadataFailoverType::MetadataFailoverNone, + } +} + +#[cfg(test)] +mod tests { + use crate::core::plugin::plugins::Extensions; + use std::sync::Arc; + use std::sync::Once; + + use super::*; + + use tracing::metadata::LevelFilter; + use crate::info; + + static LOGGER_INIT: Once = Once::new(); + + pub(crate) fn setup_log() { + LOGGER_INIT.call_once(|| { + tracing_subscriber::fmt() + .with_thread_names(true) + .with_file(true) + .with_level(true) + .with_line_number(true) + .with_thread_ids(true) + .with_max_level(LevelFilter::DEBUG) + .init() + }); + } + + #[tokio::test] + async fn test_choose_instances_no_failover() { + setup_log(); + let router = MetadataRouter {}; + let route_ctx = RouteContext { + route_info: RouteInfo { + metadata_failover: MetadataFailoverType::MetadataFailoverNone, + ..Default::default() + }, + extensions: None, + }; + let instances = ServiceInstances { + service: ServiceInfo { + namespace: "default".to_string(), + name: "test_service".to_string(), + metadata: HashMap::new(), + id: "".to_string(), + revision: "".to_string(), + }, + instances: vec![Instance { + metadata: HashMap::new(), + weight: 1, + ..Default::default() + }], + total_weight: 1, + }; + + let result = router.choose_instances(route_ctx, instances).await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_choose_instances_failover_all() { + setup_log(); + let route_ctx = RouteContext { + route_info: RouteInfo { + metadata_failover: MetadataFailoverType::MetadataFailoverAll, + metadata: [("key1".to_string(), "value1".to_string())] + .iter() + .cloned() + .collect(), + ..Default::default() + }, + extensions: None, + }; + let instances = ServiceInstances { + service: ServiceInfo { + namespace: "default".to_string(), + name: "test_service".to_string(), + metadata: HashMap::new(), + id: "".to_string(), + revision: "".to_string(), + }, + instances: vec![Instance { + metadata: [("key2".to_string(), "value2".to_string())] + .iter() + .cloned() + .collect(), + weight: 1, + ..Default::default() + }], + total_weight: 1, + }; + + let result = MetadataRouter {} + .choose_instances(route_ctx, instances) + .await; + assert!(result.is_ok()); + let route_result = result.unwrap(); + assert_eq!(route_result.instances.instances.len(), 1); + } + + #[tokio::test] + async fn test_choose_instances_failover_no_key() { + setup_log(); + let router = MetadataRouter {}; + let route_ctx = RouteContext { + route_info: RouteInfo { + metadata_failover: MetadataFailoverType::MetadataFailoverNoKey, + metadata: [("key1".to_string(), "value1".to_string())] + .iter() + .cloned() + .collect(), + ..Default::default() + }, + extensions: None, + }; + let instances = ServiceInstances { + service: ServiceInfo { + namespace: "default".to_string(), + name: "test_service".to_string(), + metadata: HashMap::new(), + id: "".to_string(), + revision: "".to_string(), + }, + instances: vec![ + Instance { + metadata: [("key1".to_string(), "value2".to_string())] + .iter() + .cloned() + .collect(), + weight: 1, + ..Default::default() + }, + Instance { + metadata: HashMap::new(), + weight: 1, + ..Default::default() + }, + ], + total_weight: 2, + }; + + let result = router.choose_instances(route_ctx, instances).await; + assert!(result.is_ok()); + let route_result = result.unwrap(); + assert_eq!(route_result.instances.instances.len(), 1); + info!("{:?}", route_result.instances.instances[0]); + assert!(route_result.instances.instances[0].metadata.is_empty()); + } +} diff --git a/src/plugins/router/metadata/mod.rs b/src/plugins/router/metadata/mod.rs index 71407cc..b2d3b7c 100644 --- a/src/plugins/router/metadata/mod.rs +++ b/src/plugins/router/metadata/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; + +pub mod metadata; diff --git a/src/plugins/router/mod.rs b/src/plugins/router/mod.rs index e385506..87dcad4 100644 --- a/src/plugins/router/mod.rs +++ b/src/plugins/router/mod.rs @@ -14,7 +14,6 @@ // specific language governing permissions and limitations under the License. pub mod health; -pub mod isolated; pub mod lane; pub mod metadata; pub mod nearby; diff --git a/src/plugins/router/nearby/mod.rs b/src/plugins/router/nearby/mod.rs index 71407cc..bf6ba19 100644 --- a/src/plugins/router/nearby/mod.rs +++ b/src/plugins/router/nearby/mod.rs @@ -12,4 +12,4 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; +pub mod nearby; diff --git a/src/plugins/router/nearby/nearby.rs b/src/plugins/router/nearby/nearby.rs new file mode 100644 index 0000000..db06781 --- /dev/null +++ b/src/plugins/router/nearby/nearby.rs @@ -0,0 +1,283 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use once_cell::sync::Lazy; +use std::collections::HashMap; + +use crate::core::{ + config::consumer::ServiceRouterPluginConfig, + model::{ + error::{ErrorCode, PolarisError}, + naming::{Instance, Location, ServiceInstances}, + router::{RouteResult, RouteState, DEFAULT_ROUTER_NEARBY}, + }, + plugin::{ + location::LocationSupplier, + plugins::Plugin, + router::{RouteContext, ServiceRouter}, + }, +}; + +static KEY_METADATA_NEARBY: &str = "internal-enable-nearby"; +static DEFAULT_NEARBY_MATCH_LEVEL: &str = "zone"; +static DEFAULT_NEARBY_MAX_MATCH_LEVEL: &str = "all"; +static MATCH_LEVEL: Lazy> = Lazy::new(|| { + [ + ("unknown".to_string(), 0), + ("campus".to_string(), 1), + ("zone".to_string(), 2), + ("region".to_string(), 3), + ("all".to_string(), 4), + ] + .iter() + .cloned() + .collect() +}); + +static ORDER_MATCH_LEVEL: Lazy> = Lazy::new(|| { + [ + (0, "unknown".to_string()), + (1, "campus".to_string()), + (2, "zone".to_string()), + (3, "region".to_string()), + (4, "all".to_string()), + ] + .iter() + .cloned() + .collect() +}); + +pub fn new_service_router(conf: &ServiceRouterPluginConfig) -> Box { + if conf.options.is_none() { + // 默认就近区域:默认城市 matchLevel: zone # 最大就近区域,默认为空(全匹配) maxMatchLevel: all # + // 假如开启了严格就近,插件的初始化会等待地域信息获取成功才返回,假如获取失败(server获取失败或者IP地域信息缺失),则会初始化失败,而且必须按照 strictNearby: false # + // 是否启用按服务不健康实例比例进行降级 enableDegradeByUnhealthyPercent: true,假如不启用,则不会降级# + // 需要进行降级的实例比例,不健康实例达到百分之多少才进行降级。值(0, 100]。 # 默认100,即全部不健康才进行切换。 + return Box::new(NearbyRouter { + strict_nearby: false, + match_level: "zone".to_string(), + max_match_level: "all".to_string(), + enable_degrade_unhealthy_percent: false, + unhealthy_percent_to_degrade: 100, + }); + } + // #描述: 就近路由的最小匹配级别。region(大区)、zone(区域)、campus(园区) + // matchLevel: zone + // #描述: 最大匹配级别 + // maxMatchLevel: all + // #描述: 强制就近 + // strictNearby: false + // #描述: 全部实例不健康时是否降级其他地域 + // enableDegradeByUnhealthyPercent: false + // #描述: 达到降级标准的不健康实例百分比 + // unhealthyPercentToDegrade: 100 + // #描述: 是否通过上报方式获取地域信息 + // enableReportLocalAddress: false + let options = conf.options.clone().unwrap(); + Box::new(NearbyRouter { + strict_nearby: options + .get("strictNearby") + .unwrap() + .parse() + .expect("strictNearby must be a boolean"), + match_level: options.get("matchLevel").unwrap().to_string(), + max_match_level: options.get("maxMatchLevel").unwrap().to_string(), + enable_degrade_unhealthy_percent: options + .get("enableDegradeByUnhealthyPercent") + .unwrap() + .parse() + .expect("enableDegradeByUnhealthyPercent must be a boolean"), + unhealthy_percent_to_degrade: options + .get("unhealthyPercentToDegrade") + .unwrap() + .parse() + .expect("unhealthyPercentToDegrade must be a number, range [0, 100]"), + }) +} + +pub struct NearbyRouter { + pub strict_nearby: bool, + pub match_level: String, + pub max_match_level: String, + pub enable_degrade_unhealthy_percent: bool, + pub unhealthy_percent_to_degrade: u16, +} + +impl NearbyRouter { + pub fn builder() -> ( + fn(&ServiceRouterPluginConfig) -> Box, + String, + ) { + (new_service_router, DEFAULT_ROUTER_NEARBY.to_string()) + } + + fn select_instances( + &self, + local_loc: Location, + match_level: &str, + instances: &ServiceInstances, + ) -> (ServiceInstances, u32) { + let mut ret = Vec::::with_capacity(instances.instances.len()); + + let mut total_weight: u64 = 0; + let mut health_ins_cnt = 0 as u32; + for (_, ins) in instances.instances.iter().enumerate() { + if ins.health { + health_ins_cnt += 1; + } + match match_level { + "campus" => { + if local_loc.campus == "" || ins.location.campus == local_loc.campus { + total_weight += ins.weight as u64; + ret.push(ins.clone()); + } + } + "zone" => { + if local_loc.zone == "" || ins.location.zone == local_loc.zone { + total_weight += ins.weight as u64; + ret.push(ins.clone()); + } + } + "region" => { + if local_loc.region == "" || ins.location.region == local_loc.region { + total_weight += ins.weight as u64; + ret.push(ins.clone()); + } + } + _ => { + total_weight += ins.weight as u64; + ret.push(ins.clone()); + } + } + } + + ( + ServiceInstances { + instances: ret, + service: instances.service.clone(), + total_weight: total_weight, + }, + health_ins_cnt, + ) + } +} + +impl Plugin for NearbyRouter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + DEFAULT_ROUTER_NEARBY.to_string() + } +} + +#[async_trait::async_trait] +impl ServiceRouter for NearbyRouter { + /// choose_instances 实例路由 + async fn choose_instances( + &self, + route_info: RouteContext, + instances: ServiceInstances, + ) -> Result { + let mut min_available_level = self.match_level.clone(); + if min_available_level.is_empty() { + min_available_level = DEFAULT_NEARBY_MATCH_LEVEL.to_string(); + } + let mut max_match_level = self.max_match_level.clone(); + if max_match_level.is_empty() { + max_match_level = DEFAULT_NEARBY_MAX_MATCH_LEVEL.to_string(); + } + + let locatin_provider = route_info + .extensions + .clone() + .unwrap() + .get_location_provider(); + + let location = locatin_provider.get_location(); + + if grater_match_level(min_available_level.as_str(), max_match_level.as_str()) { + let (ret_ins, _health_cnt) = + self.select_instances(location.clone(), min_available_level.as_str(), &instances); + if ret_ins.instances.is_empty() { + return Err(PolarisError::new(ErrorCode::LocationMismatch, format!(""))); + } + return Ok(RouteResult { + instances: ret_ins, + state: RouteState::Next, + }); + } + + let min_level_ord = MATCH_LEVEL + .get(min_available_level.as_str()) + .unwrap() + .clone(); + let max_level_ord = MATCH_LEVEL.get(max_match_level.as_str()).unwrap().clone(); + + let mut cur_level = min_available_level.clone(); + let mut ret_ins: Option = None; + for i in min_level_ord..=max_level_ord { + let cur_match_level = ORDER_MATCH_LEVEL.get(&i).unwrap(); + let (tmp_ins, health_cnt) = + self.select_instances(location.clone(), cur_match_level, &instances); + cur_level = cur_match_level.to_string().clone(); + if !tmp_ins.instances.is_empty() { + ret_ins = Some(tmp_ins); + } else { + min_available_level = cur_match_level.to_string().clone(); + } + } + + if ret_ins.is_none() { + return Err(PolarisError::new( + ErrorCode::LocationMismatch, + format!("can not find any instance by level {}", cur_level), + )); + } + + // if !self.enable_degrade_unhealthy_percent + // || cur_level == DEFAULT_NEARBY_MAX_MATCH_LEVEL.to_string() + // { + // return Ok(RouteResult { + // instances: ret_ins.unwrap(), + // state: RouteState::Next, + // }); + // } + + //TODO 需要做健康降级检查判断 + + return Ok(RouteResult { + instances: ret_ins.unwrap(), + state: RouteState::Next, + }); + } + + /// enable 是否启用 + async fn enable(&self, route_info: RouteContext, instances: ServiceInstances) -> bool { + let svc_info = instances.service.clone(); + let meta_val = svc_info.metadata.get(KEY_METADATA_NEARBY); + if meta_val.is_none() { + return false; + } + return meta_val.unwrap() != "true"; + } +} + +fn grater_match_level(a: &str, b: &str) -> bool { + let a_level = MATCH_LEVEL.get(a).unwrap(); + let b_level = MATCH_LEVEL.get(b).unwrap(); + a_level > b_level +} diff --git a/src/plugins/router/nearby/router.rs b/src/plugins/router/nearby/router.rs deleted file mode 100644 index 5992645..0000000 --- a/src/plugins/router/nearby/router.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Tencent is pleased to support the open source community by making Polaris available. -// -// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. -// -// Licensed under the BSD 3-Clause License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. diff --git a/src/plugins/router/rule/helper.rs b/src/plugins/router/rule/helper.rs new file mode 100644 index 0000000..a43e3ed --- /dev/null +++ b/src/plugins/router/rule/helper.rs @@ -0,0 +1,154 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::env::VarError; + +use polaris_specification::v1::{match_string::ValueType, MatchString, Route}; + +use crate::core::{model::ArgumentType, plugin::router::RouteContext}; + +static WILDCARD: &str = "*"; + +// route_traffic_match 匹配主、被调服务信息,以及匹配请求流量标签 +pub fn route_traffic_match(ctx: &RouteContext, rule: &Route) -> bool { + if !match_callee_caller(ctx, rule) { + return false; + } + + let traffic_provider = ctx.route_info.traffic_label_provider; + let ext_provider = ctx.route_info.external_parameter_supplier; + + // 匹配流量标签 + for (_, ele) in rule.sources.iter().enumerate() { + let mut matched = true; + for (_, (key, rule_value)) in ele.metadata.iter().enumerate() { + let mut match_key = key.as_str(); + let mut actual_val = String::new(); + + match rule_value.value_type() { + ValueType::Text => { + let mut traffic_type = ArgumentType::Custom; + if key.contains(".") { + let parts: Vec<&str> = match_key.splitn(2, '.').collect(); + match_key = parts[1]; + let mut label_prefix = parts[0]; + if parts[0].starts_with('$') { + label_prefix = &parts[0][1..]; + } + traffic_type = ArgumentType::parse_from_str(label_prefix); + } + actual_val = traffic_provider(traffic_type, match_key).unwrap_or(String::new()); + } + // 匹配参数,那就直接从 traffic_labels 中获取 + ValueType::Parameter => continue, + // 上下文环境变量,value 为环境变量名 + ValueType::Variable => match std::env::var(match_key) { + Ok(v) => actual_val = v, + Err(err) => { + if err != VarError::NotPresent { + return false; + } + match ext_provider(match_key) { + Some(v) => actual_val = v, + None => return false, + } + } + }, + } + + if match_label_value(rule_value, actual_val) { + matched = false; + break; + } + } + + if matched { + return true; + } + } + false +} + +/// match_label_value 匹配标签值 +pub fn match_label_value(rule_value: &MatchString, actual_val: String) -> bool { + let match_value = rule_value.value.clone().unwrap_or("".to_string()); + if is_match_all(&match_value) { + return true; + } + + match rule_value.r#type() { + polaris_specification::v1::match_string::MatchStringType::Exact => { + return match_value == actual_val; + } + polaris_specification::v1::match_string::MatchStringType::NotEquals => { + return match_value != actual_val; + } + polaris_specification::v1::match_string::MatchStringType::Regex => { + return regex::Regex::new(&match_value) + .unwrap() + .is_match(&actual_val); + } + polaris_specification::v1::match_string::MatchStringType::In => { + return match_value.split(',').any(|x| x == actual_val); + } + polaris_specification::v1::match_string::MatchStringType::NotIn => { + return !match_value.split(',').any(|x| x == actual_val); + } + polaris_specification::v1::match_string::MatchStringType::Range => { + let parts: Vec<&str> = match_value.split(',').collect(); + if parts.len() != 2 { + return false; + } + let min = parts[0].parse::().unwrap(); + let max = parts[1].parse::().unwrap(); + let actual_val = actual_val.parse::().unwrap(); + return actual_val >= min && actual_val <= max; + } + } +} + +/// match_callee_caller 匹配主被调服务信息 +pub fn match_callee_caller(rctx: &RouteContext, rule: &Route) -> bool { + let caller = &rctx.route_info.caller; + let callee = &rctx.route_info.callee; + + for (_, ele) in rule.sources.iter().enumerate() { + let svc = ele.service.clone().unwrap(); + let ns = ele.namespace.clone().unwrap(); + if svc != caller.name && !is_match_all(&svc) { + return false; + } + if ns != caller.namespace && !is_match_all(&ns) { + return false; + } + } + + for (_, ele) in rule.destinations.iter().enumerate() { + let svc = ele.service.clone().unwrap(); + let ns = ele.namespace.clone().unwrap(); + if svc != callee.name && !is_match_all(&svc) { + return false; + } + if ns != callee.namespace && !is_match_all(&ns) { + return false; + } + } + + true +} + +pub fn is_match_all(s: &str) -> bool { + s == WILDCARD +} diff --git a/src/plugins/router/rule/mod.rs b/src/plugins/router/rule/mod.rs index 71407cc..c947d9d 100644 --- a/src/plugins/router/rule/mod.rs +++ b/src/plugins/router/rule/mod.rs @@ -12,4 +12,5 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod router; +pub mod helper; +pub mod rule; diff --git a/src/plugins/router/rule/router.rs b/src/plugins/router/rule/router.rs deleted file mode 100644 index 5992645..0000000 --- a/src/plugins/router/rule/router.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Tencent is pleased to support the open source community by making Polaris available. -// -// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. -// -// Licensed under the BSD 3-Clause License (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. diff --git a/src/plugins/router/rule/rule.rs b/src/plugins/router/rule/rule.rs new file mode 100644 index 0000000..bfc2af9 --- /dev/null +++ b/src/plugins/router/rule/rule.rs @@ -0,0 +1,334 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::{any::Any, collections::HashMap, sync::Arc, time::Duration}; + +use polaris_specification::v1::{Destination, Route, Routing}; + +use crate::core::{ + config::consumer::ServiceRouterPluginConfig, + model::{ + cache::{EventType, ResourceEventKey}, + error::{ErrorCode, PolarisError}, + naming::{Instance, ServiceInstances}, + router::{RouteResult, RouteState, DEFAULT_ROUTER_RULE}, + }, + plugin::{ + cache::Filter, + plugins::{Extensions, Plugin}, + router::{RouteContext, ServiceRouter}, + }, +}; +use crate::warn; +use super::helper::route_traffic_match; + +#[derive(Debug, PartialEq, Eq)] +pub enum Direction { + Callee, + Caller, +} + +#[derive(Debug, PartialEq, Eq)] +enum RouteFailoverPolicy { + All, + None, +} + +#[derive(Debug, PartialEq, Eq)] +enum RuleStatus { + // 无路由策略 + NoRule, + // 被调服务路由策略匹配成功 + DestRuleSucc, + // 被调服务路由策略匹配失败 + DestRuleFail, + // 主调服务路由策略匹配成功 + SourceRuleSucc, + // 主调服务路由策略匹配失败 + SourceRuleFail, +} + +pub fn new_service_router(_conf: &ServiceRouterPluginConfig) -> Box { + let mut policy = RouteFailoverPolicy::All; + if let Some(opt) = _conf.options.clone() { + let val = opt.get("failover"); + if let Some(val) = val { + if val == "none" { + policy = RouteFailoverPolicy::None; + } + } + } + Box::new(RuleRouter { + failover_policy: policy, + }) +} + +pub struct RuleRouter { + failover_policy: RouteFailoverPolicy, +} + +impl RuleRouter { + pub fn builder() -> ( + fn(&ServiceRouterPluginConfig) -> Box, + String, + ) { + (new_service_router, DEFAULT_ROUTER_RULE.to_string()) + } +} + +impl Plugin for RuleRouter { + fn init(&mut self) {} + + fn destroy(&self) {} + + fn name(&self) -> String { + DEFAULT_ROUTER_RULE.to_string() + } +} + +impl RuleRouter { + async fn fetch_rule( + &self, + extensions: Arc, + rctx: &RouteContext, + dir: Direction, + ) -> Result, PolarisError> { + let local_cache = extensions.get_resource_cache(); + + let mut ns = &rctx.route_info.caller.namespace; + let mut svc = &rctx.route_info.caller.name; + if dir == Direction::Callee { + ns = &rctx.route_info.callee.namespace; + svc = &rctx.route_info.callee.name; + } + + let mut filter = HashMap::::new(); + filter.insert("service".to_string(), svc.to_string()); + let ret = local_cache + .load_service_rule(Filter { + resource_key: ResourceEventKey { + namespace: ns.to_string(), + event_type: EventType::RouterRule, + filter, + }, + internal_request: false, + include_cache: true, + timeout: Duration::from_secs(1), + }) + .await; + + if ret.is_err() { + return Err(ret.err().unwrap()); + } + let ret = ret.unwrap(); + + let mut rules = Vec::>::with_capacity(ret.rules.len()); + for ele in ret.rules { + let type_id = ele.type_id(); + match ele.downcast::() { + Ok(rule) => rules.push(rule), + Err(_) => { + return Err(PolarisError::new( + ErrorCode::InvalidRule, + format!("rule type error, expect Routing, but got {:?}", type_id), + )); + } + } + } + // rules 只会有一个的,所以这里指拿第一个即可 + let rule = rules.remove(0); + if dir == Direction::Callee { + return Ok(rule.inbounds); + } + return Ok(rule.outbounds); + } + + fn filter_instances( + &self, + rctx: &RouteContext, + instances: &ServiceInstances, + rules: Vec, + ) -> Result, PolarisError> { + for ele in rules { + if !route_traffic_match(rctx, &ele) { + continue; + } + // 匹配实例分组 + + let destination = filter_available_destinations(ele.destinations); + for (_, dest) in destination.iter().enumerate() { + let ret = match_callee_group(dest, instances); + if ret.is_empty() { + continue; + } + // 返回目标实例分组结果 + return Ok(ret); + } + // 没有符合的实例分组,需要看下兜底逻辑 + } + // 返回空实例列表 + Ok(vec![]) + } +} + +#[async_trait::async_trait] +impl ServiceRouter for RuleRouter { + /// choose_instances 实例路由 + async fn choose_instances( + &self, + route_ctx: RouteContext, + instances: ServiceInstances, + ) -> Result { + let extensions = route_ctx.extensions.clone().unwrap(); + + // 匹配顺序 -> 先按照被调方路由规则匹配,然后再按照主调方规则进行匹配 + let mut filtered_ins = Option::>::None; + + let mut status = RuleStatus::NoRule; + let callee_rules = self + .fetch_rule(extensions.clone(), &route_ctx, Direction::Callee) + .await?; + if !callee_rules.is_empty() { + status = RuleStatus::DestRuleSucc; + let ret = self.filter_instances(&route_ctx, &instances, callee_rules)?; + if ret.is_empty() { + status = RuleStatus::DestRuleFail; + } else { + filtered_ins = Some(ret); + } + } + + // 如果被调服务路由规则匹配失败,则判断主调方的路由规则 + if status != RuleStatus::DestRuleSucc { + let caller_rules = self + .fetch_rule(extensions, &route_ctx, Direction::Caller) + .await?; + if !caller_rules.is_empty() { + status = RuleStatus::SourceRuleSucc; + let ret = self.filter_instances(&route_ctx, &instances, caller_rules)?; + if ret.is_empty() { + status = RuleStatus::SourceRuleFail; + } else { + filtered_ins = Some(ret); + } + } + } + + match status { + RuleStatus::NoRule => Ok(RouteResult { + instances, + state: RouteState::Next, + }), + RuleStatus::DestRuleSucc | RuleStatus::SourceRuleSucc => { + let mut total_weight = 0 as u64; + let filtered_ins = filtered_ins.unwrap(); + let ins = Vec::::with_capacity(filtered_ins.capacity()); + for ele in filtered_ins { + total_weight += ele.weight as u64; + } + Ok(RouteResult { + instances: ServiceInstances { + service: instances.service.clone(), + instances: ins, + total_weight: total_weight, + }, + state: RouteState::Next, + }) + } + _ => { + warn!( + "[router][rule] route rule not match, rule status: {:?}, not matched callee:{:?} caller:{:?}", + status, + route_ctx.route_info.caller, + route_ctx.route_info.callee, + ); + match self.failover_policy { + RouteFailoverPolicy::All => Ok(RouteResult { + instances, + state: RouteState::Next, + }), + RouteFailoverPolicy::None => Ok(RouteResult { + instances: ServiceInstances { + service: instances.service.clone(), + instances: vec![], + total_weight: 0, + }, + state: RouteState::Next, + }), + } + } + } + } + + /// enable 是否启用 + async fn enable(&self, route_ctx: RouteContext, instances: ServiceInstances) -> bool { + let route_info = &route_ctx.route_info; + let chain = &route_ctx.route_info.chain; + let has_router = chain.exist_route(DEFAULT_ROUTER_RULE); + if !has_router { + return false; + } + + let caller_ret = self + .fetch_rule( + route_ctx.extensions.clone().unwrap(), + &route_ctx, + Direction::Caller, + ) + .await; + if caller_ret.is_err() { + return false; + } + let caller_empty = caller_ret.unwrap().is_empty(); + + let callee_ret = self + .fetch_rule( + route_ctx.extensions.clone().unwrap(), + &route_ctx, + Direction::Callee, + ) + .await; + if callee_ret.is_err() { + return false; + } + let callee_empty = callee_ret.unwrap().is_empty(); + + // 其中一个有规则即可 + caller_empty || callee_empty + } +} + +fn match_callee_group(dest: &Destination, instances: &ServiceInstances) -> Vec { + todo!() +} + +fn filter_available_destinations(dests: Vec) -> Vec { + let mut ret = Vec::::with_capacity(dests.capacity()); + + for ele in dests { + if ele.isolate.unwrap_or(false) { + ret.push(ele); + } + } + + // 优先级按照 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 以此类推 + ret.sort_by(|a, b| { + let a_weight = a.weight.unwrap_or(0); + let b_weight = b.weight.unwrap_or(0); + a_weight.cmp(&b_weight) + }); + + ret +} diff --git a/src/ratelimit/api.rs b/src/ratelimit/api.rs index d73fe5e..7ee839c 100644 --- a/src/ratelimit/api.rs +++ b/src/ratelimit/api.rs @@ -13,4 +13,36 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -pub trait RateLimitAPI {} +use std::sync::Arc; + +use crate::core::{context::SDKContext, model::error::PolarisError}; + +use super::{ + default::DefaultRateLimitAPI, + req::{QuotaRequest, QuotaResponse}, +}; + +/// new_ratelimit_api +pub fn new_ratelimit_api() -> Result { + let context_ret = SDKContext::default(); + if context_ret.is_err() { + return Err(context_ret.err().unwrap()); + } + + Ok(DefaultRateLimitAPI::new_raw(context_ret.unwrap())) +} + +/// new_ratelimit_api_by_context +pub fn new_ratelimit_api_by_context( + context: Arc, +) -> Result { + Ok(DefaultRateLimitAPI::new(context)) +} + +#[async_trait::async_trait] +pub trait RateLimitAPI +where + Self: Send + Sync, +{ + async fn get_quota(&self, req: QuotaRequest) -> Result; +} diff --git a/src/ratelimit/default.rs b/src/ratelimit/default.rs new file mode 100644 index 0000000..f1baa0f --- /dev/null +++ b/src/ratelimit/default.rs @@ -0,0 +1,79 @@ +// Tencent is pleased to support the open source community by making Polaris available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +use std::sync::Arc; + +use crate::core::{context::SDKContext, flow::RatelimitFlow, model::error::PolarisError}; + +use super::{ + api::RateLimitAPI, + req::{QuotaRequest, QuotaResponse}, +}; + +pub struct DefaultRateLimitAPI { + manage_sdk: bool, + context: Arc, + flow: Arc, +} + +impl DefaultRateLimitAPI { + pub fn new_raw(context: SDKContext) -> Self { + let ctx = Arc::new(context); + let extensions = ctx.get_engine().get_extensions(); + Self { + manage_sdk: true, + context: ctx, + flow: Arc::new(RatelimitFlow::new(extensions)), + } + } + + pub fn new(context: Arc) -> Self { + let extensions = context.get_engine().get_extensions(); + Self { + manage_sdk: false, + context: context, + flow: Arc::new(RatelimitFlow::new(extensions)), + } + } +} + +impl Drop for DefaultRateLimitAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } + } +} + +#[async_trait::async_trait] +impl RateLimitAPI for DefaultRateLimitAPI { + async fn get_quota(&self, req: QuotaRequest) -> Result { + let check_ret = req.check_valid(); + check_ret?; + + todo!() + } +} diff --git a/src/ratelimit/mod.rs b/src/ratelimit/mod.rs index 721e783..e94e4b2 100644 --- a/src/ratelimit/mod.rs +++ b/src/ratelimit/mod.rs @@ -13,5 +13,6 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -mod api; -mod req; +pub mod api; +pub mod default; +pub mod req; diff --git a/src/ratelimit/req.rs b/src/ratelimit/req.rs index 5992645..737d00a 100644 --- a/src/ratelimit/req.rs +++ b/src/ratelimit/req.rs @@ -12,3 +12,51 @@ // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. + +use std::time::Duration; + +use crate::core::model::{error::{ErrorCode, PolarisError}, ArgumentType}; + +/// QuotaRequest 获取请求配额 +#[derive(Clone, Debug)] +pub struct QuotaRequest { + pub flow_id: String, + pub timeout: Duration, + // service 服务名 + pub service: String, + // namespace 命名空间 + pub namespace: String, + // method 方法名 + pub method: String, + // traffic_label_provider 流量标签提供者 + pub traffic_label_provider: fn(ArgumentType, &str) -> Option, + // 北极星内部治理规则执行时,会识别规则中的参数来源类别,如果发现规则中的参数来源指定为外部数据源时,会调用本接口进行获取 + pub external_parameter_supplier: fn(&str) -> Option, +} + +impl QuotaRequest { + pub fn check_valid(&self) -> Result<(), PolarisError> { + if self.service.is_empty() { + return Err(PolarisError::new( + ErrorCode::ApiInvalidArgument, + "service is empty".to_string(), + )); + } + + if self.namespace.is_empty() { + return Err(PolarisError::new( + ErrorCode::ApiInvalidArgument, + "namespace is empty".to_string(), + )); + } + Ok(()) + } +} + + +/// QuotaResponse 配额响应 +#[derive(Clone, Debug)] +pub struct QuotaResponse { + pub allowed: bool, + pub message: String, +} diff --git a/src/router/api.rs b/src/router/api.rs index d9c1727..355b962 100644 --- a/src/router/api.rs +++ b/src/router/api.rs @@ -13,14 +13,33 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. +use std::sync::Arc; + use crate::{ - core::model::error::PolarisError, + core::{context::SDKContext, model::error::PolarisError}, router::req::{ ProcessLoadBalanceRequest, ProcessLoadBalanceResponse, ProcessRouteRequest, ProcessRouteResponse, }, }; +use super::default::DefaultRouterAPI; + +/// new_router_api +pub fn new_router_api() -> Result { + let context_ret = SDKContext::default(); + if context_ret.is_err() { + return Err(context_ret.err().unwrap()); + } + + Ok(DefaultRouterAPI::new_raw(context_ret.unwrap())) +} + +/// new_router_api_by_context +pub fn new_router_api_by_context(context: Arc) -> Result { + Ok(DefaultRouterAPI::new(context)) +} + #[async_trait::async_trait] pub trait RouterAPI where diff --git a/src/router/default.rs b/src/router/default.rs index e4171a0..eec0f8a 100644 --- a/src/router/default.rs +++ b/src/router/default.rs @@ -17,18 +17,55 @@ use std::sync::Arc; use crate::core::{ context::SDKContext, + flow::RouterFlow, model::error::{ErrorCode, PolarisError}, }; - +use crate::debug; use super::{api::RouterAPI, req::ProcessRouteResponse}; pub struct DefaultRouterAPI { + manage_sdk: bool, context: Arc, + flow: Arc, } impl DefaultRouterAPI { + pub fn new_raw(context: SDKContext) -> Self { + let ctx = Arc::new(context); + let extensions = ctx.get_engine().get_extensions(); + Self { + manage_sdk: true, + context: ctx, + flow: Arc::new(RouterFlow::new(extensions)), + } + } + pub fn new(context: Arc) -> Self { - Self { context } + let extensions = context.get_engine().get_extensions(); + Self { + manage_sdk: false, + context: context, + flow: Arc::new(RouterFlow::new(extensions)), + } + } +} + +impl Drop for DefaultRouterAPI { + fn drop(&mut self) { + if !self.manage_sdk { + return; + } + let ctx = self.context.to_owned(); + let ret = Arc::try_unwrap(ctx); + + match ret { + Ok(ctx) => { + drop(ctx); + } + Err(_) => { + // do nothing + } + } } } @@ -38,16 +75,27 @@ impl RouterAPI for DefaultRouterAPI { &self, req: super::req::ProcessRouteRequest, ) -> Result { - // TODO: 需要支持路由规则,当前直接原封不动进行返回 - Ok(ProcessRouteResponse { - service_instances: req.service_instances, - }) + debug!("[polaris][router_api] route request {:?}", req); + + let ret = self + .flow + .choose_instances(req.route_info.clone(), req.service_instances) + .await; + + match ret { + Ok(result) => Ok(ProcessRouteResponse { + service_instances: result, + }), + Err(e) => Err(e), + } } async fn load_balance( &self, req: super::req::ProcessLoadBalanceRequest, ) -> Result { + debug!("[polaris][router_api] load_balance request {:?}", req); + let criteria = req.criteria.clone(); let mut lb_policy = criteria.policy.clone(); @@ -55,20 +103,16 @@ impl RouterAPI for DefaultRouterAPI { lb_policy.clone_from(&self.context.conf.consumer.load_balancer.default_policy); } - let lb = self - .context - .get_engine() - .lookup_loadbalancer(&lb_policy) - .await; + let lb = self.flow.lookup_loadbalancer(&lb_policy).await; if lb.is_none() { - tracing::error!( + crate::error!( "[polaris][router_api] load balancer {} not found", lb_policy ); return Err(PolarisError::new( ErrorCode::PluginError, - format!("load balancer {} not found", lb_policy,), + format!("load balancer {} not found", lb_policy), )); } diff --git a/src/router/req.rs b/src/router/req.rs index 082295c..4f17db1 100644 --- a/src/router/req.rs +++ b/src/router/req.rs @@ -15,10 +15,10 @@ use crate::core::model::loadbalance::Criteria; use crate::core::model::naming::{Instance, ServiceInstances}; -use crate::core::model::router::{CalleeInfo, CallerInfo}; +use crate::core::model::router::RouteInfo; // 负载均衡相关请求 - +#[derive(Debug)] pub struct ProcessLoadBalanceRequest { pub service_instances: ServiceInstances, pub criteria: Criteria, @@ -29,11 +29,10 @@ pub struct ProcessLoadBalanceResponse { } // 路由相关请求 - +#[derive(Debug)] pub struct ProcessRouteRequest { pub service_instances: ServiceInstances, - pub caller_info: CallerInfo, - pub callee_info: CalleeInfo, + pub route_info: RouteInfo, } pub struct ProcessRouteResponse {