public WSHandler(WSConnection connection, IWSConnectionParameters options) { if (connection == null) { throw new ArgumentNullException(nameof(connection), $"{nameof(connection)} is null."); } if (options == null) { throw new ArgumentNullException(nameof(options), $"{nameof(options)} is null."); } var buffers = connection.Buffers; if (buffers.IsIncomplete) { throw new NotSupportedException($"{nameof(WSConnection.Buffers)} is incomplete"); } Connection = connection; ReadOperations = new WSOperations(buffers, options); SendOperations = new WSOperations(buffers, options); Stopwatch = new Stopwatch(); Heartbeat = options.Heartbeat; ByteBuffer = buffers.ByteBuffer; CharBuffer = buffers.CharBuffer; }
public async Task HeartbeatAsync(CancellationToken cancellationToken = default) { if (Heartbeat < TimeSpan.FromMilliseconds(1)) { return; } if (Stopwatch.IsRunning) { return; } Stopwatch.Restart(); var task = HeartbeatTaskCompletionSource.Task; var random = new Random(); var pulser = default(Task <bool>); var readFrame = default(WSFrame); using (var sendFragment = ByteBuffer.GetFragment(200)) { var sendSegment = sendFragment.GetSegment(); while (cancellationToken.IsCancellationRequested == false) { var delay = Heartbeat - Stopwatch.Elapsed; if (delay.Ticks > 0) { var result = await Task.WhenAny(task, Task.Delay(delay)); if (result == task) { break; } } else { using (await WaitForSendLock(cancellationToken)) { WSOperations.Scramble(sendSegment); pulser = Task.Run(delegate { return(Pulser.Wait(out readFrame, 3000)); }); await SendOperations.SendFrame(new WSFrame { Fragment = sendFragment, Code = WSConsts.CodePing, Last = true, }, cancellationToken); } if (await pulser) { using (var readFragment = readFrame.Fragment) { var readSegment = readFragment.GetSegment(); if (readFrame.Code == WSConsts.CodePong && readFrame.Last && readSegment.SequenceEqual(sendSegment)) { continue; } else { throw new NotSupportedException("Pong is incorrect"); } } } throw new NotSupportedException("Pong is incorrect"); } } Stopwatch.Reset(); } }