private void FetcherThreadProc() { Trace.WriteLine($"EDSM Thread logs start"); DateTime lastCommentFetch = DateTime.MinValue; int waittime = 1000; // initial waittime, will be reestimated later DateTime curtime = DateTime.UtcNow; KeyName(out string latestdatekeyname, out string oldestdatekeyname); while (!ExitRequested.WaitOne(waittime)) { if (ExitRequested.WaitOne(0)) { return; } EDSMClass edsm = new EDSMClass(Commander); // logic checked 21/12/2018 RJP if (edsm.ValidCredentials && Commander.SyncFromEdsm) { if (DateTime.UtcNow > lastCommentFetch.AddHours(1)) { edsm.GetComments(l => Trace.WriteLine(l)); lastCommentFetch = DateTime.UtcNow; } DateTime latestentry = EliteDangerousCore.DB.UserDatabase.Instance.GetSettingDate(latestdatekeyname, GammaStart); // lastest entry DateTime oldestentry = EliteDangerousCore.DB.UserDatabase.Instance.GetSettingDate(oldestdatekeyname, DateTime.UtcNow); // oldest entry DateTime logstarttime = DateTime.MinValue; // return what we got.. DateTime logendtime = DateTime.MinValue; List <JournalFSDJump> edsmlogs = null; BaseUtils.ResponseData response = default(BaseUtils.ResponseData); int res = -1; if (DateTime.UtcNow.Subtract(latestentry).TotalMinutes >= EDSMMaxLogAgeMinutes) // is latest entry old? { DateTime askfor = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Fetch latest since Curtime > lastestentry + gap " + askfor.ToStringZulu()); res = edsm.GetLogs(null, askfor, out edsmlogs, out logstarttime, out logendtime, out response); //res = 100; logstarttime = askfor.AddDays(-7); logendtime = askfor; // debug it } else if (oldestentry > GammaStart) // if oldest entry younger than gamma? { System.Diagnostics.Debug.WriteLine("Go back in time to gamma "); res = edsm.GetLogs(null, oldestentry, out edsmlogs, out logstarttime, out logendtime, out response); //res = 100; logstarttime = oldestentry.AddDays(-7); logendtime = oldestentry; // debug it } if (res == 100) // hunky dory - note if Anthor faults, we just retry again and again { System.Diagnostics.Debug.WriteLine("Data stored from " + oldestentry.ToStringZulu() + " -> " + latestentry.ToStringZulu()); System.Diagnostics.Debug.WriteLine("Process logs from " + logstarttime.ToStringZulu() + " => " + logendtime.ToStringZulu()); if (edsmlogs != null && edsmlogs.Count > 0) // if anything to process.. { Process(edsmlogs, logstarttime, logendtime); } if (logendtime > latestentry) { EliteDangerousCore.DB.UserDatabase.Instance.PutSettingDate(latestdatekeyname, logendtime); } if (logstarttime < oldestentry) { EliteDangerousCore.DB.UserDatabase.Instance.PutSettingDate(oldestdatekeyname, logstarttime); } } else if (res != -1) { System.Diagnostics.Debug.WriteLine("EDSM Log request rejected with " + res); } if (response.Headers != null && response.Headers["X-Rate-Limit-Limit"] != null && response.Headers["X-Rate-Limit-Remaining"] != null && response.Headers["X-Rate-Limit-Reset"] != null && Int32.TryParse(response.Headers["X-Rate-Limit-Limit"], out int ratelimitlimit) && Int32.TryParse(response.Headers["X-Rate-Limit-Remaining"], out int ratelimitremain) && Int32.TryParse(response.Headers["X-Rate-Limit-Reset"], out int ratelimitreset)) { if (ratelimitremain < ratelimitlimit * 2 / 4) // lets keep at least X remaining for other purposes later.. { waittime = 1000 * ratelimitreset / (ratelimitlimit - ratelimitremain); // slow down to its pace now.. example 878/(360-272) = 10 seconds per quota } else { waittime = 1000; // 1 second so we don't thrash } System.Diagnostics.Debug.WriteLine("EDSM Log Delay Parameters {0} {1} {2} => {3}ms", ratelimitlimit, ratelimitremain, ratelimitreset, waittime); } } } }
private void FetcherThreadProc() { Trace.WriteLine($"EDSM Thread logs start"); bool jupdate = false; DateTime lastCommentFetch = DateTime.MinValue; int waittime = 2000; // Max 1 request every 2 seconds, with a backoff if the rate limit is hit if (EDSMRequestBackoffTime > DateTime.UtcNow) { waittime = (int)Math.Min(EDSMMaxLogAgeMinutes * 60000, Math.Min(BackoffInterval.TotalSeconds * 1000, EDSMRequestBackoffTime.Subtract(DateTime.UtcNow).TotalSeconds * 1000)); } while (!ExitRequested.WaitOne(waittime)) { EDSMClass edsm = new EDSMClass(Commander); List <HistoryEntry> edsmlogs = null; DateTime logstarttime = DateTime.MinValue; DateTime logendtime = DateTime.MinValue; int res = -1; if (edsm.ValidCredentials && DateTime.UtcNow > lastCommentFetch.AddHours(1)) { edsm.GetComments(l => Trace.WriteLine(l)); lastCommentFetch = DateTime.UtcNow; } if (edsm.ValidCredentials && Commander.SyncFromEdsm && DateTime.UtcNow > EDSMRequestBackoffTime) { if (DateTime.UtcNow.Subtract(LastEventTime).TotalMinutes >= EDSMMaxLogAgeMinutes) { //Trace.WriteLine($"Retrieving EDSM logs starting {LastEventTime}"); res = edsm.GetLogs(LastEventTime, null, out edsmlogs, out logstarttime, out logendtime); } else if (FirstEventTime > GammaStart) { //Trace.WriteLine($"Retrieving EDSM logs ending {FirstEventTime}"); res = edsm.GetLogs(null, FirstEventTime, out edsmlogs, out logstarttime, out logendtime); } } if (ExitRequested.WaitOne(0)) { return; } if (res == 429) // Rate Limit Exceeded { Trace.WriteLine($"EDSM Log request rate limit hit - backing off for {BackoffInterval.TotalSeconds}s"); EDSMRequestBackoffTime = DateTime.UtcNow + BackoffInterval; BackoffInterval = BackoffInterval + TimeSpan.FromSeconds(60); } else if (logstarttime > LastEventTime && logendtime < FirstEventTime) { Trace.WriteLine($"Bad start and/or end times returned by EDSM - backing off for {BackoffInterval.TotalSeconds}s"); EDSMRequestBackoffTime = DateTime.UtcNow + BackoffInterval; BackoffInterval = BackoffInterval + TimeSpan.FromSeconds(60); } else if (res == 100 && edsmlogs != null) { if (edsmlogs.Count > 0) // if anything to process.. { //Trace.WriteLine($"Retrieving EDSM logs count {edsmlogs.Count}"); BackoffInterval = TimeSpan.FromSeconds(60); if (logendtime > DateTime.UtcNow) { logendtime = DateTime.UtcNow; } if (logstarttime < DateTime.MinValue.AddDays(1)) { logstarttime = DateTime.MinValue.AddDays(1); } // Get all of the local entries now that we have the entries from EDSM // Moved here to avoid the race that could have been causing duplicate entries List <HistoryEntry> hlfsdlist = JournalEntry.GetAll(Commander.Nr, logstarttime.AddDays(-1), logendtime.AddDays(1)).OfType <JournalLocOrJump>().OrderBy(je => je.EventTimeUTC).Select(je => HistoryEntry.FromJournalEntry(je, null, out jupdate)).ToList(); HistoryList hl = new HistoryList(hlfsdlist); List <DateTime> hlfsdtimes = hlfsdlist.Select(he => he.EventTimeUTC).ToList(); List <HistoryEntry> toadd = new List <HistoryEntry>(); int previdx = -1; foreach (HistoryEntry he in edsmlogs) // find out list of ones not present { int index = hlfsdlist.FindIndex(x => x.System.Name.Equals(he.System.Name, StringComparison.InvariantCultureIgnoreCase) && x.EventTimeUTC.Ticks == he.EventTimeUTC.Ticks); if (index < 0) { // Look for any entries where DST may have thrown off the time foreach (var vi in hlfsdlist.Select((v, i) => new { v = v, i = i }).Where(vi => vi.v.System.Name.Equals(he.System.Name, StringComparison.InvariantCultureIgnoreCase))) { if (vi.i > previdx) { double hdiff = vi.v.EventTimeUTC.Subtract(he.EventTimeUTC).TotalHours; if (hdiff >= -2 && hdiff <= 2 && hdiff == Math.Floor(hdiff)) { if (vi.v.System.EDSMID <= 0) { vi.v.System.EDSMID = 0; hl.FillEDSM(vi.v); } if (vi.v.System.EDSMID <= 0 || vi.v.System.EDSMID == he.System.EDSMID) { index = vi.i; break; } } } } } if (index < 0) { toadd.Add(he); } else { HistoryEntry lhe = hlfsdlist[index]; if (he.IsEDSMFirstDiscover && !lhe.IsEDSMFirstDiscover) { lhe.SetFirstDiscover(); } previdx = index; } } if (toadd.Count > 0) // if we have any, we can add { Trace.WriteLine($"Adding EDSM logs count {toadd.Count}"); TravelLogUnit tlu = new TravelLogUnit(); // need a tlu for it tlu.type = 2; // EDSM tlu.Name = "EDSM-" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); tlu.Size = 0; tlu.Path = "EDSM"; tlu.CommanderId = EDCommander.CurrentCmdrID; tlu.Add(); // Add to Database using (SQLiteConnectionUser cn = new SQLiteConnectionUser(utc: true)) { foreach (HistoryEntry he in toadd) { JObject jo = JournalEntry.CreateFSDJournalEntryJson(he.EventTimeUTC, he.System.Name, he.System.X, he.System.Y, he.System.Z, EliteConfigInstance.InstanceConfig.DefaultMapColour); JournalEntry je = JournalEntry.CreateFSDJournalEntry(tlu.id, tlu.CommanderId.Value, (int)SyncFlags.EDSM, jo, he.System.EDSMID); System.Diagnostics.Trace.WriteLine(string.Format("Add {0} {1}", je.EventTimeUTC, he.System.Name)); je.Add(jo, cn); } } LogLine($"Retrieved {toadd.Count} log entries from EDSM, from {logstarttime.ToLocalTime().ToString()} to {logendtime.ToLocalTime().ToString()}"); if (logendtime > LastEventTime || logstarttime <= GammaStart) { if (OnDownloadedSystems != null) { OnDownloadedSystems(); } } } } if (logstarttime < FirstEventTime) { FirstEventTime = logstarttime; } if (logendtime > LastEventTime) { LastEventTime = logendtime; } } } }
private void FetcherThreadProc() { Trace.WriteLine($"EDSM Thread logs start"); bool jupdate = false; DateTime lastCommentFetch = DateTime.MinValue; int waittime = 2000; // Max 1 request every 2 seconds, with a backoff if the rate limit is hit if (EDSMRequestBackoffTime > DateTime.UtcNow) { waittime = (int)Math.Min(EDSMMaxLogAgeMinutes * 60000, Math.Min(BackoffInterval.TotalSeconds * 1000, EDSMRequestBackoffTime.Subtract(DateTime.UtcNow).TotalSeconds * 1000)); } while (!ExitRequested.WaitOne(waittime)) { EDSMClass edsm = new EDSMClass(Commander); if (edsm.ValidCredentials && DateTime.UtcNow > lastCommentFetch.AddHours(1)) { edsm.GetComments(l => Trace.WriteLine(l)); lastCommentFetch = DateTime.UtcNow; } DateTime logstarttime = DateTime.MinValue; // return what we got.. DateTime logendtime = DateTime.MinValue; List <JournalFSDJump> edsmlogs = null; int res = -1; //return code if (edsm.ValidCredentials && Commander.SyncFromEdsm && DateTime.UtcNow > EDSMRequestBackoffTime) { if (DateTime.UtcNow.Subtract(LastEventTime).TotalMinutes >= EDSMMaxLogAgeMinutes) { System.Diagnostics.Debug.WriteLine($"Retrieving EDSM logs starting {LastEventTime}"); res = edsm.GetLogs(LastEventTime, null, out edsmlogs, out logstarttime, out logendtime); } else if (FirstEventTime > GammaStart) { System.Diagnostics.Debug.WriteLine($"Retrieving EDSM logs ending {FirstEventTime}"); res = edsm.GetLogs(null, FirstEventTime, out edsmlogs, out logstarttime, out logendtime); } } if (ExitRequested.WaitOne(0)) { return; } if (res == 429) // Rate Limit Exceeded { Trace.WriteLine($"EDSM Log request rate limit hit - backing off for {BackoffInterval.TotalSeconds}s"); EDSMRequestBackoffTime = DateTime.UtcNow + BackoffInterval; BackoffInterval = BackoffInterval + TimeSpan.FromSeconds(60); } else if (logstarttime > LastEventTime && logendtime < FirstEventTime) { Trace.WriteLine($"Bad start and/or end times returned by EDSM - backing off for {BackoffInterval.TotalSeconds}s"); EDSMRequestBackoffTime = DateTime.UtcNow + BackoffInterval; BackoffInterval = BackoffInterval + TimeSpan.FromSeconds(60); } else if (res == 100 && edsmlogs != null) { if (edsmlogs.Count > 0) // if anything to process.. { //Trace.WriteLine($"Retrieving EDSM logs count {edsmlogs.Count}"); BackoffInterval = TimeSpan.FromSeconds(60); if (logendtime > DateTime.UtcNow) { logendtime = DateTime.UtcNow; } if (logstarttime < DateTime.MinValue.AddDays(1)) { logstarttime = DateTime.MinValue.AddDays(1); } // Get all of the local entries now that we have the entries from EDSM // Moved here to avoid the race that could have been causing duplicate entries // EDSM only returns FSD entries, so only look for them. Tested 27/4/2018 after the HE optimisations List <HistoryEntry> hlfsdlist = JournalEntry.GetAll(Commander.Nr, logstarttime.AddDays(-1), logendtime.AddDays(1)). OfType <JournalLocOrJump>().OrderBy(je => je.EventTimeUTC). Select(je => HistoryEntry.FromJournalEntry(je, null, out jupdate)).ToList(); // using HE just because of the FillEDSM func HistoryList hl = new HistoryList(hlfsdlist); // just so we can access the FillEDSM func List <JournalFSDJump> toadd = new List <JournalFSDJump>(); int previdx = -1; foreach (JournalFSDJump jfsd in edsmlogs) // find out list of ones not present { int index = hlfsdlist.FindIndex(x => x.System.Name.Equals(jfsd.StarSystem, StringComparison.InvariantCultureIgnoreCase) && x.EventTimeUTC.Ticks == jfsd.EventTimeUTC.Ticks); if (index < 0) { // Look for any entries where DST may have thrown off the time foreach (var vi in hlfsdlist.Select((v, i) => new { v = v, i = i }).Where(vi => vi.v.System.Name.Equals(jfsd.StarSystem, StringComparison.InvariantCultureIgnoreCase))) { if (vi.i > previdx) { double hdiff = vi.v.EventTimeUTC.Subtract(jfsd.EventTimeUTC).TotalHours; if (hdiff >= -2 && hdiff <= 2 && hdiff == Math.Floor(hdiff)) { if (vi.v.System.EDSMID <= 0) // if we don't have a valid EDMSID.. { vi.v.System.EDSMID = 0; hl.FillEDSM(vi.v); } if (vi.v.System.EDSMID <= 0 || vi.v.System.EDSMID == jfsd.EdsmID) { index = vi.i; break; } } } } } if (index < 0) // its not a duplicate, add to db { toadd.Add(jfsd); } else { // it is a duplicate, check if the first discovery flag is set right JournalFSDJump existingfsd = hlfsdlist[index].journalEntry as JournalFSDJump; if (existingfsd != null && existingfsd.EDSMFirstDiscover != jfsd.EDSMFirstDiscover) // if we have a FSD one, and first discover is different { existingfsd.UpdateFirstDiscover(jfsd.EDSMFirstDiscover); } previdx = index; } } if (toadd.Count > 0) // if we have any, we can add { Trace.WriteLine($"Adding EDSM logs count {toadd.Count}"); TravelLogUnit tlu = new TravelLogUnit(); // need a tlu for it tlu.type = 2; // EDSM tlu.Name = "EDSM-" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); tlu.Size = 0; tlu.Path = "EDSM"; tlu.CommanderId = EDCommander.CurrentCmdrID; tlu.Add(); // Add to Database using (SQLiteConnectionUser cn = new SQLiteConnectionUser(utc: true)) { foreach (JournalFSDJump jfsd in toadd) { System.Diagnostics.Trace.WriteLine(string.Format("Add {0} {1}", jfsd.EventTimeUTC, jfsd.StarSystem)); jfsd.SetTLUCommander(tlu.id, jfsd.CommanderId); // update its TLU id to the TLU made above jfsd.Add(jfsd.CreateFSDJournalEntryJson(), cn); } } LogLine($"Retrieved {toadd.Count} log entries from EDSM, from {logstarttime.ToLocalTime().ToString()} to {logendtime.ToLocalTime().ToString()}"); if (logendtime > LastEventTime || logstarttime <= GammaStart) { if (OnDownloadedSystems != null) { OnDownloadedSystems(); } } } } if (logstarttime < FirstEventTime) { FirstEventTime = logstarttime; } if (logendtime > LastEventTime) { LastEventTime = logendtime; } } } }
private void Sync(EDSMClass edsm, HistoryList hl) { try { logout("EDSM sync begin"); List <HistoryEntry> hlfsdunsyncedlist = hl.FilterByNotEDSMSyncedAndFSD; // first entry is oldest if (_syncTo && hlfsdunsyncedlist.Count > 0) // send systems to edsm (verified with dates, 29/9/2016, utc throughout) { DateTime logstarttime = DateTime.MinValue; DateTime logendtime = DateTime.MinValue; logout("EDSM: Sending " + hlfsdunsyncedlist.Count.ToString() + " flightlog entries"); List <HistoryEntry> edsmsystemlog = null; int edsmsystemssent = 0; foreach (var he in hlfsdunsyncedlist) { if (Exit) { running = false; return; } if (edsmsystemlog == null || he.EventTimeUTC >= logendtime.AddDays(-1)) { edsm.GetLogs(he.EventTimeUTC.AddDays(-1), null, out edsmsystemlog, out logstarttime, out logendtime); // always returns a log, time is in UTC as per HistoryEntry and JournalEntry } if (logendtime < logstarttime) { running = false; return; } if (edsmsystemlog == null) { running = false; return; } HistoryEntry ps2 = (from c in edsmsystemlog where c.System.name == he.System.name && c.EventTimeUTC.Ticks == he.EventTimeUTC.Ticks select c).FirstOrDefault(); if (ps2 != null) // it did, just make sure EDSM sync flag is set.. { he.SetEdsmSync(); } else { string errmsg; // (verified with EDSM 29/9/2016) bool firstdiscover; int edsmid; if (edsm.SendTravelLog(he.System.name, he.EventTimeUTC, he.System.HasCoordinate && !he.IsStarPosFromEDSM, he.System.x, he.System.y, he.System.z, out errmsg, out firstdiscover, out edsmid)) { if (edsmid != 0 && he.System.id_edsm <= 0) { he.System.id_edsm = edsmid; JournalEntry.UpdateEDSMIDPosJump(he.Journalid, he.System, false, -1); } if (firstdiscover) { he.SetFirstDiscover(); } he.SetEdsmSync(); edsmsystemssent++; } if (errmsg.Length > 0) { logout(errmsg); break; } } } logout(string.Format("EDSM Systems sent {0}", edsmsystemssent)); } // TBD Comments to edsm? if (_syncFrom) // Verified ok with time 29/9/2016 { var json = edsm.GetComments(new DateTime(2011, 1, 1)); if (json != null) { JObject msg = JObject.Parse(json); int msgnr = msg["msgnum"].Value <int>(); JArray comments = (JArray)msg["comments"]; if (comments != null) { int commentsadded = 0; foreach (JObject jo in comments) { string name = jo["system"].Value <string>(); string note = jo["comment"].Value <string>(); string utctime = jo["lastUpdate"].Value <string>(); int edsmid = 0; if (!Int32.TryParse(jo["systemId"].Str("0"), out edsmid)) { edsmid = 0; } DateTime localtime = DateTime.ParseExact(utctime, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(); SystemNoteClass curnote = SystemNoteClass.GetNoteOnSystem(name, edsmid); if (curnote != null) // curnote uses local time to store { if (localtime.Ticks > curnote.Time.Ticks) // if newer, add on (verified with EDSM 29/9/2016) { curnote.UpdateNote(curnote.Note + ". EDSM: " + note, true, localtime, edsmid, true); commentsadded++; } } else { SystemNoteClass.MakeSystemNote(note, localtime, name, 0, edsmid, true); // new one! its an FSD one as well commentsadded++; } } logout(string.Format("EDSM Comments downloaded/updated {0}", commentsadded)); } } } logout("EDSM sync Done"); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine("Exception ex:" + ex.Message); logout("EDSM sync Exception " + ex.Message); } }