private static async Task CrawlGames(ILogger logger, GamesListingOptions gameListingOptions) { using (FicsClient client = new FicsClient()) { await client.Login(configuration.FicsUsername, configuration.FicsPassword); client.ServerVariables.ShowPromptTime = false; client.ServerVariables.Seek = false; client.ServerVariables.MoveBell = false; client.ServerVariables.Style = 12; client.ServerVariables.ShowProvisionalRatings = true; client.ServerVariables.Interface = "GameCrawler"; client.ServerInterfaceVariables.PreciseTimes = true; client.ServerInterfaceVariables.DetailedGameInfo = true; client.ServerInterfaceVariables.PreMove = true; client.ServerInterfaceVariables.SmartMove = false; client.UnknownMessageReceived += (message) => { logger.LogUnknownMessage(message); }; client.GameStateChange += (state) => { ObservingGame game; lock (observingGames) { if (!observingGames.TryGetValue(state.GameId, out game)) return; } if (state.LastMove != null && state.LastMove != "none") { var move = new ChessMove() { Move = state.LastMove, Time = state.LastMoveTime, }; List<ChessMove> movesList = state.WhiteMove ? game.BlackMovesList : game.WhiteMovesList; int moveNumber = !state.WhiteMove ? state.Move : state.Move - 1; lock (movesList) { while (movesList.Count < moveNumber) { movesList.Add(null); } movesList[moveNumber - 1] = move; } } }; client.GameEnded += (result) => { ObservingGame game; lock (observingGames) { if (observingGames.TryGetValue(result.GameId, out game)) { game.Result = result; Log("Game ended {0}\nWhite moves: {1}\nBlack moves: {2}", game.Game, game.WhiteMovesList.Count, game.BlackMovesList.Count); observingGames.Remove(result.GameId); } } // Check if game was aborted and save otherwise if (game != null && result.WhitePlayerPoints + result.BlackPlayerPoints > 0) { bool save = true; if (game.PartnersGame != null) { if (game.Game.WhitePlayer.Username.CompareTo(game.PartnersGame.Game.WhitePlayer.Username) < 0) { lock (game) lock (game.PartnersGame) { game.Finished = true; if (!game.PartnersGame.Finished) save = false; } } else { lock (game.PartnersGame) lock (game) { game.Finished = true; if (!game.PartnersGame.Finished) save = false; } } } if (save) logger.SaveGame(game); } }; while (client.ConnectionWorking) { var games = await client.ListGames(gameListingOptions); Log("Active games: {0}", games.Count); foreach (var game in games) { if (game.Examined || game.InSetup) continue; bool containsKey; lock (observingGames) { containsKey = observingGames.ContainsKey(game.Id); } if (!containsKey) { try { // Add game to the list var observingGame = new ObservingGame(); observingGame.BlackMovesList = new List<ChessMove>(); observingGame.WhiteMovesList = new List<ChessMove>(); observingGame.Game = game; lock (observingGames) { observingGames.Add(game.Id, observingGame); } // Start observing game var result = await client.StartObservingGame(game); // If we started observing different game, stop observing it if (!result.GameInfo.WhitePlayer.Username.StartsWith(game.WhitePlayer.Username) || !result.GameInfo.BlackPlayer.Username.StartsWith(game.BlackPlayer.Username)) { Log("Canceling game {0}", game); await client.StopObservingGame(game); } Log("Starting game {0}", game); // Collect and update moves list var moveList = await client.GetMoveList(game); observingGame.GameStarted = moveList.GameStarted; lock (observingGame.WhiteMovesList) { while (observingGame.WhiteMovesList.Count < moveList.WhiteMoves.Count) observingGame.WhiteMovesList.Add(null); for (int i = 0; i < moveList.WhiteMoves.Count; i++) observingGame.WhiteMovesList[i] = moveList.WhiteMoves[i]; } lock (observingGame.BlackMovesList) { while (observingGame.BlackMovesList.Count < moveList.BlackMoves.Count) observingGame.BlackMovesList.Add(null); for (int i = 0; i < moveList.BlackMoves.Count; i++) observingGame.BlackMovesList[i] = moveList.BlackMoves[i]; } // Connect partners game if (result.GameInfo.PartnersGameId > 0) { ObservingGame partnersGame; lock (observingGames) { if (observingGames.TryGetValue(result.GameInfo.PartnersGameId, out partnersGame)) { partnersGame.PartnersGame = observingGame; observingGame.PartnersGame = partnersGame; } } } } catch (Exception ex) { logger.LogException(ex); lock (observingGames) { observingGames.Remove(game.Id); } try { await client.StopObservingGame(game.Id); } catch (Exception) { // We want to swallow this exception } } } } await Task.Delay(TimeSpan.FromSeconds(10)); } } }