private async Task <Server[]> HandshakeAsync(bool reconnect, bool resumable, GatewaySocket socket, IRef <bool> loop) { DiscordDebug.WriteLine("Getting Hello data..."); ReceiveGatewayData data = await socket.ReadAsync(); DiscordDebug.WriteLine("Got Hello data."); if (reconnect) { _listener.UpdateSocket(socket); } else { DiscordDebug.WriteLine("Initializing response listener and heartbeater..."); _listener = new ResponseListener(socket); _heartbeater = new GatewayHeartbeater(_listener, _seqMutex, () => _lastSequence, ConnectAsync); DiscordDebug.WriteLine("Response listener and heartbeater initialized."); } // Need to handle cases where heartbeat timer elapses, thus the event/semaphore model DiscordDebug.WriteLine("Waiting for initial heartbeat ack..."); var signal = new Semaphore(0, 1); bool success = false; void EvtListener(object sender, bool e) { success = e; signal.Release(); } _heartbeater.Started += EvtListener; _heartbeater.Start(data, reconnect); signal.WaitOne(); _heartbeater.Started -= EvtListener; if (success) { DiscordDebug.WriteLine("Heartbeat ack heard."); return(await IdentAsync(reconnect, resumable)); // ReSharper disable once RedundantIfElseBlock } else { DiscordDebug.WriteLine("Heartbeat ack not heard, trying again..."); // Reconnect immediately await _heartbeater.AbortAsync(); _heartbeater.Dispose(); _listener.Dispose(); loop.Value = true; return(null); } }
internal async Task <Server[]> ConnectAsync(bool reconnect, bool resumable) { if (reconnect) { _dispatcher?.TearDown(); } var loop = new SharedRef <bool>(false); int loops = 0; DiscordDebug.WriteLine("Starting connection appempt..."); Server[] res = null; do { if (loops >= _maxConnectAttempts) { throw new GatewayConnectException("Gateway failed to connect " + _maxConnectAttempts + " times, and the connection attempt was aborted."); } loop.Value = false; await _connectMutex.WaitAsync(); if (_listener == null) { string url = await GetGatewayUrlAsync(); DiscordDebug.WriteLine("Opening socket..."); var socket = new GatewaySocket(this); socket.Connect(url); if (socket.State == WebSocketState.Open) { DiscordDebug.WriteLine("Socket opened."); res = await HandshakeAsync(reconnect, resumable, socket, loop); } else { DiscordDebug.WriteLine("Socket opening failed, trying again..."); loop.Value = true; } } _connectMutex.Release(); loops++; } while (loop.Value); DiscordDebug.WriteLine("Connection attempt done."); // ReSharper disable once AssignNullToNotNullAttribute (null value is default to get compiler to shut up - whenever res is null, the loop should continue) return(res); }