using System; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Windows; namespace WarframeClock { /// /// Interaction logic for App.xaml /// public partial class App : Application { public static readonly string VersionString = "Warframe Clock Overlay 2019-05-06"; public static readonly string WebsiteUriString = "https://poepoe.org/warframe/clock/"; public static readonly Uri WebsiteUri = new Uri(WebsiteUriString); public static readonly AppData AppData = new AppData(); private Timer _worldStateFetchTimer, _eeLogFetchTimer; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); StartWorldStateFetchTimer(); StartEeLogFetchTimer(); } 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}"); AppData.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(@"^syncing world state jobs in ([0-9.]+)$"); var regexWorldStateRefreshedFromDb = new Regex(@"^Background: world state refreshed from db$"); var regexCetusJoin = new Regex(@"^IRC out: JOIN #H_CETUSHUB4_(.+)$"); var regexArbitration = new Regex(@"^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)); if (reset < DateTimeOffset.UtcNow) return; AppData.NextBountiesReset = reset; Trace.WriteLine($"EE.log: 'syncing world state jobs in'; next bounties reset: {reset}"); } else if ((match = regexWorldStateRefreshedFromDb.Match(args.Content)).Success) { if (AppData.NextBountiesReset == null) return; AppData.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}"); var solNode = WfcdWorldStateData.GetSolNode(match.Groups[1].Value); AppData.ArbitrationSolNodeUpdated = args.DateTime; AppData.ArbitrationSolNode = solNode; } else if ((match = regexKuvaFlood.Match(args.Content)).Success) { if (match.Groups[1].Value == "6" || match.Groups[1].Value == "12") { Trace.WriteLine($"EE.log: Kuva Flood: {match.Groups[2].Value}"); var solNode = WfcdWorldStateData.GetSolNode(match.Groups[2].Value); AppData.KuvaFloodSolNodeUpdated = args.DateTime; AppData.KuvaFloodSolNode = solNode; } } }; parser.OnLogFileReset += (sender, args) => { AppData.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)); } internal void Terminate() { _worldStateFetchTimer.Change(Timeout.Infinite, Timeout.Infinite); _eeLogFetchTimer.Change(Timeout.Infinite, Timeout.Infinite); MainWindow?.Close(); } } }