internal async Task OnBackgroundModeChangedAsync(object sender, BackgroundModeChangedEventArgs args) { var goingIntoBackground = args.IsInBackground; var wasInBackground = LockUtils.WithWriteLock(_stateLock, () => { var oldValue = _inBackground; _inBackground = goingIntoBackground; return(oldValue); }); if (goingIntoBackground == wasInBackground) { return; } Log.DebugFormat("Background mode is changing to {0}", goingIntoBackground); if (goingIntoBackground) { if (!Config.EnableBackgroundUpdating) { Log.Debug("Background updating is disabled"); await _connectionManager.SetUpdateProcessorFactory(null, false); return; } Log.Debug("Background updating is enabled, starting polling processor"); } await _connectionManager.SetUpdateProcessorFactory( Factory.CreateUpdateProcessorFactory(_config, User, flagCacheManager, goingIntoBackground), false // don't reset initialized state because the user is still the same ); }
/// <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(); // not awaiting })); }
/// <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.InfoFormat("Offline mode is now {0}", forceOffline); return OpenOrCloseConnectionIfNecessary(); // not awaiting })); }
/// <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.InfoFormat("Network availability is now {0}", networkEnabled); return OpenOrCloseConnectionIfNecessary(); // not awaiting })); }
public void Dispose() { IMobileUpdateProcessor processor = null; LockUtils.WithWriteLock(_lock, () => { if (_disposed) { return; } processor = _updateProcessor; _updateProcessor = null; _updateProcessorFactory = null; _disposed = true; }); processor?.Dispose(); }
/// <summary> /// Sets the factory function for creating an update processor, and attempts to connect if /// appropriate. /// </summary> /// <remarks> /// The factory function encapsulates all the information that <see cref="LdClient"/> takes into /// account when making a connection, i.e. whether we are in streaming or polling mode, the /// polling interval, and the curent user. <c>ConnectionManager</c> itself has no knowledge of /// those things. /// /// Besides updating the private factory function field, we do the following: /// /// If the function is null, we drop our current connection (if any), and we will not make /// any connections no matter what other properties are changed as long as it is still null. /// /// If it is non-null and we already have the same factory function, nothing happens. /// /// If it is non-null and we do not already have the same factory function, but other conditions /// disallow making a connection, nothing happens. /// /// If it is non-null and we do not already have the same factory function, and no other /// conditions disallow making a connection, we create an update processor and tell it to start. /// In this case, we also reset <see cref="Initialized"/> to false if <c>resetInitialized</c> is /// true. /// /// 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="updateProcessorFactory">a factory function or null</param> /// <param name="resetInitialized">true if we should reset the initialized state (e.g. if we /// are switching users</param> /// <returns>a task as described above</returns> public Task <bool> SetUpdateProcessorFactory(Func <IMobileUpdateProcessor> updateProcessorFactory, bool resetInitialized) { return(LockUtils.WithWriteLock(_lock, () => { if (_disposed || _updateProcessorFactory == updateProcessorFactory) { return Task.FromResult(false); } _updateProcessorFactory = updateProcessorFactory; _updateProcessor?.Dispose(); _updateProcessor = null; if (resetInitialized) { _initialized = false; } return OpenOrCloseConnectionIfNecessary(); // not awaiting })); }
/// <inheritdoc/> public async Task <bool> IdentifyAsync(User user) { if (user == null) { throw new ArgumentNullException(nameof(user)); } User newUser = DecorateUser(user); LockUtils.WithWriteLock(_stateLock, () => { _user = newUser; }); SendEventIfOnline(_eventFactoryDefault.NewIdentifyEvent(newUser)); return(await _connectionManager.SetUpdateProcessorFactory( Factory.CreateUpdateProcessorFactory(_config, newUser, flagCacheManager, _inBackground), true )); }
// 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. Log.ErrorFormat("Failed to initialize LaunchDarkly connection: {0}", Util.ExceptionMessage(task.Exception)); return(false); } var success = task.Result; if (success) { LockUtils.WithWriteLock(_lock, () => { _initialized = true; }); return(true); } } return(false); }