Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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;
        }
Exemple #4
0
        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);
        }