2424#include < thread> // NOLINT
2525#include < vector>
2626
27- #include " firebase/ app.h"
28- #include " firebase/future .h"
27+ #include " app/src/callback .h"
28+ #include " app/src/time .h"
2929#include " remote_config/src/common.h"
30- #include " remote_config/src/desktop/config_data.h"
31- #include " remote_config/src/desktop/file_manager.h"
3230#include " remote_config/src/desktop/rest.h"
33- #include " remote_config/src/include/firebase/remote_config.h"
3431
3532#ifndef SWIG
3633#include " firebase/variant.h"
@@ -40,6 +37,8 @@ namespace firebase {
4037namespace remote_config {
4138namespace internal {
4239
40+ using callback::NewCallback;
41+
4342const char * const RemoteConfigInternal::kDefaultNamespace = " configns:firebase" ;
4443const char * const RemoteConfigInternal::kDefaultValueForString = " " ;
4544const int64_t RemoteConfigInternal::kDefaultValueForLong = 0L ;
@@ -48,39 +47,54 @@ const bool RemoteConfigInternal::kDefaultValueForBool = false;
4847
4948static const char * kFilePathSuffix = " remote_config_data" ;
5049
50+ template <typename T>
51+ struct RCDataHandle {
52+ RCDataHandle (
53+ ReferenceCountedFutureImpl* _future_api,
54+ const SafeFutureHandle<T>& _future_handle,
55+ RemoteConfigInternal* _rc_internal,
56+ std::vector<std::string> _default_keys = std::vector<std::string>())
57+ : future_api(_future_api),
58+ future_handle (_future_handle),
59+ rc_internal(_rc_internal),
60+ default_keys(_default_keys) {}
61+ ReferenceCountedFutureImpl* future_api;
62+ SafeFutureHandle<T> future_handle;
63+ RemoteConfigInternal* rc_internal;
64+ std::vector<std::string> default_keys;
65+ };
66+
5167RemoteConfigInternal::RemoteConfigInternal (
5268 const firebase::App& app, const RemoteConfigFileManager& file_manager)
5369 : app_(app),
5470 file_manager_(file_manager),
5571 is_fetch_process_have_task_(false ),
56- future_impl_(kRemoteConfigFnCount ) {
72+ future_impl_(kRemoteConfigFnCount ),
73+ safe_this_(this ) {
5774 InternalInit ();
5875}
5976
6077RemoteConfigInternal::RemoteConfigInternal (const firebase::App& app)
6178 : app_(app),
6279 file_manager_(kFilePathSuffix ),
6380 is_fetch_process_have_task_(false ),
64- future_impl_(kRemoteConfigFnCount ) {
81+ future_impl_(kRemoteConfigFnCount ),
82+ safe_this_(this ) {
6583 InternalInit ();
6684}
6785
6886RemoteConfigInternal::~RemoteConfigInternal () {
69- fetch_channel_.Close ();
70- if (fetch_thread_.joinable ()) {
71- fetch_thread_.join ();
72- }
73-
7487 save_channel_.Close ();
7588 if (save_thread_.joinable ()) {
7689 save_thread_.join ();
7790 }
91+
92+ safe_this_.ClearReference ();
7893}
7994
8095void RemoteConfigInternal::InternalInit () {
8196 file_manager_.Load (&configs_);
8297 AsyncSaveToFile ();
83- AsyncFetch ();
8498}
8599
86100bool RemoteConfigInternal::Initialized () const {
@@ -151,7 +165,7 @@ void RemoteConfigInternal::AsyncSaveToFile() {
151165 while (save_channel_.Get ()) {
152166 LayeredConfigs copy;
153167 {
154- std::unique_lock<std::mutex> lock (mutex_ );
168+ MutexLock lock (internal_mutex_ );
155169 copy = configs_;
156170 }
157171 file_manager_.Save (copy);
@@ -225,14 +239,14 @@ Future<void> RemoteConfigInternal::SetDefaults(const ConfigKeyValue* defaults,
225239void RemoteConfigInternal::SetDefaults (
226240 const std::map<std::string, std::string>& defaults_map) {
227241 {
228- std::unique_lock<std::mutex> lock (mutex_ );
242+ MutexLock lock (internal_mutex_ );
229243 configs_.defaults .SetNamespace (defaults_map, kDefaultNamespace );
230244 }
231245 save_channel_.Put ();
232246}
233247
234248std::string RemoteConfigInternal::GetConfigSetting (ConfigSetting setting) {
235- std::unique_lock<std::mutex> lock (mutex_ );
249+ MutexLock lock (internal_mutex_ );
236250 return configs_.metadata .GetSetting (setting);
237251}
238252
@@ -242,7 +256,7 @@ void RemoteConfigInternal::SetConfigSetting(ConfigSetting setting,
242256 return ;
243257 }
244258 {
245- std::unique_lock<std::mutex> lock (mutex_ );
259+ MutexLock lock (internal_mutex_ );
246260 configs_.metadata .AddSetting (setting, value);
247261 }
248262 save_channel_.Put ();
@@ -263,8 +277,7 @@ bool RemoteConfigInternal::CheckValueInConfig(
263277 if (!key) return false ;
264278
265279 {
266- // TODO(b/74461360): Replace the thread locks with firebase ones.
267- std::unique_lock<std::mutex> lock (mutex_);
280+ MutexLock lock (internal_mutex_);
268281 if (!config.HasValue (key, kDefaultNamespace )) {
269282 return false ;
270283 }
@@ -418,7 +431,7 @@ std::vector<std::string> RemoteConfigInternal::GetKeysByPrefix(
418431 if (prefix == nullptr ) return std::vector<std::string>();
419432 std::set<std::string> unique_keys;
420433 {
421- std::unique_lock<std::mutex> lock (mutex_ );
434+ MutexLock lock (internal_mutex_ );
422435 configs_.active .GetKeysByPrefix (prefix, kDefaultNamespace , &unique_keys);
423436 configs_.defaults .GetKeysByPrefix (prefix, kDefaultNamespace , &unique_keys);
424437 }
@@ -433,7 +446,7 @@ std::map<std::string, Variant> RemoteConfigInternal::GetAll() {
433446
434447bool RemoteConfigInternal::ActivateFetched () {
435448 {
436- std::unique_lock<std::mutex> lock (mutex_ );
449+ MutexLock lock (internal_mutex_ );
437450 // Fetched config not found or already activated.
438451 if (configs_.fetched .timestamp () <= configs_.active .timestamp ())
439452 return false ;
@@ -444,63 +457,24 @@ bool RemoteConfigInternal::ActivateFetched() {
444457}
445458
446459const ConfigInfo RemoteConfigInternal::GetInfo () const {
447- std::unique_lock<std::mutex> lock (mutex_ );
460+ MutexLock lock (internal_mutex_ );
448461 return configs_.metadata .info ();
449462}
450463
451- void RemoteConfigInternal::AsyncFetch () {
452- fetch_thread_ = std::thread ([this ]() {
453- SafeFutureHandle<void > handle;
454- while (fetch_channel_.Get ()) {
455- RemoteConfigREST* rest = nullptr ;
456-
457- {
458- std::unique_lock<std::mutex> lock (mutex_);
459- handle = fetch_handle_;
460- rest = new RemoteConfigREST (app_.options (), configs_,
461- cache_expiration_in_seconds_);
462- }
463-
464- // Fetch fresh config from server.
465- rest->Fetch (app_);
466-
467- {
468- std::unique_lock<std::mutex> lock (mutex_);
469-
470- // Need to copy everything to `configs_.fetched`.
471- configs_.fetched = rest->fetched ();
472-
473- // Need to copy only info and digests to `configs_.metadata`.
474- const RemoteConfigMetadata& metadata = rest->metadata ();
475- configs_.metadata .set_info (metadata.info ());
476- configs_.metadata .set_digest_by_namespace (
477- metadata.digest_by_namespace ());
478-
479- delete rest;
480-
481- is_fetch_process_have_task_ = false ;
482- }
483- FutureStatus futureResult =
484- (GetInfo ().last_fetch_status == kLastFetchStatusSuccess )
485- ? kFutureStatusSuccess
486- : kFutureStatusFailure ;
487-
488- FutureData* future_data = FutureData::Get ();
489- future_data->api ()->Complete (handle, futureResult);
490- }
491- });
492- }
493-
494464Future<void > RemoteConfigInternal::Fetch (uint64_t cache_expiration_in_seconds) {
495- std::unique_lock<std::mutex> lock (mutex_ );
465+ MutexLock lock (internal_mutex_ );
496466
497467 uint64_t milliseconds_since_epoch =
498468 std::chrono::duration_cast<std::chrono::milliseconds>(
499469 std::chrono::system_clock::now ().time_since_epoch ())
500470 .count ();
501471
502472 uint64_t cache_expiration_timestamp =
503- configs_.fetched .timestamp () + 1000 * cache_expiration_in_seconds;
473+ configs_.fetched .timestamp () +
474+ ::firebase::internal::kMillisecondsPerSecond *
475+ cache_expiration_in_seconds;
476+
477+ const auto future_handle = future_impl_.SafeAlloc <void >(kRemoteConfigFnFetch );
504478
505479 // Need to fetch in two cases:
506480 // - we are not fetching at this moment
@@ -511,19 +485,58 @@ Future<void> RemoteConfigInternal::Fetch(uint64_t cache_expiration_in_seconds) {
511485 if (!is_fetch_process_have_task_ &&
512486 ((cache_expiration_in_seconds == 0 ) ||
513487 (cache_expiration_timestamp < milliseconds_since_epoch))) {
514- ReferenceCountedFutureImpl* api = FutureData::Get ()->api ();
515- fetch_handle_ = api->SafeAlloc <void >(kRemoteConfigFnFetch );
488+ auto data_handle =
489+ MakeShared<RCDataHandle<void >>(&future_impl_, future_handle, this );
490+
491+ auto callback = NewCallback (
492+ [](ThisRef ref, SharedPtr<RCDataHandle<void >> handle) {
493+ ThisRefLock lock (&ref);
494+ if (lock.GetReference () != nullptr ) {
495+ MutexLock lock (handle->rc_internal ->internal_mutex_ );
496+ RemoteConfigREST* rest = new RemoteConfigREST (
497+ handle->rc_internal ->app_ .options (),
498+ handle->rc_internal ->configs_ ,
499+ handle->rc_internal ->cache_expiration_in_seconds_ );
500+
501+ // Fetch fresh config from server.
502+ rest->Fetch (handle->rc_internal ->app_ );
503+
504+ // Need to copy everything to `configs_.fetched`.
505+ handle->rc_internal ->configs_ .fetched = rest->fetched ();
506+
507+ // Need to copy only info and digests to `configs_.metadata`.
508+ const RemoteConfigMetadata& metadata = rest->metadata ();
509+ handle->rc_internal ->configs_ .metadata .set_info (metadata.info ());
510+ handle->rc_internal ->configs_ .metadata .set_digest_by_namespace (
511+ metadata.digest_by_namespace ());
512+
513+ delete rest;
514+
515+ handle->rc_internal ->is_fetch_process_have_task_ = false ;
516+
517+ FutureStatus futureResult =
518+ (handle->rc_internal ->GetInfo ().last_fetch_status ==
519+ kLastFetchStatusSuccess )
520+ ? kFutureStatusSuccess
521+ : kFutureStatusFailure ;
522+ handle->future_api ->Complete (handle->future_handle , futureResult);
523+ }
524+ },
525+ safe_this_, data_handle);
526+
527+ scheduler_.Schedule (callback);
516528 is_fetch_process_have_task_ = true ;
517- fetch_channel_.Put ();
518529 cache_expiration_in_seconds_ = cache_expiration_in_seconds;
530+ } else {
531+ // Do not fetch, complete future immediately.
532+ future_impl_.Complete (future_handle, kFutureStatusSuccess );
519533 }
520- return FetchLastResult ( );
534+ return MakeFuture< void >(&future_impl_, future_handle );
521535}
522536
523537Future<void > RemoteConfigInternal::FetchLastResult () {
524- ReferenceCountedFutureImpl* api = FutureData::Get ()->api ();
525538 return static_cast <const Future<void >&>(
526- api-> LastResult (kRemoteConfigFnFetch ));
539+ future_impl_. LastResult (kRemoteConfigFnFetch ));
527540}
528541
529542} // namespace internal
0 commit comments