Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{collections::HashMap, env, thread, time::Duration};
use std::{collections::HashMap, env, io::Write, thread, time::Duration};

use appconfiguration::{
AppConfigurationClient, AppConfigurationClientIBMCloud, ConfigurationId, Entity, Feature,
OfflineMode, Property, Value,
AppConfigurationClient, AppConfigurationClientIBMCloud, ConfigurationId, ConfigurationProvider,
Entity, Feature, OfflineMode, Property, Value,
};
use dotenvy::dotenv;
use std::error::Error;
Expand Down Expand Up @@ -54,6 +54,10 @@ fn main() -> std::result::Result<(), Box<dyn Error>> {
let configuration = ConfigurationId::new(guid, environment_id, collection_id);
let client =
AppConfigurationClientIBMCloud::new(&apikey, &region, configuration, OfflineMode::Fail)?;
print!("Waiting for initial data...");
std::io::stdout().flush().unwrap();
client.wait_until_online();
println!(" DONE");

let entity = CustomerEntity {
id: "user123".to_string(),
Expand Down
3 changes: 3 additions & 0 deletions src/client/app_configuration_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ pub trait ConfigurationProvider {
/// For remote configurations, it returns whether it's connected to the
/// remote or not
fn is_online(&self) -> Result<bool>;

/// For remote configurations: Blocks until it's connected to the remote.
fn wait_until_online(&self);
}

/// AppConfiguration client for browsing, and evaluating features and properties.
Expand Down
8 changes: 8 additions & 0 deletions src/client/app_configuration_http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ impl<T: LiveConfiguration> ConfigurationProvider for AppConfigurationClientHttp<
fn is_online(&self) -> Result<bool> {
self.live_configuration.is_online()
}

fn wait_until_online(&self) {
self.live_configuration.wait_until_online();
}
}

#[cfg(test)]
Expand Down Expand Up @@ -131,6 +135,10 @@ mod tests {
fn is_online(&self) -> Result<bool> {
todo!()
}

fn wait_until_online(&self) {
todo!()
}
}
impl LiveConfiguration for LiveConfigurationMock {
fn get_thread_status(
Expand Down
4 changes: 4 additions & 0 deletions src/client/app_configuration_ibm_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ impl ConfigurationProvider for AppConfigurationClientIBMCloud {
fn is_online(&self) -> Result<bool> {
self.client.is_online()
}

fn wait_until_online(&self) {
self.client.wait_until_online();
}
}

#[cfg(test)]
Expand Down
6 changes: 6 additions & 0 deletions src/client/app_configuration_offline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use crate::errors::Result;
use crate::models::{Configuration, FeatureSnapshot, PropertySnapshot};
use crate::ConfigurationProvider;
use log::error;

/// AppConfiguration client using a local file with a configuration snapshot
#[derive(Debug)]
Expand Down Expand Up @@ -55,4 +56,9 @@ impl ConfigurationProvider for AppConfigurationOffline {
fn is_online(&self) -> Result<bool> {
Ok(false)
}

fn wait_until_online(&self) {
error!("Waiting for AppConfigurationOffline to get online. This will never happen.");
std::thread::park(); // block forever
}
}
6 changes: 6 additions & 0 deletions src/models/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::ConfigurationDataError;
use super::feature_snapshot::FeatureSnapshot;
use super::property_snapshot::PropertySnapshot;
use crate::ConfigurationProvider;
use log::error;

/// Represents all the configuration data needed for the client to perform
/// feature/propery evaluation.
Expand Down Expand Up @@ -192,6 +193,11 @@ impl ConfigurationProvider for Configuration {
fn is_online(&self) -> Result<bool> {
Ok(false)
}

fn wait_until_online(&self) {
error!("Waiting for Configuration to get online. This will never happen.");
std::thread::park(); // block forever
}
}

#[cfg(test)]
Expand Down
45 changes: 32 additions & 13 deletions src/network/live_configuration/live_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::{Arc, Mutex};
use std::sync::{Arc, Condvar, Mutex};

use super::current_mode::CurrentModeOfflineReason;
use super::update_thread_worker::UpdateThreadWorker;
use super::{CurrentMode, Error, OfflineMode, Result};
use crate::models::Configuration;
use crate::network::http_client::ServerClient;
use crate::network::live_configuration::current_mode;
use crate::utils::{ThreadHandle, ThreadStatus};
use crate::{ConfigurationId, ConfigurationProvider};
use crate::{AppConfigurationOffline, ConfigurationId, ConfigurationProvider};

/// A [`ConfigurationProvider`] that keeps the configuration updated with some
/// third-party source using an asyncronous mechanism.
Expand All @@ -40,7 +41,7 @@ pub(crate) struct LiveConfigurationImpl {
configuration: Arc<Mutex<Option<Configuration>>>,

/// Current operation mode.
current_mode: Arc<Mutex<CurrentMode>>,
current_mode: Arc<(Mutex<CurrentMode>, Condvar)>,

/// Handler to the internal thread that takes care of updating the [`LiveConfigurationImpl::configuration`].
update_thread: ThreadHandle<Result<()>>,
Expand All @@ -58,9 +59,10 @@ impl LiveConfigurationImpl {
configuration_id: ConfigurationId,
) -> Self {
let configuration = Arc::new(Mutex::new(None));
let current_mode = Arc::new(Mutex::new(CurrentMode::Offline(
CurrentModeOfflineReason::Initializing,
)));
let current_mode = Arc::new((
Mutex::new(CurrentMode::Offline(CurrentModeOfflineReason::Initializing)),
Condvar::new(),
));

let worker = UpdateThreadWorker::new(
server_client,
Expand All @@ -84,7 +86,8 @@ impl LiveConfigurationImpl {
/// configured for this object.
fn get_configuration(&self) -> Result<Configuration> {
// TODO: Can we return a reference instead?
match &*self.current_mode.lock()? {
let (current_mode_mutex, _) = &*self.current_mode;
match &*current_mode_mutex.lock()? {
CurrentMode::Online => {
match &*self.configuration.lock()? {
// We store the configuration retrieved from the server into the Arc<Mutex> before switching the flag to Online
Expand Down Expand Up @@ -122,6 +125,8 @@ impl LiveConfigurationImpl {
}
}

fn assert_type<T>(_val: T) {}

impl ConfigurationProvider for LiveConfigurationImpl {
fn get_feature_ids(&self) -> crate::Result<Vec<String>> {
self.get_configuration()?.get_feature_ids()
Expand All @@ -142,6 +147,16 @@ impl ConfigurationProvider for LiveConfigurationImpl {
fn is_online(&self) -> crate::Result<bool> {
Ok(self.get_current_mode()? == CurrentMode::Online)
}

fn wait_until_online(&self) {
let (current_mode_mutex, condition_variable) = &*self.current_mode;
let current_mode_guard = current_mode_mutex.lock().unwrap();
let _guard = condition_variable
.wait_while(current_mode_guard, |current_mode| {
*current_mode != CurrentMode::Online
})
.unwrap();
}
}

impl LiveConfiguration for LiveConfigurationImpl {
Expand All @@ -150,7 +165,8 @@ impl LiveConfiguration for LiveConfigurationImpl {
}

fn get_current_mode(&self) -> Result<CurrentMode> {
Ok(self.current_mode.lock()?.clone())
let (current_mode_mutex, _) = &*self.current_mode;
Ok(current_mode_mutex.lock()?.clone())
}
}

Expand Down Expand Up @@ -323,7 +339,7 @@ mod tests {
let mut cfg = LiveConfigurationImpl {
configuration: Arc::new(Mutex::new(Some(Configuration::default()))),
offline_mode: OfflineMode::Fail,
current_mode: Arc::new(Mutex::new(CurrentMode::Online)),
current_mode: Arc::new((Mutex::new(CurrentMode::Online), Condvar::new())),
update_thread: ThreadHandle {
_thread_termination_sender: tx,
thread_handle: None,
Expand Down Expand Up @@ -364,9 +380,12 @@ mod tests {
let mut cfg = LiveConfigurationImpl {
offline_mode: OfflineMode::Fail,
configuration: Arc::new(Mutex::new(Some(Configuration::default()))),
current_mode: Arc::new(Mutex::new(CurrentMode::Offline(
CurrentModeOfflineReason::WebsocketClosed,
))),
current_mode: Arc::new((
Mutex::new(CurrentMode::Offline(
CurrentModeOfflineReason::WebsocketClosed,
)),
Condvar::new(),
)),
update_thread: ThreadHandle {
_thread_termination_sender: tx,
thread_handle: None,
Expand Down Expand Up @@ -419,7 +438,7 @@ mod tests {
let mut cfg = LiveConfigurationImpl {
offline_mode: OfflineMode::Fail,
configuration: Arc::new(Mutex::new(Some(Configuration::default()))),
current_mode: Arc::new(Mutex::new(CurrentMode::Defunct(Ok(())))),
current_mode: Arc::new((Mutex::new(CurrentMode::Defunct(Ok(()))), Condvar::new())),
update_thread: ThreadHandle {
_thread_termination_sender: tx,
thread_handle: None,
Expand Down
Loading
Loading