using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Threading; namespace WarframeClock { public class AppData : IDisposable { public DateTimeOffset NextBountiesResetByWorldState { get; set; } = DateTimeOffset.FromUnixTimeMilliseconds(1548159123053); public DateTimeOffset? NextBountiesReset { get; set; } public DateTimeOffset ArbitrationSolNodeUpdated { get; set; } = DateTimeOffset.FromUnixTimeMilliseconds(0); public WfcdWorldStateData.SolNode ArbitrationSolNode { get; set; } public DateTimeOffset KuvaFloodSolNodeUpdated { get; set; } = DateTimeOffset.FromUnixTimeMilliseconds(0); public WfcdWorldStateData.SolNode KuvaFloodSolNode { get; set; } private Timer _worldStateFetchTimer, _eeLogFetchTimer; public AppData() { StartWorldStateFetchTimer(); StartEeLogFetchTimer(); } public void Dispose() { _worldStateFetchTimer.Change(Timeout.Infinite, Timeout.Infinite); _worldStateFetchTimer.Dispose(); _eeLogFetchTimer.Change(Timeout.Infinite, Timeout.Infinite); _eeLogFetchTimer.Dispose(); } private void StartWorldStateFetchTimer() { _worldStateFetchTimer = new Timer(state => { try { var worldState = WorldState.Fetch().Result; var cetusSyndicate = worldState.SyndicateMissions.FirstOrDefault(mi => mi.Tag == "CetusSyndicate"); if (cetusSyndicate == null) { Trace.WriteLine("WorldState: CetusSyndicate missions not found"); return; } var cetusExpiry = cetusSyndicate.Expiry.Date.NumberLong; Trace.WriteLine($"WorldState: CetusSyndicate missions expire at {cetusExpiry}"); NextBountiesResetByWorldState = DateTimeOffset.FromUnixTimeMilliseconds(cetusExpiry); } catch (Exception ex) { Trace.WriteLine($"WorldState: Failed to fetch or parse worldState.php: {ex}"); Trace.WriteLine(ex.StackTrace); } }, null, TimeSpan.Zero, TimeSpan.FromMinutes(10)); } private void StartEeLogFetchTimer() { var parser = new EeLogParser(); var regexSyncingWorldStateJobs = new Regex(@"^JobNpc.lua: syncing world state jobs in ([0-9.]+)$"); var regexWorldStateRefreshedFromDb = new Regex(@"^Background.lua: Background: world state refreshed from db$"); var regexCetusJoin = new Regex(@"^IRC out: JOIN #H_CETUSHUB4_(.+)$"); var regexArbitration = new Regex(@"^Background.lua: EliteAlertMission at (.+) \(.+\)$"); var regexKuvaFlood = new Regex(@"^KuvaMission(\d+) at (.+)\((.+) - (.+)\)$"); parser.OnLogEntry += (sender, args) => { Match match; if ((match = regexSyncingWorldStateJobs.Match(args.Content)).Success) { var reset = args.DateTime.AddSeconds( double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture)); if (reset < DateTimeOffset.UtcNow) return; NextBountiesReset = reset; Trace.WriteLine($"EE.log: 'syncing world state jobs in'; next bounties reset: {reset}"); } else if ((match = regexWorldStateRefreshedFromDb.Match(args.Content)).Success) { if (NextBountiesReset == null) return; NextBountiesReset = null; Trace.WriteLine($"EE.log: 'world state refreshed from db'; resetting next bounties reset"); } else if ((match = regexCetusJoin.Match(args.Content)).Success) { Trace.WriteLine($"EE.log: Loaded Cetus: {match.Groups[1].Value}"); } else if ((match = regexArbitration.Match(args.Content)).Success) { Trace.WriteLine($"EE.log: Arbitration: {match.Groups[1].Value}"); try { var solNode = WfcdWorldStateData.GetSolNode(match.Groups[1].Value); ArbitrationSolNodeUpdated = args.DateTime; ArbitrationSolNode = solNode; } catch (Exception ex) { Trace.WriteLine($"EE.log: Unknown SolNode"); Trace.WriteLine(ex); } } else if ((match = regexKuvaFlood.Match(args.Content)).Success) { if (match.Groups[1].Value == "6" || match.Groups[1].Value == "12") { Trace.WriteLine($"EE.log: Arbitration: {match.Groups[1].Value}"); try { Trace.WriteLine($"EE.log: Kuva Flood: {match.Groups[2].Value} " + $"({match.Groups[3].Value} - {match.Groups[4].Value})"); var solNode = WfcdWorldStateData.GetSolNodeByName(match.Groups[3].Value, match.Groups[4].Value); KuvaFloodSolNodeUpdated = args.DateTime; KuvaFloodSolNode = solNode; } catch (Exception ex) { Trace.WriteLine($"EE.log: Unknown SolNode"); Trace.WriteLine(ex); } } } }; parser.OnLogFileReset += (sender, args) => { NextBountiesReset = null; }; _eeLogFetchTimer = new Timer(state => { try { parser.Update(); } catch (Exception ex) { Trace.WriteLine($"EE.log: Failed to parse EE.log: {ex}"); Trace.WriteLine(ex.StackTrace); } }, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); } } }