public Shard(GatewaySettings settings, ShardInfo info, IGatewayRatelimiter ratelimiter, string url, ILogger logger) { _jsonSerializerOptions = new JsonSerializerOptions().ConfigureForMyriad(); _settings = settings; _info = info; _ratelimiter = ratelimiter; _url = url; _logger = logger.ForContext <Shard>().ForContext("ShardId", info.ShardId); _stateManager = new ShardStateManager(info, _jsonSerializerOptions, logger) { HandleEvent = HandleEvent, SendHeartbeat = SendHeartbeat, SendIdentify = SendIdentify, SendResume = SendResume, Connect = ConnectInner, Reconnect = Reconnect, }; _stateManager.OnHeartbeatReceived += latency => { HeartbeatReceived?.Invoke(latency); }; _conn = new ShardConnection(_jsonSerializerOptions, _logger); }
private async Task <bool> TickHeartbeat(ShardConnection conn) { // If we don't need to heartbeat, do nothing if (_lastHeartbeatSent == null || _currentHeartbeatInterval == null) { return(true); } if (DateTimeOffset.UtcNow - _lastHeartbeatSent < _currentHeartbeatInterval) { return(true); } // If we haven't received the ack in time, close w/ error if (!_hasReceivedAck) { _logger.Warning( "Shard {ShardId}: Did not receive heartbeat Ack from gateway within interval ({HeartbeatInterval})", ShardId, _currentHeartbeatInterval); State = ShardState.Closing; await conn.Disconnect(WebSocketCloseStatus.ProtocolError, "Did not receive ACK in time"); return(false); } // Otherwise just send it :) await SendHeartbeat(conn); _hasReceivedAck = false; return(true); }
private async Task SendHeartbeat(ShardConnection conn) { _logger.Debug("Shard {ShardId}: Sending heartbeat with seq.no. {LastSequence}", ShardId, SessionInfo.LastSequence); await conn.Send(new GatewayPacket { Opcode = GatewayOpcode.Heartbeat, Payload = SessionInfo.LastSequence }); _lastHeartbeatSent = DateTimeOffset.UtcNow; }
private async Task <bool> Tick(ShardConnection conn) { if (conn.State != WebSocketState.Connecting && conn.State != WebSocketState.Open) { return(false); } if (!await TickHeartbeat(conn)) { // TickHeartbeat returns false if we're disconnecting return(false); } return(true); }