@@ -131,6 +131,15 @@ PersistentConnection::~PersistentConnection() {
131131 // executing code which requires reference to this.
132132 safe_this_.ClearReference ();
133133
134+ // Clear OnCompletion function for pending token future
135+ {
136+ MutexLock future_lock (pending_token_future_mutex_);
137+ if (pending_token_future_.status () != kFutureStatusInvalid ) {
138+ pending_token_future_.OnCompletion (nullptr , nullptr );
139+ pending_token_future_ = Future<std::string>();
140+ }
141+ }
142+
134143 // Destroy the client so that no more event will be triggered from this point.
135144 realtime_.reset (nullptr );
136145}
@@ -487,21 +496,75 @@ void PersistentConnection::TryScheduleReconnect() {
487496 }
488497
489498 assert (connection_state_ == kDisconnected );
490-
499+ bool force_refresh = force_auth_refresh_;
500+ force_auth_refresh_ = false ;
491501 LogDebug (" %s Scheduling connection attempt" , log_id_.c_str ());
492502
493- // TODO(chkuang): Implement Retry
494- Reconnect ();
503+ // TODO(chkuang): Implement Exponential Backoff Retry
504+ connection_state_ = kGettingToken ;
505+ LogDebug (" %s Trying to fetch auth token" , log_id_.c_str ());
506+
507+ // Get Token Asynchronously to make sure the token is not expired.
508+ Future<std::string> future;
509+ bool succeeded = app_->function_registry ()->CallFunction (
510+ ::firebase::internal::FnAuthGetTokenAsync, app_, &force_refresh, &future);
511+ if (succeeded && future.status () != kFutureStatusInvalid ) {
512+ // Set pending future
513+ MutexLock future_lock (pending_token_future_mutex_);
514+ pending_token_future_ = future;
515+ future.OnCompletion (OnTokenFutureComplete, this );
516+ } else {
517+ // Auth is not available now. Start the connection anyway.
518+ OpenNetworkConnection ();
519+ }
495520}
496521
497- void PersistentConnection::Reconnect () {
498- assert (connection_state_ == kDisconnected );
499- connection_state_ = kGettingToken ;
522+ void PersistentConnection::OnTokenFutureComplete (
523+ const Future<std::string>& result_data, void * user_data) {
524+ assert (user_data);
525+ PersistentConnection* connection =
526+ static_cast <PersistentConnection*>(user_data);
527+ ThisRefLock lock (&connection->safe_this_ );
528+ // If the connection is destroyed or being destroyed, do nothing.
529+ if (!lock.GetReference ()) return ;
530+
531+ {
532+ // Clear pending future
533+ MutexLock future_lock (connection->pending_token_future_mutex_ );
534+ connection->pending_token_future_ = Future<std::string>();
535+ }
500536
501- LogDebug (" %s Trying to fetch auth token" , log_id_.c_str ());
502- GetAuthToken (&auth_token_);
537+ connection->scheduler_ ->Schedule (
538+ new callback::CallbackValue2<ThisRef, Future<std::string>>(
539+ connection->safe_this_ , result_data,
540+ [](ThisRef ref, Future<std::string> future) {
541+ ThisRefLock lock (&ref);
542+ if (lock.GetReference ()) {
543+ lock.GetReference ()->HandleTokenFuture (future);
544+ }
545+ }));
546+ }
503547
504- OpenNetworkConnection ();
548+ void PersistentConnection::HandleTokenFuture (Future<std::string> future) {
549+ if (future.error () == 0 ) {
550+ if (connection_state_ == kGettingToken ) {
551+ LogDebug (" %s Successfully fetched token, opening connection" ,
552+ log_id_.c_str ());
553+ auth_token_ = *future.result ();
554+ OpenNetworkConnection ();
555+ } else {
556+ assert (connection_state_ == kDisconnected );
557+ LogDebug (
558+ " %s Not opening connection after token refresh, because "
559+ " connection was set to disconnected" ,
560+ log_id_.c_str ());
561+ }
562+ } else {
563+ connection_state_ = kDisconnected ;
564+ LogDebug (" %s Error fetching token: %s" , log_id_.c_str (),
565+ future.error_message ());
566+ TryScheduleReconnect ();
567+ }
505568}
506569
507570void PersistentConnection::OpenNetworkConnection () {
@@ -945,6 +1008,7 @@ void PersistentConnection::HandleAuthTokenResponse(const Variant& message,
9451008 }
9461009 } else {
9471010 auth_token_.clear ();
1011+ force_auth_refresh_ = true ;
9481012 event_handler_->OnAuthStatus (false );
9491013
9501014 std::string reason = GetStringValue (message, kServerResponseData );
0 commit comments