/// <summary> /// Verifies that we are currectly connected to the server. If not but we *wish* to be connected, /// it attempts to establish the connection. If not and we don't wish to be connected, it fails. /// </summary> private async Task EnsureConnectedAsync() { if (_client != null) { // We are likely to still be connected. return; } if (!_shouldBeConnected) { throw new Exception("A method was called that requires an IGS connection but the 'Connect()' method was not called; or maybe 'Disconnect()' was called."); } _client = new TcpSocketClient(); try { await _client.ConnectAsync(_hostname, _port); _streamWriter = new StreamWriter(_client.WriteStream); _streamReader = new StreamReader(_client.ReadStream); _streamWriter.AutoFlush = true; #pragma warning disable 4014 HandleIncomingData(_streamReader).ContinueWith(t => { throw new Exception("If this is connection error, then fine, otherwise throw up."); }, TaskContinuationOptions.OnlyOnFaulted); #pragma warning restore 4014 _composure = IgsComposure.InitialHandshake; _streamWriter.WriteLine("guest"); _streamWriter.WriteLine("toggle client on"); await WaitUntilComposureChangesAsync(); } catch { throw new Exception("We failed to establish a connection with the server."); } }
private Task WaitUntilComposureChangesAsync() { IgsComposure originalComposure = _composure; return(Task.Run(() => { lock (_mutexComposureRegained) { while (_composure == originalComposure) { Monitor.Wait(_mutexComposureRegained); } } })); }
/// <summary> /// Connects to IGS at the specified host and port and logs in as a guest account. If we are already connected, /// then this method does nothing. /// </summary> /// <param name="hostname">The hostname to connect to.</param> /// <param name="port">The port to connect to.</param> /// <returns></returns> public async Task <bool> ConnectAsync(string hostname = ServerLocations.IgsPrimary, int port = ServerLocations.IgsPortPrimary) { _hostname = hostname; _port = port; try { if (_client != null && ConnectionEstablished) { // We are likely to still be connected. return(true); } _client = new TcpSocketClient(); try { Composure = IgsComposure.InitialHandshake; await _client.ConnectAsync(_hostname, _port); _streamWriter = new StreamWriter(_client.WriteStream); _streamReader = new StreamReader(_client.ReadStream); _streamWriter.AutoFlush = true; #pragma warning disable 4014 HandleIncomingData(_streamReader).ContinueWith(t => { // Cancel everything. ConnectionLost(); }, TaskContinuationOptions.OnlyOnFaulted); #pragma warning restore 4014 _streamWriter.WriteLine("guest"); _streamWriter.WriteLine("toggle client on"); await WaitUntilComposureChangesAsync(); } catch { Composure = IgsComposure.Disconnected; return(false); } ConnectionEstablished = true; } catch { Composure = IgsComposure.Disconnected; return(false); } return(true); }
/// <summary> /// Unlike other methods, this is not always thread-safe. /// </summary> /// <param name="username">The username.</param> /// <param name="password">The password.</param> public async Task <bool> LoginAsync(string username, string password) { if (username == null) { throw new ArgumentNullException(nameof(username)); } if (password == null) { throw new ArgumentNullException(nameof(password)); } await EnsureConnectedAsync(); _composure = IgsComposure.LoggingIn; _username = username; _password = password; _loginError = null; ClearConnectionInformation(); _streamWriter.WriteLine("login"); _streamWriter.WriteLine(_username); _streamWriter.WriteLine(_password); await WaitUntilComposureChangesAsync(); if (_composure == IgsComposure.Confused) { await _client.DisconnectAsync(); _client = null; return(false); } if (_loginError != null) { OnIncomingLine("LOGIN ERROR: " + _loginError); return(false); } await MakeRequestAsync("toggle quiet true"); await MakeRequestAsync("toggle newundo true"); await MakeRequestAsync("toggle verbose false"); return(true); }
private void ConnectionLost() { LoggedIn = false; if (Composure == IgsComposure.Disconnected) { return; // Don't do this twice. // Thread safety problems may occur. Oh well, it's networking. Hopefully they won't. // If yes, we should eliminate the possibilities for connection loss elsewehere and maybe ensure that a single // point of connection failure exists, possibly in OnFaulted. We'll see. } _client = null; Composure = IgsComposure.Disconnected; ConnectionEstablished = false; foreach (var game in _availableConnectors) { game.Value.Disconnect(); } Data.GamesInProgress.Clear(); Data.OnlineUsers.Clear(); this.GamesYouHaveOpened.Clear(); this.GamesBeingObserved.Clear(); _availableConnectors.Clear(); IgsRequest notYetHandledRequest; while (_outgoingRequests.TryDequeue(out notYetHandledRequest)) { notYetHandledRequest.Disconnect(); } lock (_mutex) { _requestInProgress?.Disconnect(); _requestInProgress = null; } Events.RaiseDisconnected(); }
/// <summary> /// Unlike other methods, this is not always thread-safe. /// </summary> /// <param name="username">The username.</param> /// <param name="password">The password.</param> public async Task <bool> LoginAsync(string username, string password) { if (username == null) { throw new ArgumentNullException(nameof(username)); } if (password == null) { throw new ArgumentNullException(nameof(password)); } try { Events.RaiseLoginPhaseChanged(IgsLoginPhase.Connecting); if (!ConnectionEstablished) { if (!await ConnectAsync()) { return(false); } } Events.RaiseLoginPhaseChanged(IgsLoginPhase.LoggingIn); Composure = IgsComposure.LoggingIn; _username = username; _password = password; _loginError = null; ClearConnectionInformation(); _streamWriter.WriteLine("login"); _streamWriter.WriteLine(_username); _streamWriter.WriteLine(_password); await WaitUntilComposureChangesAsync(); if (Composure == IgsComposure.Confused) { await _client.DisconnectAsync(); _client = null; Events.RaiseLoginComplete(false); return(false); } if (_loginError != null) { Events.OnIncomingLine("LOGIN ERROR: " + _loginError); Events.RaiseLoginComplete(false); return(false); } Events.RaiseLoginPhaseChanged(IgsLoginPhase.SendingInitialBurst); await MakeRequestAsync("toggle quiet true"); await MakeRequestAsync("id omegaGo"); await MakeRequestAsync("toggle newundo true"); await MakeRequestAsync("toggle verbose false"); Events.RaiseLoginPhaseChanged(IgsLoginPhase.RefreshingGames); await Commands.ListGamesInProgressAsync(); Events.RaiseLoginPhaseChanged(IgsLoginPhase.RefreshingUsers); await Commands.ListOnlinePlayersAsync(); Events.RaiseLoginPhaseChanged(IgsLoginPhase.Done); LoggedIn = true; Events.RaiseLoginComplete(true); return(true); } catch { await DisconnectAsync(); return(false); } }