Esempio n. 1
0
 /// <summary>
 /// Tells the <c>ConnectionManager</c> that it can go ahead and connect if appropriate.
 /// </summary>
 /// <returns>a task which will yield true if this method results in a successful connection, or
 /// if we are in offline mode and don't need to make a connection</returns>
 public Task <bool> Start()
 {
     return(LockUtils.WithWriteLock(_lock, () =>
     {
         if (_started)
         {
             return Task.FromResult(_initialized);
         }
         _started = true;
         return OpenOrCloseConnectionIfNecessary(false); // not awaiting
     }));
 }
Esempio n. 2
0
        /// <inheritdoc/>
        public async Task <bool> IdentifyAsync(User user)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            User newUser = _userDecorator.DecorateUser(user);
            User oldUser = newUser; // this initialization is overwritten below, it's only here to satisfy the compiler

            LockUtils.WithWriteLock(_stateLock, () =>
            {
                oldUser = _user;
                _user   = newUser;
            });

            // If we had cached data for the new user, set the current in-memory flag data state to use
            // that data, so that any Variation calls made before Identify has completed will use the
            // last known values. If we did not have cached data, then we update the current in-memory
            // state to reflect that there is no flag data, so that Variation calls done before completion
            // will receive default values rather than the previous user's values. This does not modify
            // any flags in persistent storage, and (currently) it does *not* trigger any FlagValueChanged
            // events from FlagTracker.
            var cachedData = _dataStore.GetCachedData(newUser);

            if (cachedData != null)
            {
                _log.Debug("Identify found cached flag data for the new user");
            }
            _dataStore.Init(
                newUser,
                cachedData ?? new DataStoreTypes.FullDataSet(null),
                false // false means "don't rewrite the flags to persistent storage"
                );

            EventProcessorIfEnabled().RecordIdentifyEvent(new EventProcessorTypes.IdentifyEvent
            {
                Timestamp = UnixMillisecondTime.Now,
                User      = user
            });
            if (oldUser.Anonymous && !newUser.Anonymous && !_config.AutoAliasingOptOut)
            {
                EventProcessorIfEnabled().RecordAliasEvent(new EventProcessorTypes.AliasEvent
                {
                    Timestamp    = UnixMillisecondTime.Now,
                    User         = user,
                    PreviousUser = oldUser
                });
            }

            return(await _connectionManager.SetUser(newUser));
        }
Esempio n. 3
0
 /// <summary>
 /// Updates the current user.
 /// </summary>
 /// <param name="user">the new user</param>
 /// <returns>a task that is completed when we have received data for the new user, if the
 /// data source is online, or completed immediately otherwise</returns>
 public Task <bool> SetUser(User user)
 {
     return(LockUtils.WithWriteLock(_lock, () =>
     {
         if (_disposed)
         {
             return Task.FromResult(false);
         }
         _user = user;
         _initialized = false;
         return OpenOrCloseConnectionIfNecessary(true);
     }));
 }
Esempio n. 4
0
 /// <summary>
 /// Sets whether the application is currently in the background.
 /// </summary>
 /// <remarks>
 /// When in the background, we use a different data source (polling, at a longer interval)
 /// and we do not send diagnostic events.
 /// </remarks>
 /// <param name="inBackground">true if the application is now in the background</param>
 public void SetInBackground(bool inBackground)
 {
     LockUtils.WithWriteLock(_lock, () =>
     {
         if (_disposed || _inBackground == inBackground)
         {
             return;
         }
         _inBackground = inBackground;
         _log.Debug("Background mode is changing to {0}", inBackground);
         _ = OpenOrCloseConnectionIfNecessary(true); // not awaiting
     });
 }
Esempio n. 5
0
 /// <summary>
 /// Sets whether we should be able to make network connections, and attempts to connect if appropriate.
 /// </summary>
 /// <remarks>
 /// Besides updating the value of the <see cref="NetworkEnabled"/> property, we do the
 /// following:
 ///
 /// If <c>networkEnabled</c> is false, we drop our current connection (if any), and we will not
 /// make any connections no matter what other properties are changed as long as this property is
 /// still true.
 ///
 /// If <c>networkEnabled</c> is true and we already have a connection, nothing happens.
 ///
 /// If <c>networkEnabled</c> is true and we have no connection, but other conditions disallow
 /// making a connection (or we do not have an update processor factory), nothing happens.
 ///
 /// If <c>networkEnabled</c> is true, and we do not yet have a connection, and no other
 /// conditions disallow making a connection, and we have an update processor factory,
 /// we create an update processor and tell it to start.
 ///
 /// The returned task is immediately completed unless we are making a new connection, in which
 /// case it is completed when the update processor signals success or failure. The task yields
 /// a true result if we successfully made a connection <i>or</i> if we decided not to connect
 /// because we are in offline mode. In other words, the result is true if
 /// <see cref="Initialized"/> is true.
 /// </remarks>
 /// <param name="networkEnabled">true if we think we can make network connections</param>
 /// <returns>a task as described above</returns>
 public Task <bool> SetNetworkEnabled(bool networkEnabled)
 {
     return(LockUtils.WithWriteLock(_lock, () =>
     {
         if (_disposed || _networkEnabled == networkEnabled)
         {
             return Task.FromResult(false);
         }
         _networkEnabled = networkEnabled;
         _log.Info("Network availability is now {0}", networkEnabled);
         return OpenOrCloseConnectionIfNecessary(false); // not awaiting
     }));
 }
Esempio n. 6
0
 /// <summary>
 /// Sets whether the client should always be offline, and attempts to connect if appropriate.
 /// </summary>
 /// <remarks>
 /// Besides updating the value of the <see cref="ForceOffline"/> property, we do the
 /// following:
 ///
 /// If <c>forceOffline</c> is true, we drop our current connection (if any), and we will not
 /// make any connections no matter what other properties are changed as long as this property is
 /// still true.
 ///
 /// If <c>forceOffline</c> is false and we already have a connection, nothing happens.
 ///
 /// If <c>forceOffline</c> is false and we have no connection, but other conditions disallow
 /// making a connection (or we do not have an update processor factory), nothing happens.
 ///
 /// If <c>forceOffline</c> is false, and we do not yet have a connection, and no other
 /// conditions disallow making a connection, and we have an update processor factory,
 /// we create an update processor and tell it to start.
 ///
 /// The returned task is immediately completed unless we are making a new connection, in which
 /// case it is completed when the update processor signals success or failure. The task yields
 /// a true result if we successfully made a connection <i>or</i> if we decided not to connect
 /// because we are in offline mode. In other words, the result is true if
 /// <see cref="Initialized"/> is true.
 /// </remarks>
 /// <param name="forceOffline">true if the client should always be offline</param>
 /// <returns>a task as described above</returns>
 public Task <bool> SetForceOffline(bool forceOffline)
 {
     return(LockUtils.WithWriteLock(_lock, () =>
     {
         if (_disposed || _forceOffline == forceOffline)
         {
             return Task.FromResult(false);
         }
         _forceOffline = forceOffline;
         _log.Info("Offline mode is now {0}", forceOffline);
         return OpenOrCloseConnectionIfNecessary(false); // not awaiting
     }));
 }
Esempio n. 7
0
        public void Dispose()
        {
            IDataSource dataSource = null;

            LockUtils.WithWriteLock(_lock, () =>
            {
                if (_disposed)
                {
                    return;
                }
                dataSource  = _dataSource;
                _dataSource = null;
                _disposed   = true;
            });
            dataSource?.Dispose();
        }
Esempio n. 8
0
        // When this method is called, we are no longer holding the lock.

        private bool SetInitializedIfUpdateProcessorStartedSuccessfully(Task <bool> task)
        {
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    // Don't let exceptions from the update processor propagate up into the SDK. Just say we didn't initialize.
                    LogHelpers.LogException(_log, "Failed to initialize LaunchDarkly connection", task.Exception);
                    return(false);
                }
                var success = task.Result;
                if (success)
                {
                    LockUtils.WithWriteLock(_lock, () =>
                    {
                        _initialized = true;
                    });
                    return(true);
                }
            }
            return(false);
        }