-
Notifications
You must be signed in to change notification settings - Fork 4
/
PingPong.cs
68 lines (61 loc) · 2.43 KB
/
PingPong.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#region Related components
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using net.vieapps.Components.Utility;
#endregion
namespace net.vieapps.Components.WebSockets
{
internal class PingPongManager
{
readonly WebSocketImplementation _websocket;
readonly CancellationToken _cancellationToken;
readonly Action<ManagedWebSocket, byte[]> _onPong;
readonly Func<ManagedWebSocket, byte[], byte[]> _getPongPayload;
readonly Func<ManagedWebSocket, byte[]> _getPingPayload;
long _pingTimestamp = 0;
public PingPongManager(WebSocketImplementation websocket, WebSocketOptions options, CancellationToken cancellationToken)
{
this._websocket = websocket;
this._cancellationToken = cancellationToken;
this._getPongPayload = options.GetPongPayload;
this._onPong = options.OnPong;
if (this._websocket.KeepAliveInterval != TimeSpan.Zero)
{
this._getPingPayload = options.GetPingPayload;
this.SendPingAsync().Run();
}
}
public void OnPong(byte[] pong)
{
this._pingTimestamp = 0;
this._onPong?.Invoke(this._websocket, pong);
}
public ValueTask SendPongAsync(byte[] ping)
=> this._websocket.SendPongAsync((this._getPongPayload?.Invoke(this._websocket, ping) ?? ping).ToArraySegment(), this._cancellationToken);
public async Task SendPingAsync()
{
Events.Log.PingPongManagerStarted(this._websocket.ID, this._websocket.KeepAliveInterval.TotalSeconds.CastAs<int>());
try
{
while (!this._cancellationToken.IsCancellationRequested)
{
await Task.Delay(this._websocket.KeepAliveInterval, this._cancellationToken).ConfigureAwait(false);
if (this._websocket.State != WebSocketState.Open)
break;
if (this._pingTimestamp != 0)
{
Events.Log.KeepAliveIntervalExpired(this._websocket.ID, (int)this._websocket.KeepAliveInterval.TotalSeconds);
await this._websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, $"No PONG message received in response to a PING message after keep-alive interval ({this._websocket.KeepAliveInterval})", this._cancellationToken).ConfigureAwait(false);
break;
}
this._pingTimestamp = DateTime.Now.ToUnixTimestamp();
await this._websocket.SendPingAsync((this._getPingPayload?.Invoke(this._websocket) ?? this._pingTimestamp.ToBytes()).ToArraySegment(), this._cancellationToken).ConfigureAwait(false);
}
}
catch { }
Events.Log.PingPongManagerEnded(this._websocket.ID);
}
}
}