1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
// Copyright 2020,2021,2022 Cognite AS
/*!
[Unleash](https://unleash.github.io) is a feature flag API system. This is a
client for it to facilitate using the API to control features in Rust programs.
## Client overview
The client is written using async. Any std compatible async runtime should be
compatible. Examples with async-std and tokio are in the examples/ in the source
tree.
To use it in a sync program, run an async executor and `block_on()` the relevant
calls. As the client specification requires sending background metrics to the API,
you will need to arrange to call the `poll_for_updates` method from a thread as
demonstrated in `examples/threads.rs`.
The unleash defined strategies are included, to support custom strategies
use the `ClientBuilder` and call the `strategy` method to register your custom
strategy memoization function.
```no_run
# mod i {
# cfg_if::cfg_if!{
# if #[cfg(not(feature = "surf"))] {
# pub fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
# Ok(())
# }
# } else {
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::hash::BuildHasher;
use std::time::Duration;
use async_std::task;
use futures_timer::Delay;
use serde::{Deserialize, Serialize};
use enum_map::Enum;
use unleash_api_client::client;
use unleash_api_client::config::EnvironmentConfig;
use unleash_api_client::context::Context;
use unleash_api_client::strategy;
fn _reversed_uids<S: BuildHasher>(
parameters: Option<HashMap<String, String, S>>,
) -> strategy::Evaluate {
let mut uids: HashSet<String> = HashSet::new();
if let Some(parameters) = parameters {
if let Some(uids_list) = parameters.get("userIds") {
for uid in uids_list.split(',') {
uids.insert(uid.chars().rev().collect());
}
}
}
Box::new(move |context: &Context| -> bool {
context
.user_id
.as_ref()
.map(|uid| uids.contains(uid))
.unwrap_or(false)
})
}
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize, Enum, Clone)]
enum UserFeatures {
default
}
# pub
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
let _ = simple_logger::init();
task::block_on(async {
let config = EnvironmentConfig::from_env()?;
let client = client::ClientBuilder::default()
.strategy("reversed", Box::new(&_reversed_uids))
.into_client::<UserFeatures, unleash_api_client::prelude::DefaultClient>(
&config.api_url,
&config.app_name,
&config.instance_id,
config.secret,
)?;
client.register().await?;
futures::future::join(client.poll_for_updates(), async {
// Ensure we have initial load of features completed
Delay::new(Duration::from_millis(500)).await;
assert_eq!(true, client.is_enabled(UserFeatures::default, None, false));
// ... serve more requests
client.stop_poll().await;
}).await;
Ok(())
})
}
# }
# }
# }
# fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
# i::main()
# }
```
Previously there was a Re-export of enum_map::Enum - this trait is part of
our public API. But there is a bug:
https://gitlab.com/KonradBorowski/enum-map/-/issues/22 so instead you must
match the version in your dependencies.
## Crate features
* **backtrace** -
Enable backtrace feature in anyhow (nightly only)
* **default** -
The default feature enables the async-std/surf feature.
* **functional** -
Only relevant to developers: enables the functional test suite.
* **reqwest-client** -
Enables reqwest with OpenSSL TLS support
* **reqwest-client-rustls** -
Enables reqwest with RusTLS support
* **strict** -
Turn unexpected fields in API responses into errors
* **surf-client** -
Enables Surf as the HTTP client to retrieve flags
*/
#![warn(clippy::all)]
#![cfg_attr(feature = "backtrace", feature(backtrace))]
pub mod api;
pub mod client;
pub mod config;
pub mod context;
pub mod http;
pub mod strategy;
// Exports for ergonomical use
pub use crate::client::{Client, ClientBuilder};
pub use crate::config::EnvironmentConfig;
pub use crate::context::Context;
pub use crate::strategy::Evaluate;
/// For the complete minimalist
///
/// ```no_run
/// use serde::{Deserialize, Serialize};
/// use enum_map::Enum;
/// use unleash_api_client::prelude::*;
///
/// let config = EnvironmentConfig::from_env()?;
///
/// #[allow(non_camel_case_types)]
/// #[derive(Debug, Deserialize, Serialize, Enum, Clone)]
/// enum UserFeatures {
/// feature
/// }
///
/// let client = ClientBuilder::default()
/// .into_client::<UserFeatures, DefaultClient>(
/// &config.api_url,
/// &config.app_name,
/// &config.instance_id,
/// config.secret,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>(())
/// ```
pub mod prelude {
pub use crate::client::ClientBuilder;
pub use crate::config::EnvironmentConfig;
cfg_if::cfg_if! {
if #[cfg(feature = "surf")] {
pub use surf::Client as DefaultClient;
} else if #[cfg(feature = "reqwest")] {
pub use reqwest::Client as DefaultClient;
}
}
}