public async Task <T> CancelAfterTimeoutAsync <T>(Func <CancellationToken, Task <T> > taskProvider, TimeSpan timeout, bool throwOnTimeout, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(await taskProvider.Invoke(cancellationToken).ConfigureAwait(false)); } using (var timeoutCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { using (var linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { var stopwatch = new Stopwatch(); stopwatch.Start(); var task = Task.Run(() => taskProvider.Invoke(linkedCancellation.Token)); var firstCompletedTask = await Task.WhenAny(task, CancellableDelay(timeout, timeoutCancellation.Token)).ConfigureAwait(false); stopwatch.Stop(); if (cancellationToken.IsCancellationRequested) { _bleLogger?.Log(LogSender, $"Task was cancelled after {stopwatch.Elapsed} (timeout = {timeout})"); return(await task); } if (ReferenceEquals(firstCompletedTask, task)) { _bleLogger?.Log(LogSender, $"Task was completed after {stopwatch.Elapsed} (timeout = {timeout})"); timeoutCancellation.Cancel(); return(await task); } _bleLogger?.Log(LogSender, $"Task was timed out after {stopwatch.Elapsed} (timeout = {timeout})"); linkedCancellation.Cancel(); if (!throwOnTimeout) { return(await task); } HandleTaskExceptions(task); throw new TimeoutException($"Operation timed out after {timeout}"); } } }
public Task <IBleResult> TryConnectToDeviceAsync(IDevice device, bool connectWhenAvailable, CancellationToken cancellationToken) { _logger?.Log(LogSender, $"Trying to connect to device [DeviceName={device.Name},GUID={device.Id:D}]"); return(_bleAvailability.ExecuteWithBleAvailabilityCheckAsync(async() => { IBleResult result; _logger?.Log(LogSender, $"Internal connect to device started"); try { var connectParameters = new ConnectParameters(connectWhenAvailable); await _bleAdapter.ConnectToDeviceAsync(device, connectParameters, cancellationToken); result = device.State == DeviceState.Connected ? BleResult.Success() : BleResult.Failure(BleFailure.ConnectNotCompleted); } catch (TimeoutException) { result = BleResult.Failure(BleFailure.OperationTimeout); } catch (OperationCanceledException) { result = BleResult.Failure(BleFailure.OperationCancelled); } catch (Exception e) { result = BleResult.Failure(e); } _logger?.Log(LogSender, $"Internal connect to device completed with result: {result}"); return result; })); }
public void HandleTaskExceptions(Task task) { task.ContinueWith(t => { t.Exception.Handle(ex => { _bleLogger.Log(LogSender, $"Unhandled exception {ex.Message}, stacktrace=[{ex.StackTrace}]"); return(true); }); }, TaskContinuationOptions.OnlyOnFaulted); }
private void OnDeviceDiscovered(object sender, DeviceEventArgs e) { try { _logger?.Log(LogSender, $"Device discovered, DeviceName={e.Device?.Name ?? "N/A"}"); if (_deviceFilter.IsWantedDevice(e.Device)) { _logger?.Log(LogSender, $"Wanted device found, DeviceName={e.Device?.Name ?? "N/A"}"); _observer.OnNext(e.Device); if (_stopAfterFirstResult) { _logger?.Log(LogSender, "Completing search"); _searchCancellation.Cancel(); } } } catch (Exception ex) { _logger?.Log(LogSender, $"Exception while discovering device: {ex}"); } }
void IListener <ConnectionEvent> .Notify(ConnectionEvent value) { switch (value) { case ConnectionEvent.ConnectionLost: _executor.RunWithoutAwaiting(RestartConnectionAsync); break; case ConnectionEvent.Disconnected: _logger.Log(LogSender, "WARNING! Device was disconnected while in KeepConnection mode"); break; } }
public SearchAdapter(IAdapter bleAdapter, IObserver <IDevice> observer, IDeviceFilter deviceFilter, bool stopAfterFirstResult, IExecutor executor, IBleLogger logger, CancellationToken cancellationToken) { _bleAdapter = bleAdapter; _observer = observer; _deviceFilter = deviceFilter; _stopAfterFirstResult = stopAfterFirstResult; _executor = executor; _logger = logger; _searchCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); _searchCancellation.Token.Register(OnSearchInterrupted, false); _logger?.Log(LogSender, $"Starting search {DateTime.Now} (stopAfterFirstResult={stopAfterFirstResult})"); _executor.RunWithoutAwaiting(() => TryStartSearchAsync(_searchCancellation.Token)); }