public async Task GameLogEventDetection_WorksAfterFileSizeReset() { var reader = A.Fake <IGameLogReader>(); var factory = A.Fake <IGameLogReaderFactory>(); A.CallTo(() => factory.CreateGameLogReader(A <Uri[]> .Ignored, A <IEventParser> .Ignored)) .Returns(reader); var detect = new GameLogEventDetection(serviceProvider.GetService <IW4MServer>(), new Uri[] { new Uri("C:\\test.log") }, factory); A.CallTo(() => reader.Length) .Returns(100) .Once() .Then .Returns(200) .Once() .Then .Returns(10) .Once() .Then .Returns(100); for (int i = 0; i < 4; i++) { await detect.UpdateLogEvents(); } A.CallTo(() => reader.ReadEventsFromLog(A <long> .Ignored, A <long> .Ignored)) .MustHaveHappenedTwiceExactly(); }
public async Task Initialize() { RconParser = Manager.AdditionalRConParsers .FirstOrDefault(_parser => _parser.Version == ServerConfig.RConParserVersion); EventParser = Manager.AdditionalEventParsers .FirstOrDefault(_parser => _parser.Version == ServerConfig.EventParserVersion); RconParser = RconParser ?? new BaseRConParser(); EventParser = EventParser ?? new BaseEventParser(); RemoteConnection.SetConfiguration(RconParser.Configuration); var version = await this.GetDvarAsync <string>("version"); Version = version.Value; GameName = Utilities.GetGame(version?.Value ?? RconParser.Version); if (GameName == Game.UKN) { GameName = RconParser.GameName; } if (version?.Value?.Length != 0) { RconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => _parser.Version == version.Value) ?? RconParser; EventParser = Manager.AdditionalEventParsers.FirstOrDefault(_parser => _parser.Version == version.Value) ?? EventParser; Version = RconParser.Version; } var infoResponse = RconParser.Configuration.CommandPrefixes.RConGetInfo != null ? await this.GetInfoAsync() : null; // this is normally slow, but I'm only doing it because different games have different prefixes var hostname = infoResponse == null ? (await this.GetDvarAsync <string>("sv_hostname")).Value : infoResponse.Where(kvp => kvp.Key.Contains("hostname")).Select(kvp => kvp.Value).First(); var mapname = infoResponse == null ? (await this.GetDvarAsync <string>("mapname")).Value : infoResponse["mapname"]; int maxplayers = (GameName == Game.IW4) ? // gotta love IW4 idiosyncrasies (await this.GetDvarAsync <int>("party_maxplayers")).Value : infoResponse == null ? (await this.GetDvarAsync <int>("sv_maxclients")).Value : Convert.ToInt32(infoResponse["sv_maxclients"]); var gametype = infoResponse == null ? (await this.GetDvarAsync <string>("g_gametype")).Value : infoResponse.Where(kvp => kvp.Key.Contains("gametype")).Select(kvp => kvp.Value).First(); var basepath = await this.GetDvarAsync <string>("fs_basepath"); var game = infoResponse == null || !infoResponse.ContainsKey("fs_game") ? (await this.GetDvarAsync <string>("fs_game")).Value : infoResponse["fs_game"]; var logfile = await this.GetDvarAsync <string>("g_log"); var logsync = await this.GetDvarAsync <int>("g_logsync"); var ip = await this.GetDvarAsync <string>("net_ip"); WorkingDirectory = basepath.Value; try { var website = await this.GetDvarAsync <string>("_website"); Website = website.Value; } catch (DvarException) { Website = loc["SERVER_WEBSITE_GENERIC"]; } InitializeMaps(); this.Hostname = hostname.StripColors(); this.CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; this.MaxClients = maxplayers; this.FSGame = game; this.Gametype = gametype; this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress; if ((logsync.Value == 0 || logfile.Value == string.Empty) && RconParser.CanGenerateLogPath) { // this DVAR isn't set until the a map is loaded await this.SetDvarAsync("logfile", 2); await this.SetDvarAsync("g_logsync", 2); // set to 2 for continous in other games, clamps to 1 for IW4 //await this.SetDvarAsync("g_log", "games_mp.log"); Logger.WriteWarning("Game log file not properly initialized, restarting map..."); await this.ExecuteCommandAsync("map_restart"); logfile = await this.GetDvarAsync <string>("g_log"); } CustomCallback = await ScriptLoaded(); // they've manually specified the log path if (!string.IsNullOrEmpty(ServerConfig.ManualLogPath)) { LogPath = ServerConfig.ManualLogPath; } else { string mainPath = EventParser.Configuration.GameDirectory; LogPath = string.IsNullOrEmpty(game) ? $"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile?.Value}" : $"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game?.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile?.Value}"; // fix wine drive name mangling if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { LogPath = Regex.Replace($"{Path.DirectorySeparatorChar}{LogPath}", @"[A-Z]:/", ""); } if (!File.Exists(LogPath) && ServerConfig.GameLogServerUrl == null) { Logger.WriteError(loc["SERVER_ERROR_DNE"].FormatExt(LogPath)); throw new ServerException(loc["SERVER_ERROR_DNE"].FormatExt(LogPath)); } } LogEvent = new GameLogEventDetection(this, LogPath, ServerConfig.GameLogServerUrl); Logger.WriteInfo($"Log file is {LogPath}"); _ = Task.Run(() => LogEvent.PollForChanges()); #if !DEBUG Broadcast(loc["BROADCAST_ONLINE"]); #endif }