private void Controller_RefreshComplete() { Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh complete"); RefreshButton(true); actioncontroller.ActionRunOnRefresh(); if (EDCommander.Current.SyncToInara && history.GetLast != null) { EliteDangerousCore.Inara.InaraSync.Refresh(LogLine, history.GetLast, EDCommander.Current); } if (DLLManager.Count > 0) { HistoryEntry lastfileh = history.GetLastHistoryEntry(x => x.EntryType == JournalTypeEnum.Fileheader); if (lastfileh != null) { for (int i = lastfileh.EntryNumber - 1; i < history.Count; i++) // play thru last history entries up to last file position for the DLLs, indicating stored { //System.Diagnostics.Debug.WriteLine("{0} : {1} {2}", i, history.EntryOrder[i].EventTimeUTC, history.EntryOrder[i].EventSummary); DLLManager.NewJournalEntry(EliteDangerousCore.DLL.EDDDLLCallerHE.CreateFromHistoryEntry(history, history[i]), true); } } DLLManager.Refresh(EDCommander.Current.Name, EliteDangerousCore.DLL.EDDDLLCallerHE.CreateFromHistoryEntry(history, history.GetLast)); } FrontierCAPI.Disconnect(); // Disconnect capi from current user, but don't clear their credential file // available, and not hidden commander, and we have logged in previously if (FrontierCAPI.ClientIDAvailable && EDCommander.Current.Id >= 0 && FrontierCAPI.HasUserBeenLoggedIn(EDCommander.Current.Name)) { System.Threading.Tasks.Task.Run(() => // don't hold up the main thread, do it in a task, as its a HTTP operation { if (FrontierCAPI.LogIn(EDCommander.Current.Name)) // try and get to Active. May cause a new frontier login { LogLine(FrontierCAPI.Active ? "CAPI User Logged in" : "CAPI User requires new log in"); } }); } Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh complete finished"); if (EDCommander.Current.SyncToEdsm) // no sync, no credentials, no action { EDSMClass edsm = new EDSMClass(); if (edsm.ValidCredentials) { EDSMSend(); } } }
// this thread waits around until told to do a refresh then performs it. // ONLY used for subsequent refreshes, first one done on background worker private void BackgroundHistoryRefreshWorkerThread() { System.Diagnostics.Debug.WriteLine("Background history refresh worker thread going.. waiting for read for refresh"); WaitHandle.WaitAny(new WaitHandle[] { closeRequested, readyForNewRefresh }); // Wait to be ready for new refresh after initial load caused by DoRefreshHistory, called by the controller. It sets the flag System.Diagnostics.Debug.WriteLine("Background history refresh worker thread refresh given permission, close " + PendingClose); int capirefreshinterval = 10000; // how often we check CAPI system. This is not the poll interval. while (!PendingClose) { int wh = WaitHandle.WaitAny(new WaitHandle[] { closeRequested, refreshRequested }, capirefreshinterval); // wait for a second and subsequent refresh request. if (PendingClose) { break; } switch (wh) { case 0: // Close Requested break; case 1: // Refresh Requested journalmonitor.StopMonitor(); // this is called by the foreground. Ensure background is stopped. Foreground must restart it. EdsmLogFetcher.AsyncStop(); InvokeAsyncOnUiThread(() => { OnRefreshStarting?.Invoke(); }); RefreshWorkerArgs argstemp = null; RefreshWorkerArgs args = null; while (refreshWorkerQueue.TryDequeue(out argstemp)) // Get the most recent refresh { args = argstemp; } if (args != null) { readyForNewRefresh.Reset(); DoRefreshHistory(args); WaitHandle.WaitAny(new WaitHandle[] { closeRequested, readyForNewRefresh }); // Wait to be ready for new refresh } break; case WaitHandle.WaitTimeout: if (EDCommander.Current.ConsoleCommander && FrontierCAPI.Active) { var retstate = FrontierCAPI.ManageJournalDownload(EDCommander.Current.ConsoleUploadHistory, EDDOptions.Instance.CAPIDirectory(), EDCommander.Current.Name, new TimeSpan(0, 30, 0), // journal poll interval 28); // and days back in time to look if (EDCommander.Current.ConsoleUploadHistory == null || !retstate.DeepEquals(EDCommander.Current.ConsoleUploadHistory)) // if changed { EDCommander.Current.ConsoleUploadHistory = retstate; EDCommander.Current.Update(); } } break; } } }
// Called on foreground after history has refreshed private void ForegroundHistoryRefreshCompleteonUI(HistoryList hist) { Debug.Assert(System.Windows.Forms.Application.MessageLoop); if (!PendingClose) { Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh history worker completed"); if (hist != null) { history.Copy(hist); OnRefreshCommanders?.Invoke(); EdsmLogFetcher.StopCheck(); Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh Displays"); OnHistoryChange?.Invoke(history); Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh Displays Completed"); } Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " JM On"); journalmonitor.StartMonitor(true); Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Call Refresh Complete"); OnRefreshComplete?.Invoke(); // History is completed FrontierCAPI.Disconnect(); // Disconnect capi from current user, but don't clear their credential file // available, and not hidden commander, and we have logged in before if (FrontierCAPI.ClientIDAvailable && EDCommander.Current.Id >= 0 && FrontierCAPI.GetUserState(EDCommander.Current.Name) != CAPI.CompanionAPI.UserState.NeverLoggedIn) { System.Threading.Tasks.Task.Run(() => // don't hold up the main thread, do it in a task, as its a HTTP operation { FrontierCAPI.LogIn(EDCommander.Current.Name); // try and get to Active. May cause a new frontier login if (FrontierCAPI.Active) // if active, indicate { LogLine("CAPI User Logged in"); } else { LogLine("CAPI Require Log in"); } }); } if (history.CommanderId >= 0) { EdsmLogFetcher.Start(EDCommander.Current); } refreshHistoryRequestedFlag = 0; readyForNewRefresh.Set(); // say i'm okay for another refresh System.Diagnostics.Debug.WriteLine("Refresh completed, allow another refresh"); LogLine("History refresh complete.".T(EDTx.EDDiscoveryController_HRC)); ReportRefreshProgress(-1, ""); Trace.WriteLine(BaseUtils.AppTicks.TickCountLap() + " Refresh history complete"); } }
public void DoCAPI(string station, string system, bool beta, bool?allowcobramkiv) { // don't hold up the main thread, do it in a task, as its a HTTP operation System.Threading.Tasks.Task.Run(() => { bool donemarket = false, doneshipyard = false; for (int tries = 3; tries >= 1 && (donemarket == false || doneshipyard == false); tries--) { Thread.Sleep(10000); // for the first go, give the CAPI servers a chance to update, for the next goes, spread out the requests FrontierCAPI.GameIsBeta = beta; if (!donemarket) { string marketjson = FrontierCAPI.Market(); if (marketjson != null) { System.IO.File.WriteAllText(@"c:\code\market.json", marketjson); CAPI.Market mk = new CAPI.Market(marketjson); if (mk.IsValid && station.Equals(mk.Name, StringComparison.InvariantCultureIgnoreCase)) { System.Diagnostics.Trace.WriteLine($"CAPI got market {mk.Name}"); var entry = new EliteDangerousCore.JournalEvents.JournalEDDCommodityPrices(DateTime.UtcNow, mk.ID, mk.Name, system, EDCommander.CurrentCmdrID, mk.Commodities); var jo = entry.ToJSON(); // get json of it, and add it to the db entry.Add(jo); InvokeAsyncOnUiThread(() => { Debug.Assert(System.Windows.Forms.Application.MessageLoop); NewJournalEntryFromScanner(entry, null); // then push it thru. this will cause another set of calls to NewEntry First/Second // EDDN handler will pick up EDDCommodityPrices and send it. }); donemarket = true; Thread.Sleep(500); // space the next check out a bit } } } if (!donemarket) { LogLine("CAPI failed to get market data" + (tries > 1 ? ", retrying" : ", give up")); } if (!doneshipyard) { string shipyardjson = FrontierCAPI.Shipyard(); if (shipyardjson != null) { CAPI.Shipyard sh = new CAPI.Shipyard(shipyardjson); System.IO.File.WriteAllText(@"c:\code\shipyard.json", shipyardjson); if (sh.IsValid && station.Equals(sh.Name, StringComparison.InvariantCultureIgnoreCase)) { System.Diagnostics.Trace.WriteLine($"CAPI got shipyard {sh.Name}"); var modules = sh.GetModules(); if (modules?.Count > 0) { var list = modules.Select(x => new Tuple <long, string, long>(x.ID, x.Name.ToLower(), x.Cost)).ToArray(); var outfitting = new EliteDangerousCore.JournalEvents.JournalOutfitting(DateTime.UtcNow, station, system, sh.ID, list, EDCommander.CurrentCmdrID); var jo = outfitting.ToJSON(); // get json of it, and add it to the db outfitting.Add(jo); InvokeAsyncOnUiThread(() => { NewJournalEntryFromScanner(outfitting, null); // then push it thru. this will cause another set of calls to NewEntry First/Second, then EDDN will send it }); } var shipyard = sh.GetShips(); if (shipyard?.Count > 0 && allowcobramkiv.HasValue) { var list = shipyard.Select(x => new Tuple <long, string, long>(x.ID, x.Name.ToLower(), x.BaseValue)).ToArray(); var shipyardevent = new EliteDangerousCore.JournalEvents.JournalShipyard(DateTime.UtcNow, station, system, sh.ID, list, EDCommander.CurrentCmdrID, allowcobramkiv.Value); var jo = shipyardevent.ToJSON(); // get json of it, and add it to the db shipyardevent.Add(jo); InvokeAsyncOnUiThread(() => { NewJournalEntryFromScanner(shipyardevent, null); // then push it thru. this will cause another set of calls to NewEntry First/Second, then EDDN will send it }); } doneshipyard = true; } } } if (!doneshipyard) { LogLine("CAPI failed to get shipyard data" + (tries > 1 ? ", retrying" : ", give up")); } } }); }
private void ActionEntry(JournalEntry je) // UI thread issue the JE to the system { System.Diagnostics.Trace.WriteLine(string.Format(Environment.NewLine + "New JEntry {0} {1}", je.EventTimeUTC, je.EventTypeStr)); OnNewJournalEntry?.Invoke(je); // Always call this on all entries... // filter out commanders, and filter out any UI events if (je.CommanderId == history.CommanderId) { BaseUtils.AppTicks.TickCountLapDelta("CTNE", true); HistoryEntry he = history.AddJournalEntryToHistory(je, h => LogLineHighlight(h)); // add a new one on top var t1 = BaseUtils.AppTicks.TickCountLapDelta("CTNE"); if (t1.Item2 >= 20) { System.Diagnostics.Trace.WriteLine(" NE Add Journal slow " + t1.Item1); } if (he != null) // may reject it { if (OnNewEntry != null) { foreach (var e in OnNewEntry.GetInvocationList()) // do the invokation manually, so we can time each method { Stopwatch sw = new Stopwatch(); sw.Start(); e.DynamicInvoke(he, history); if (sw.ElapsedMilliseconds >= 20) { System.Diagnostics.Trace.WriteLine(" NE Add Method " + e.Method.DeclaringType + " took " + sw.ElapsedMilliseconds); } } } var t2 = BaseUtils.AppTicks.TickCountLapDelta("CTNE"); if (t2.Item2 >= 40) { System.Diagnostics.Trace.WriteLine(" NE First Slow " + t2.Item1); } OnNewEntrySecond?.Invoke(he, history); // secondary hook.. // finally, CAPI, if docked, try and get commodity data, and if so, create a new EDD record. Do not do this for console commanders if (he.EntryType == JournalTypeEnum.Docked) { if (FrontierCAPI.Active && !EDCommander.Current.ConsoleCommander) { // don't hold up the main thread, do it in a task, as its a HTTP operation // and wait for the CAPI to recover by delaying for 15 s System.Threading.Tasks.Task.Delay(15000).ContinueWith((task) => { var dockevt = he.journalEntry as EliteDangerousCore.JournalEvents.JournalDocked; for (int tries = 0; tries < 3; tries++) { FrontierCAPI.GameIsBeta = he.journalEntry.IsBeta; string marketjson = FrontierCAPI.Market(); CAPI.Market mk = new CAPI.Market(marketjson); if (mk.IsValid) { //System.IO.File.WriteAllText(@"c:\code\market.json", marketjson); if (dockevt.StationName.Equals(mk.Name, StringComparison.InvariantCultureIgnoreCase)) { System.Diagnostics.Trace.WriteLine($"CAPI got market {mk.Name}"); var entry = new EliteDangerousCore.JournalEvents.JournalEDDCommodityPrices(he.EventTimeUTC.AddSeconds(1), mk.ID, mk.Name, he.System.Name, EDCommander.CurrentCmdrID, mk.Commodities); var jo = entry.ToJSON(); // get json of it, and add it to the db entry.Add(jo); InvokeAsyncOnUiThread(() => { Debug.Assert(System.Windows.Forms.Application.MessageLoop); System.Diagnostics.Debug.WriteLine("CAPI fire new entry"); NewEntry(entry); // then push it thru. this will cause another set of calls to NewEntry First/Second // EDDN handler will pick up EDDCommodityPrices and send it. }); break; } else { LogLine("CAPI received incorrect information, retrying"); System.Diagnostics.Trace.WriteLine($"CAPI disagree on market {dockevt.StationName} vs {mk.Name}"); } } else { LogLine("CAPI market data invalid, retrying"); System.Diagnostics.Trace.WriteLine($"CAPI market invalid {marketjson}"); } Thread.Sleep(10000); } }); } } var t3 = BaseUtils.AppTicks.TickCountLapDelta("CTNE"); System.Diagnostics.Trace.WriteLine("NE END " + t3.Item1 + " " + (t3.Item3 > 99 ? "!!!!!!!!!!!!!" : "")); } } if (je.EventTypeID == JournalTypeEnum.LoadGame) // and issue this on Load game { OnRefreshCommanders?.Invoke(); } }
private void Controller_NewEntrySecond(HistoryEntry he, HistoryList hl) // called after all UI's have had their chance { BaseUtils.AppTicks.TickCountLapDelta("DFS", true); actioncontroller.ActionRunOnEntry(he, Actions.ActionEventEDList.NewEntry(he)); var t1 = BaseUtils.AppTicks.TickCountLapDelta("DFS"); if (t1.Item2 >= 80) { System.Diagnostics.Trace.WriteLine("NE Second Actions slow " + t1.Item1); } // all notes committed SystemNoteClass.CommitDirtyNotes((snc) => { if (EDCommander.Current.SyncToEdsm && snc.FSDEntry) { EDSMClass.SendComments(snc.SystemName, snc.Note, 0, he.Commander); } }); var lastent = history.GetLast; if (!object.ReferenceEquals(he, lastent)) { LogLineHighlight(string.Format("Current history entry is not last in history - possible re-entrancy.\nAlert the EDDiscovery developers using either discord or Github (see help) and attach log file {0}", BaseUtils.TraceLog.LogFileName)); Trace.WriteLine($"Current history entry is not last in history"); Trace.WriteLine($"Current entry: {he.journalEntry?.GetJsonString()}"); Trace.WriteLine($"Last entry: {lastent.journalEntry?.GetJsonString()}"); Trace.WriteLine($"Stack Trace:"); Trace.WriteLine(new StackTrace(true).ToString()); } if (he.IsFSDCarrierJump) { int count = history.GetVisitsCount(he.System.Name); LogLine(string.Format("Arrived at system {0} Visit No. {1}".T(EDTx.EDDiscoveryForm_Arrived), he.System.Name, count)); System.Diagnostics.Trace.WriteLine("Arrived at system: " + he.System.Name + " " + count + ":th visit."); } if (EDCommander.Current.SyncToEdsm && EDSMJournalSync.OkayToSend(he)) // send this one, if allowed. { EDSMJournalSync.SendEDSMEvents(LogLine, new List <HistoryEntry>() { he }); // send, if bad credentials, EDSM will moan alerting the user } if (EDCommander.Current.SyncToInara) { EliteDangerousCore.Inara.InaraSync.NewEvent(LogLine, he); } if (EDCommander.Current.SyncToIGAU) { EliteDangerousCore.IGAU.IGAUSync.NewEvent(LogLine, he); } if (EDDNClass.IsEDDNMessage(he.EntryType) && he.AgeOfEntry() < TimeSpan.FromDays(1.0) && EDCommander.Current.SyncToEddn == true) { EDDNSync.SendEDDNEvents(LogLine, he); } DLLManager.NewJournalEntry(EliteDangerousCore.DLL.EDDDLLCallerHE.CreateFromHistoryEntry(history, he), false); screenshotconverter.NewJournalEntry(he.journalEntry); // tell the screenshotter. CheckActionProfile(he); // finally, CAPI, if docked, try and get commodity data, and if so, create a new EDD record // placed here because it causes a new set of newentries to be called if (he.EntryType == JournalTypeEnum.Docked && FrontierCAPI.Active) { System.Threading.Tasks.Task.Run(() => // don't hold up the main thread, do it in a task, as its a HTTP operation { var dockevt = he.journalEntry as EliteDangerousCore.JournalEvents.JournalDocked; string marketjson = FrontierCAPI.Market(); CAPI.Market mk = new CAPI.Market(marketjson); if (mk.IsValid) { System.IO.File.WriteAllText(@"c:\code\market.json", marketjson); if (dockevt.StationName.Equals(mk.Name, StringComparison.InvariantCultureIgnoreCase)) { System.Diagnostics.Debug.WriteLine($"CAPI got market {mk.Name}"); var entry = new EliteDangerousCore.JournalEvents.JournalEDDCommodityPrices(he.EventTimeUTC.AddSeconds(1), mk.ID, mk.Name, he.System.Name, EDCommander.CurrentCmdrID, mk.Commodities); var jo = entry.ToJSON(); // get json of it, and add it to the db entry.Add(jo); BeginInvoke((System.Windows.Forms.MethodInvoker) delegate { Debug.Assert(System.Windows.Forms.Application.MessageLoop); System.Diagnostics.Debug.WriteLine("CAPI fire new entry"); NewEntry(entry); // then push it thru. this will cause another set of calls to NewEntry First/Second // EDDN handler will pick up EDDCommodityPrices and send it. }); } else { System.Diagnostics.Trace.WriteLine($"CAPI disagree on market {dockevt.StationName} vs {mk.Name}"); } } else { System.Diagnostics.Trace.WriteLine($"CAPI market invalid {marketjson}"); } }); } }