1use std::{collections::HashMap, env, fs};
19
20use crate::{protocol::Protocol, registry::RegistryConfig};
21use once_cell::sync::OnceCell;
22use serde::{Deserialize, Serialize};
23use tracing::trace;
24
25use super::{protocol::ProtocolConfig, provider::ProviderConfig, service::ServiceConfig};
26
27pub const DUBBO_CONFIG_PATH: &str = "./dubbo.yaml";
28
29pub static GLOBAL_ROOT_CONFIG: OnceCell<RootConfig> = OnceCell::new();
30pub const DUBBO_CONFIG_PREFIX: &str = "dubbo";
31
32#[allow(dead_code)]
35#[derive(Debug, Default, Serialize, Deserialize, Clone)]
36pub struct RootConfig {
37 #[serde(default)]
38 pub protocols: ProtocolConfig,
39
40 #[serde(default)]
41 pub provider: ProviderConfig,
42
43 #[serde(default)]
44 pub registries: HashMap<String, RegistryConfig>,
45
46 #[serde(default)]
47 pub data: HashMap<String, String>,
48}
49
50pub fn get_global_config() -> &'static RootConfig {
51 GLOBAL_ROOT_CONFIG.get_or_init(|| {
52 tracing::debug!("current path: {:?}", env::current_dir());
53 RootConfig::new()
54 .load()
55 .unwrap_or_else(|err| panic!("Failed to load global config, error: {}", err))
56 })
57}
58
59impl RootConfig {
60 pub fn new() -> Self {
61 Self {
62 protocols: HashMap::new(),
63 registries: HashMap::new(),
64 provider: ProviderConfig::new(),
65 data: HashMap::new(),
66 }
67 }
68
69 pub fn load(&self) -> std::io::Result<Self> {
70 let config_path = match env::var("DUBBO_CONFIG_PATH") {
71 Ok(v) => {
72 tracing::info!("read config_path from env: {:?}", v);
73 v
74 }
75 Err(err) => {
76 tracing::warn!(
77 "error loading config_path: {:?}, use default path: {:?}",
78 err,
79 DUBBO_CONFIG_PATH
80 );
81 DUBBO_CONFIG_PATH.to_string()
82 }
83 };
84
85 tracing::info!("current path: {:?}", env::current_dir());
86 let data = fs::read(config_path)?;
87 trace!("config data: {:?}", String::from_utf8(data.clone()));
88 let conf: HashMap<String, RootConfig> = serde_yaml::from_slice(&data).unwrap();
89 let root_config: RootConfig = conf.get(DUBBO_CONFIG_PREFIX).unwrap().clone();
90 tracing::debug!("origin config: {:?}", conf);
91 Ok(root_config)
92 }
93
94 pub fn test_config(&mut self) {
95 let mut provider = ProviderConfig::new();
96 provider.protocol_ids = vec!["triple".to_string()];
97 provider.registry_ids = vec![];
98
99 let service_config = ServiceConfig::default()
100 .group("test".to_string())
101 .version("1.0.0".to_string())
102 .protocol("triple".to_string())
103 .interface("grpc.examples.echo.Echo".to_string());
104
105 self.provider
106 .services
107 .insert("grpc.examples.echo.Echo".to_string(), service_config);
108 self.provider.services.insert(
109 "helloworld.Greeter".to_string(),
110 ServiceConfig::default()
111 .group("test".to_string())
112 .version("1.0.0".to_string())
113 .interface("helloworld.Greeter".to_string())
114 .protocol("triple".to_string()),
115 );
116 self.protocols.insert(
117 "triple".to_string(),
118 Protocol::default()
119 .name("triple".to_string())
120 .ip("0.0.0.0".to_string())
121 .port("8889".to_string()),
122 );
123
124 self.provider = provider.clone();
125 println!("provider config: {:?}", provider);
126 self.data.insert(
128 "dubbo.provider.url".to_string(),
129 "dubbo://127.0.0.1:8888/?serviceName=hellworld".to_string(),
130 );
131 }
133
134 #[inline]
135 pub fn leak(self) -> &'static Self {
136 Box::leak(Box::new(self))
137 }
138}
139
140impl Config for RootConfig {
141 fn bool(&self, key: String) -> bool {
142 match self.data.get(&key) {
143 None => false,
144 Some(val) => match val.parse::<bool>() {
145 Ok(v) => v,
146 Err(_err) => {
147 tracing::error!("key: {}, val: {} is not boolean", key, val);
148 false
149 }
150 },
151 }
152 }
153
154 fn string(&self, key: String) -> String {
155 match self.data.get(&key) {
156 None => "".to_string(),
157 Some(val) => val.to_string(),
158 }
159 }
160}
161
162pub trait BusinessConfig {
163 fn init() -> Self;
164 fn load() -> Result<(), std::convert::Infallible>;
165}
166
167pub trait Config {
168 fn bool(&self, key: String) -> bool;
169 fn string(&self, key: String) -> String;
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn test_config() {
178 let mut r = RootConfig::new();
179 r.test_config();
180 }
181
182 #[test]
183 fn test_load() {
184 println!("current path: {:?}", env::current_dir());
186 let r = RootConfig::new();
187 r.load();
188 }
189
190 #[test]
191 fn test_load1() {
192 println!("current path: {:?}", env::current_dir());
194 let r = RootConfig::new();
195 r.load();
196 }
197
198 #[test]
199 fn test_write_yaml() {
200 let mut r = RootConfig::new();
201 r.test_config();
202 let yaml = serde_yaml::to_string(&r).unwrap();
203 println!("config data: {:?}", yaml);
204
205 fs::write("./test_dubbo.yaml", yaml);
206 }
207}