private async Task HandshakeAsync(double minTimeoutSeconds) { using (await synchronization.LockAsync().ConfigureAwait(false)) { var isServer = androidBluetoothAdapter.AdapterId.CompareTo(AdapterId) > 0; // Michael's laptop is always the client as windows client doesn't understand being a server. if (Name?.Contains("DESKTOP") ?? false) { isServer = true; } if (isServer) { socket = await inboundBluetoothSocketTable.TakeAsyncOrTimeout(device).ConfigureAwait(false); } else { var socketBox = new AsyncBox <BluetoothSocket>(); new Thread(() => { try { socketBox.SetResult(device.CreateInsecureRfcommSocketToServiceRecord(CampfireNetBluetoothConstants.APP_UUID)); } catch (Exception e) { socketBox.SetException(e); } }).Start(); socket = await socketBox.GetResultAsync().ConfigureAwait(false); var connectedChannel = ChannelFactory.Nonblocking <bool>(); Go(async() => { await socket.ConnectAsync().ConfigureAwait(false); await ChannelsExtensions.WriteAsync(connectedChannel, true); }).Forget(); bool isTimeout = false; await new Select { Case(ChannelFactory.Timer(TimeSpan.FromSeconds(minTimeoutSeconds)), () => { socket.Dispose(); isTimeout = true; }), Case(connectedChannel, () => { // whee! }) }.ConfigureAwait(false); if (isTimeout) { throw new TimeoutException(); } } disconnectedChannel.SetIsClosed(false); ChannelsExtensions.Go(async() => { Console.WriteLine("Entered BT Reader Task"); var networkStream = socket.InputStream; try { while (!disconnectedChannel.IsClosed) { Console.WriteLine("Reading BT Frame"); var dataLengthBuffer = await ReadBytesAsync(networkStream, 4).ConfigureAwait(false); var dataLength = BitConverter.ToInt32(dataLengthBuffer, 0); var data = await ReadBytesAsync(networkStream, dataLength).ConfigureAwait(false); await ChannelsExtensions.WriteAsync(inboundChannel, data).ConfigureAwait(false); } } catch (Exception e) { Console.WriteLine(e); Teardown(); } }).Forget(); } }
private async Task ProcessCaseAsync <T>(ReadableChannel <T> channel, Func <T, Task> callback, Func <T, bool> additionalAcceptanceTest) { try { while (!cts.IsCancellationRequested) { bool isFinalDispatch = false; T item; try { item = await channel.ReadAsync( cts.Token, x => { if (!additionalAcceptanceTest(x)) { return(false); } if (Interlocked.CompareExchange(ref dispatchesRemaining, 0, 0) == kTimesInfinite) { return(true); } else { var spinner = new SpinWait(); while (true) { var capturedDispatchesRemaining = Interlocked.CompareExchange(ref dispatchesRemaining, 0, 0); var nextDispatchesRemaining = capturedDispatchesRemaining - 1; if (nextDispatchesRemaining < 0) { return(false); } if (Interlocked.CompareExchange(ref dispatchesRemaining, nextDispatchesRemaining, capturedDispatchesRemaining) == capturedDispatchesRemaining) { isFinalDispatch = nextDispatchesRemaining == 0; return(true); } spinner.SpinOnce(); } } }).ConfigureAwait(false); } catch (OperationCanceledException) { //Exit processing loop - no dispatches remaining break; } // Signal other case workers to exit if (isFinalDispatch) { cts.Cancel(); } // Execute callback await callback(item).ConfigureAwait(false); // Mark dispatcher as completed, signal awaiters if (isFinalDispatch) { IsCompleted = true; completionBox.SetResult(true); } } } catch (Exception ex) { // Signal all other case workers to exit cts.Cancel(); // Bubble all exceptions up to dispatcher awaiters IsCompleted = true; completionBox.SetException(ex); } }