Skip to content

Commit 8ce0e25

Browse files
committed
refactor: FeatureProbe Constructor and Config
1 parent 1913dd4 commit 8ce0e25

File tree

7 files changed

+192
-134
lines changed

7 files changed

+192
-134
lines changed

examples/demo.rs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,25 @@
1-
use feature_probe_server_sdk::{FPConfig, FPUser, FeatureProbe};
1+
use feature_probe_server_sdk::{FPConfigBuilder, FPError, FPUser, FeatureProbe};
22
use std::time::Duration;
33

44
// Connect to demo docker environment.
55
// cargo run --example demo
66

77
#[tokio::main]
8-
async fn main() {
8+
async fn main() -> Result<(), FPError> {
9+
let _ = tracing_subscriber::fmt().init();
910
// let remote_url = "http://localhost:4009/server"; // for local docker
1011
let remote_url = "https://featureprobe.io/server";
1112
// Server SDK key in Project List Page.
1213
let server_sdk_key = "server-7fa2f771259cb7235b96433d70b91e99abcf6ff8";
1314
let interval = Duration::from_millis(2000);
14-
let config = FPConfig {
15-
remote_url: remote_url.to_owned(),
16-
server_sdk_key: server_sdk_key.to_owned(),
17-
refresh_interval: interval,
18-
#[cfg(feature = "use_tokio")]
19-
http_client: None,
20-
start_wait: Some(Duration::from_secs(5)),
21-
..Default::default()
22-
};
15+
let config = FPConfigBuilder::new(remote_url.to_owned(), server_sdk_key.to_owned(), interval)
16+
.start_wait(Duration::from_secs(5))
17+
.build()?;
2318

24-
let fp = match FeatureProbe::new(config) {
25-
Ok(fp) => fp,
26-
Err(e) => {
27-
tracing::error!("{:?}", e);
28-
return;
29-
}
30-
};
19+
let fp = FeatureProbe::new(config);
20+
if !fp.initialized() {
21+
println!("FeatureProbe failed to initialize, will return default value");
22+
}
3123

3224
let mut user = FPUser::new();
3325
user = user.with("userId", "00001");
@@ -40,4 +32,5 @@ async fn main() {
4032
println!(" => rule index : {:?}", detail.rule_index);
4133

4234
fp.close();
35+
Ok(())
4336
}

src/config.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use std::time::Duration;
2+
3+
#[cfg(feature = "use_tokio")]
4+
use reqwest::Client;
5+
use tracing::info;
6+
use url::Url;
7+
8+
use crate::FPError;
9+
10+
#[derive(Debug, Default, Clone)]
11+
pub struct FPConfigBuilder {
12+
pub remote_url: String,
13+
pub toggles_url: Option<String>,
14+
pub events_url: Option<String>,
15+
pub server_sdk_key: String,
16+
pub refresh_interval: Duration,
17+
#[cfg(feature = "use_tokio")]
18+
pub http_client: Option<Client>,
19+
pub start_wait: Option<Duration>,
20+
}
21+
22+
#[derive(Debug, Clone)]
23+
pub struct FPConfig {
24+
pub toggles_url: Url,
25+
pub events_url: Url,
26+
pub server_sdk_key: String,
27+
pub refresh_interval: Duration,
28+
#[cfg(feature = "use_tokio")]
29+
pub http_client: Option<Client>,
30+
pub start_wait: Option<Duration>,
31+
}
32+
33+
impl Default for FPConfig {
34+
fn default() -> Self {
35+
Self {
36+
server_sdk_key: "".to_owned(),
37+
toggles_url: Url::parse("http://127.0.0.1:8080").unwrap(),
38+
events_url: Url::parse("http://127.0.0.1:8080").unwrap(),
39+
refresh_interval: Duration::from_secs(5),
40+
start_wait: None,
41+
#[cfg(feature = "use_tokio")]
42+
http_client: None,
43+
}
44+
}
45+
}
46+
47+
impl FPConfigBuilder {
48+
pub fn new(
49+
remote_url: String,
50+
server_sdk_key: String,
51+
refresh_interval: Duration,
52+
) -> FPConfigBuilder {
53+
Self {
54+
remote_url,
55+
server_sdk_key,
56+
refresh_interval,
57+
..Default::default()
58+
}
59+
}
60+
61+
pub fn toggles_url(mut self, toggles_url: String) -> FPConfigBuilder {
62+
self.toggles_url = Some(toggles_url);
63+
self
64+
}
65+
66+
pub fn events_url(mut self, events_url: String) -> FPConfigBuilder {
67+
self.events_url = Some(events_url);
68+
self
69+
}
70+
71+
pub fn start_wait(mut self, start_wait: Duration) -> FPConfigBuilder {
72+
self.start_wait = Some(start_wait);
73+
self
74+
}
75+
76+
#[cfg(feature = "use_tokio")]
77+
pub fn http_client(mut self, http_client: Client) -> FPConfigBuilder {
78+
self.http_client = Some(http_client);
79+
self
80+
}
81+
82+
pub fn build(&self) -> Result<FPConfig, FPError> {
83+
info!("build_config from {:?}", self);
84+
let remote_url = {
85+
if !self.remote_url.ends_with('/') {
86+
self.remote_url.clone() + "/"
87+
} else {
88+
self.remote_url.clone()
89+
}
90+
};
91+
let toggles_url = match &self.toggles_url {
92+
None => remote_url.clone() + "api/server-sdk/toggles",
93+
Some(url) => url.to_owned(),
94+
};
95+
96+
let toggles_url: Url = match Url::parse(&toggles_url) {
97+
Err(e) => return Err(FPError::UrlError(e.to_string())),
98+
Ok(url) => url,
99+
};
100+
101+
let events_url = match &self.events_url {
102+
None => remote_url + "api/events",
103+
Some(url) => url.to_owned(),
104+
};
105+
106+
let events_url: Url = match Url::parse(&events_url) {
107+
Err(e) => return Err(FPError::UrlError(e.to_string())),
108+
Ok(url) => url,
109+
};
110+
111+
Ok(FPConfig {
112+
toggles_url,
113+
events_url,
114+
server_sdk_key: self.server_sdk_key.clone(),
115+
refresh_interval: self.refresh_interval,
116+
start_wait: self.start_wait,
117+
#[cfg(feature = "use_tokio")]
118+
http_client: self.http_client.clone(),
119+
})
120+
}
121+
}

src/evalutate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ impl Segment {
483483
pub struct Repository {
484484
pub(crate) segments: HashMap<String, Segment>,
485485
pub(crate) toggles: HashMap<String, Toggle>,
486+
pub(crate) version: Option<String>,
486487
}
487488

488489
fn validate_toggle(_toggle: &Toggle) -> Result<(), FPError> {

src/feature_probe.rs

Lines changed: 22 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ use serde_json::Value;
33
use std::collections::HashMap;
44
use std::fmt::Debug;
55
use std::sync::Arc;
6-
use std::time::Duration;
7-
use tracing::info;
8-
use url::Url;
6+
use tracing::trace;
97

10-
use crate::evalutate::{EvalDetail, Repository};
118
use crate::sync::Synchronizer;
129
use crate::user::FPUser;
13-
use crate::{FPDetail, FPError, SdkAuthorization, Toggle};
10+
use crate::{
11+
config::FPConfig,
12+
evalutate::{EvalDetail, Repository},
13+
};
14+
use crate::{FPDetail, SdkAuthorization, Toggle};
1415
#[cfg(feature = "event")]
1516
use feature_probe_event_std::event::AccessEvent;
1617
#[cfg(feature = "event")]
@@ -23,31 +24,26 @@ use feature_probe_event_tokio::event::AccessEvent;
2324
use feature_probe_event_tokio::recorder::unix_timestamp;
2425
#[cfg(feature = "event_tokio")]
2526
use feature_probe_event_tokio::recorder::EventRecorder;
26-
#[cfg(feature = "use_tokio")]
27-
use reqwest::Client;
2827

2928
#[derive(Debug, Default, Clone)]
3029
pub struct FeatureProbe {
3130
repo: Arc<RwLock<Repository>>,
3231
syncer: Option<Synchronizer>,
3332
#[cfg(any(feature = "event", feature = "event_tokio"))]
3433
event_recorder: Option<EventRecorder>,
35-
config: InnerConfig,
34+
config: FPConfig,
3635
should_stop: Arc<RwLock<bool>>,
3736
}
3837

3938
impl FeatureProbe {
40-
pub fn new(config: FPConfig) -> Result<Self, FPError> {
41-
let config = build_config(config);
39+
pub fn new(config: FPConfig) -> Self {
4240
let mut slf = Self {
4341
config,
4442
..Default::default()
4543
};
4644

47-
match slf.start() {
48-
Ok(_) => Ok(slf),
49-
Err(e) => Err(e),
50-
}
45+
slf.start();
46+
slf
5147
}
5248

5349
pub fn new_for_test(toggle: &str, value: Value) -> Self {
@@ -106,7 +102,7 @@ impl FeatureProbe {
106102

107103
pub fn new_with(server_key: String, repo: Repository) -> Self {
108104
Self {
109-
config: InnerConfig {
105+
config: FPConfig {
110106
server_sdk_key: server_key,
111107
..Default::default()
112108
},
@@ -119,7 +115,7 @@ impl FeatureProbe {
119115
}
120116

121117
pub fn close(&self) {
122-
info!("closing featureprobe client");
118+
trace!("closing featureprobe client");
123119
#[cfg(any(feature = "event", feature = "event_tokio"))]
124120
if let Some(recorder) = &self.event_recorder {
125121
recorder.flush();
@@ -195,19 +191,15 @@ impl FeatureProbe {
195191
None
196192
}
197193

198-
fn start(&mut self) -> Result<(), FPError> {
199-
self.sync()?;
194+
fn start(&mut self) {
195+
self.sync();
200196
#[cfg(any(feature = "event", feature = "event_tokio"))]
201-
self.flush_events()?;
202-
Ok(())
197+
self.flush_events();
203198
}
204199

205-
fn sync(&mut self) -> Result<(), FPError> {
206-
info!("sync url {}", &self.config.toggles_url);
207-
let toggles_url: Url = match Url::parse(&self.config.toggles_url) {
208-
Err(e) => return Err(FPError::UrlError(e.to_string())),
209-
Ok(url) => url,
210-
};
200+
fn sync(&mut self) {
201+
trace!("sync url {}", &self.config.toggles_url);
202+
let toggles_url = self.config.toggles_url.clone();
211203
let refresh_interval = self.config.refresh_interval;
212204
let auth = SdkAuthorization(self.config.server_sdk_key.clone()).encode();
213205
let repo = self.repo.clone();
@@ -220,17 +212,13 @@ impl FeatureProbe {
220212
repo,
221213
);
222214
self.syncer = Some(syncer.clone());
223-
syncer.sync(self.config.start_wait, self.should_stop.clone())?;
224-
Ok(())
215+
syncer.sync(self.config.start_wait, self.should_stop.clone());
225216
}
226217

227218
#[cfg(any(feature = "event", feature = "event_tokio"))]
228-
fn flush_events(&mut self) -> Result<(), FPError> {
229-
info!("flush_events");
230-
let events_url: Url = match Url::parse(&self.config.events_url) {
231-
Err(e) => return Err(FPError::UrlError(e.to_string())),
232-
Ok(url) => url,
233-
};
219+
fn flush_events(&mut self) {
220+
trace!("flush_events");
221+
let events_url = self.config.events_url.clone();
234222
let flush_interval = self.config.refresh_interval;
235223
let auth = SdkAuthorization(self.config.server_sdk_key.clone()).encode();
236224
let should_stop = self.should_stop.clone();
@@ -243,7 +231,6 @@ impl FeatureProbe {
243231
should_stop,
244232
);
245233
self.event_recorder = Some(event_recorder);
246-
Ok(())
247234
}
248235

249236
#[cfg(feature = "internal")]
@@ -252,52 +239,6 @@ impl FeatureProbe {
252239
}
253240
}
254241

255-
#[derive(Debug, Default, Clone)]
256-
pub struct FPConfig {
257-
pub remote_url: String,
258-
pub toggles_url: Option<String>,
259-
pub events_url: Option<String>,
260-
pub server_sdk_key: String,
261-
pub refresh_interval: Duration,
262-
#[cfg(feature = "use_tokio")]
263-
pub http_client: Option<Client>,
264-
pub start_wait: Option<Duration>,
265-
}
266-
267-
#[derive(Debug, Default, Clone)]
268-
pub struct InnerConfig {
269-
pub toggles_url: String,
270-
pub events_url: String,
271-
pub server_sdk_key: String,
272-
pub refresh_interval: Duration,
273-
#[cfg(feature = "use_tokio")]
274-
pub http_client: Option<Client>,
275-
pub start_wait: Option<Duration>,
276-
}
277-
278-
fn build_config(mut config: FPConfig) -> InnerConfig {
279-
info!("build_config from {:?}", config);
280-
if !config.remote_url.ends_with('/') {
281-
config.remote_url += "/";
282-
}
283-
if config.toggles_url.is_none() {
284-
config.toggles_url = Some(config.remote_url.clone() + "api/server-sdk/toggles")
285-
}
286-
if config.events_url.is_none() {
287-
config.events_url = Some(config.remote_url + "api/events")
288-
}
289-
290-
InnerConfig {
291-
toggles_url: config.toggles_url.expect("not none"),
292-
events_url: config.events_url.expect("not none"),
293-
server_sdk_key: config.server_sdk_key,
294-
refresh_interval: config.refresh_interval,
295-
start_wait: config.start_wait,
296-
#[cfg(feature = "use_tokio")]
297-
http_client: config.http_client,
298-
}
299-
}
300-
301242
#[cfg(test)]
302243
mod tests {
303244
use serde_json::json;

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
mod config;
12
mod evalutate;
23
mod feature_probe;
34
mod sync;
45
mod user;
56

7+
pub use crate::config::{FPConfig, FPConfigBuilder};
68
pub use crate::evalutate::{load_json, Repository, Segment, Toggle};
7-
pub use crate::feature_probe::{FPConfig, FeatureProbe};
9+
pub use crate::feature_probe::FeatureProbe;
810
pub use crate::user::FPUser;
911
use headers::{Error, Header, HeaderName, HeaderValue};
1012
use http::header::AUTHORIZATION;

0 commit comments

Comments
 (0)