From 1d6a771c8a6bdea6aa9a6eab025edf3e7a99d384 Mon Sep 17 00:00:00 2001 From: Paul Woolcock <11843015+phw198@users.noreply.github.com> Date: Thu, 20 Aug 2020 00:52:53 +0100 Subject: [PATCH 1/5] rateLimitExceeded error message changed. #1053 --- .../GoogleOgcs/GoogleCalendar.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index 088239f7..252bb25f 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -1644,6 +1644,7 @@ public static Google.Apis.Calendar.v3.Data.EventAttendee CreateAttendee(Recipien public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event ev) { //https://developers.google.com/analytics/devguides/reporting/core/v3/coreErrors + log.Fail(ex.Message); if (Settings.Instance.AddAttendees && ex.Message.Contains("Calendar usage limits exceeded. [403]") && ev != null) { //"Google.Apis.Requests.RequestError\r\nCalendar usage limits exceeded. [403]\r\nErrors [\r\n\tMessage[Calendar usage limits exceeded.] Location[ - ] Reason[quotaExceeded] Domain[usageLimits]\r\n]\r\n" //This happens because too many attendees have been added in a short period of time. @@ -1659,11 +1660,10 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e ev.Attendees = new List(); return ApiException.justContinue; - } else if (ex.Message.Contains("Rate Limit Exceeded")) { + } else if (ex.Error.Errors.First().Reason == "rateLimitExceeded" && ex.Message.Contains("limit 'Queries per day'")) { return ApiException.backoffThenRetry; } else if (ex.Message.Contains("Daily Limit Exceeded")) { - log.Warn(ex.Message); log.Warn("Google's free Calendar quota has been exhausted! New quota comes into effect 08:00 GMT."); Forms.Main.Instance.SyncNote(Forms.Main.SyncNotes.QuotaExhaustedInfo, null); @@ -1680,19 +1680,17 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e return ApiException.freeAPIexhausted; } else if (ex.Message.Contains("Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. [403]")) { - log.Warn(ex.Message); Forms.Main.Instance.Console.Update("You are not properly authenticated to Google.
" + "On the Settings > Google tab, please disconnect and re-authenticate your account.", Console.Markup.error); ex.Data.Add("OGCS", "Unauthenticated access to Google account attempted. Authentication required."); return ApiException.throwException; } else if (ex.Error != null && ex.Error.Code == 401 && ex.Error.Message.Contains("Unauthorized")) { - log.Warn(ex.Message); log.Debug("This error seems to be a new transient issue, so treating it with exponential backoff..."); return ApiException.backoffThenRetry; } else { - log.Warn(ex.Message); + log.Warn("Unhandled API exception."); return ApiException.throwException; } } From 1671564957dfcb3926d8d6b2f0d17ee844b96448 Mon Sep 17 00:00:00 2001 From: Paul Woolcock <11843015+phw198@users.noreply.github.com> Date: Sun, 4 Oct 2020 20:05:49 +0100 Subject: [PATCH 2/5] Use HandleAPIlimits() when retrieving calendar settings. #1053 --- .../GoogleOgcs/GoogleCalendar.cs | 74 +++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index 252bb25f..9ac27df7 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -1292,9 +1292,33 @@ public Boolean CompareRecipientsToAttendees(AppointmentItem ai, Event ev, String /// public void GetSettings() { try { - //Get the timezone offset - convert from IANA string to UTC offset integer - Setting setting = Service.Settings.Get("timezone").Execute(); - this.UTCoffset = TimezoneDB.GetUtcOffset(setting.Value); + log.Fine("Get the timezone offset - convert from IANA string to UTC offset integer."); + SettingsResource.GetRequest gr = Service.Settings.Get("timezone"); + int backoff = 0; + while (backoff < backoffLimit) { + try { + Setting setting = gr.Execute(); + this.UTCoffset = TimezoneDB.GetUtcOffset(setting.Value); + } catch (Google.GoogleApiException ex) { + switch (HandleAPIlimits(ex, null)) { + case ApiException.throwException: throw; + case ApiException.freeAPIexhausted: + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref aex); + throw aex; + case ApiException.backoffThenRetry: + backoff++; + if (backoff == backoffLimit) { + log.Error("API limit backoff was not successful. Retrieve failed."); + throw; + } else { + log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); + System.Threading.Thread.Sleep(backoff * 1000); + } + break; + } + } + } } catch (System.Exception ex) { OGCSexception.Analyse("Not able to retrieve Google calendar's global timezone", ex); } @@ -1303,14 +1327,39 @@ public void GetSettings() { private void getCalendarSettings() { if (!Settings.Instance.AddReminders || !Settings.Instance.UseGoogleDefaultReminder) return; try { - CalendarListResource.GetRequest request = Service.CalendarList.Get(Settings.Instance.UseGoogleCalendar.Id); - CalendarListEntry cal = request.Execute(); - if (cal.DefaultReminders.Count == 0) - this.MinDefaultReminder = long.MinValue; - else - this.MinDefaultReminder = cal.DefaultReminders.Where(x => x.Method.Equals("popup")).OrderBy(x => x.Minutes.Value).First().Minutes.Value; + CalendarListResource.GetRequest gr = Service.CalendarList.Get(Settings.Instance.UseGoogleCalendar.Id); + int backoff = 0; + while (backoff < backoffLimit) { + try { + CalendarListEntry cal = gr.Execute(); + if (cal.DefaultReminders.Count == 0) + this.MinDefaultReminder = long.MinValue; + else + this.MinDefaultReminder = cal.DefaultReminders.Where(x => x.Method.Equals("popup")).OrderBy(x => x.Minutes.Value).First().Minutes.Value; + + } catch (Google.GoogleApiException ex) { + switch (HandleAPIlimits(ex, null)) { + case ApiException.throwException: throw; + case ApiException.freeAPIexhausted: + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref aex); + throw aex; + case ApiException.backoffThenRetry: + backoff++; + if (backoff == backoffLimit) { + log.Error("API limit backoff was not successful. Retrieve failed."); + throw; + } else { + log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); + System.Threading.Thread.Sleep(backoff * 1000); + } + break; + } + } + } } catch (System.Exception ex) { OGCSexception.Analyse("Failed to get calendar settings.", ex); + this.MinDefaultReminder = long.MinValue; } } @@ -1659,11 +1708,10 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e ev.Attendees = new List(); return ApiException.justContinue; + + } else if (ex.Message.Contains("Daily Limit Exceeded") || + (ex.Error.Errors.First().Reason == "rateLimitExceeded" && ex.Message.Contains("limit 'Queries per day'"))) { - } else if (ex.Error.Errors.First().Reason == "rateLimitExceeded" && ex.Message.Contains("limit 'Queries per day'")) { - return ApiException.backoffThenRetry; - - } else if (ex.Message.Contains("Daily Limit Exceeded")) { log.Warn("Google's free Calendar quota has been exhausted! New quota comes into effect 08:00 GMT."); Forms.Main.Instance.SyncNote(Forms.Main.SyncNotes.QuotaExhaustedInfo, null); From cc023bbc9cee2b3ff2e7aef72947f1dd8def5ffc Mon Sep 17 00:00:00 2001 From: Paul Woolcock <11843015+phw198@users.noreply.github.com> Date: Sun, 4 Oct 2020 20:47:55 +0100 Subject: [PATCH 3/5] Revert "Use HandleAPIlimits() when retrieving calendar settings." This reverts commit 1671564957dfcb3926d8d6b2f0d17ee844b96448. --- .../GoogleOgcs/GoogleCalendar.cs | 67 +++---------------- 1 file changed, 9 insertions(+), 58 deletions(-) diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index 9ac27df7..f71de74d 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -1293,32 +1293,8 @@ public Boolean CompareRecipientsToAttendees(AppointmentItem ai, Event ev, String public void GetSettings() { try { log.Fine("Get the timezone offset - convert from IANA string to UTC offset integer."); - SettingsResource.GetRequest gr = Service.Settings.Get("timezone"); - int backoff = 0; - while (backoff < backoffLimit) { - try { - Setting setting = gr.Execute(); - this.UTCoffset = TimezoneDB.GetUtcOffset(setting.Value); - } catch (Google.GoogleApiException ex) { - switch (HandleAPIlimits(ex, null)) { - case ApiException.throwException: throw; - case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); - OGCSexception.LogAsFail(ref aex); - throw aex; - case ApiException.backoffThenRetry: - backoff++; - if (backoff == backoffLimit) { - log.Error("API limit backoff was not successful. Retrieve failed."); - throw; - } else { - log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); - System.Threading.Thread.Sleep(backoff * 1000); - } - break; - } - } - } + Setting setting = Service.Settings.Get("timezone").Execute(); + this.UTCoffset = TimezoneDB.GetUtcOffset(setting.Value); } catch (System.Exception ex) { OGCSexception.Analyse("Not able to retrieve Google calendar's global timezone", ex); } @@ -1327,39 +1303,14 @@ public void GetSettings() { private void getCalendarSettings() { if (!Settings.Instance.AddReminders || !Settings.Instance.UseGoogleDefaultReminder) return; try { - CalendarListResource.GetRequest gr = Service.CalendarList.Get(Settings.Instance.UseGoogleCalendar.Id); - int backoff = 0; - while (backoff < backoffLimit) { - try { - CalendarListEntry cal = gr.Execute(); - if (cal.DefaultReminders.Count == 0) - this.MinDefaultReminder = long.MinValue; - else - this.MinDefaultReminder = cal.DefaultReminders.Where(x => x.Method.Equals("popup")).OrderBy(x => x.Minutes.Value).First().Minutes.Value; - - } catch (Google.GoogleApiException ex) { - switch (HandleAPIlimits(ex, null)) { - case ApiException.throwException: throw; - case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); - OGCSexception.LogAsFail(ref aex); - throw aex; - case ApiException.backoffThenRetry: - backoff++; - if (backoff == backoffLimit) { - log.Error("API limit backoff was not successful. Retrieve failed."); - throw; - } else { - log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); - System.Threading.Thread.Sleep(backoff * 1000); - } - break; - } - } - } + CalendarListResource.GetRequest request = Service.CalendarList.Get(Settings.Instance.UseGoogleCalendar.Id); + CalendarListEntry cal = request.Execute(); + if (cal.DefaultReminders.Count == 0) + this.MinDefaultReminder = long.MinValue; + else + this.MinDefaultReminder = cal.DefaultReminders.Where(x => x.Method.Equals("popup")).OrderBy(x => x.Minutes.Value).First().Minutes.Value; } catch (System.Exception ex) { OGCSexception.Analyse("Failed to get calendar settings.", ex); - this.MinDefaultReminder = long.MinValue; } } @@ -1708,7 +1659,7 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e ev.Attendees = new List(); return ApiException.justContinue; - + } else if (ex.Message.Contains("Daily Limit Exceeded") || (ex.Error.Errors.First().Reason == "rateLimitExceeded" && ex.Message.Contains("limit 'Queries per day'"))) { From b92a311a06707df37873bfa48473bbc42621e310 Mon Sep 17 00:00:00 2001 From: Paul Woolcock <11843015+phw198@users.noreply.github.com> Date: Fri, 26 Jun 2020 11:40:12 +0100 Subject: [PATCH 4/5] Update console when unable to get Google calendar timezone/reminder settings. Check for quota limits error. #1026 #1053 --- .../GoogleOgcs/GoogleCalendar.cs | 2 ++ src/OutlookGoogleCalendarSync/Sync/Engine.cs | 14 ++------------ src/OutlookGoogleCalendarSync/Telemetry.cs | 3 +-- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index f71de74d..c4794624 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -1297,6 +1297,7 @@ public void GetSettings() { this.UTCoffset = TimezoneDB.GetUtcOffset(setting.Value); } catch (System.Exception ex) { OGCSexception.Analyse("Not able to retrieve Google calendar's global timezone", ex); + throw new System.ApplicationException("Unable to retrieve Google calendar's global timezone.", ex); } getCalendarSettings(); } @@ -1311,6 +1312,7 @@ private void getCalendarSettings() { this.MinDefaultReminder = cal.DefaultReminders.Where(x => x.Method.Equals("popup")).OrderBy(x => x.Minutes.Value).First().Minutes.Value; } catch (System.Exception ex) { OGCSexception.Analyse("Failed to get calendar settings.", ex); + throw new System.ApplicationException("Unable to retrieve Google calendar's reminder settings.", ex); } } diff --git a/src/OutlookGoogleCalendarSync/Sync/Engine.cs b/src/OutlookGoogleCalendarSync/Sync/Engine.cs index 2d37a0bd..221211d6 100644 --- a/src/OutlookGoogleCalendarSync/Sync/Engine.cs +++ b/src/OutlookGoogleCalendarSync/Sync/Engine.cs @@ -190,18 +190,7 @@ public void Start(Boolean updateSyncSchedule = true) { SyncResult syncResult = SyncResult.Fail; int failedAttempts = 0; Telemetry.TrackSync(); - try { - GoogleOgcs.Calendar.Instance.GetSettings(); - } catch (System.AggregateException ae) { - OGCSexception.AnalyseAggregate(ae); - syncResult = SyncResult.AutoRetry; - } catch (System.ApplicationException ex) { - mainFrm.Console.Update(ex.Message, Console.Markup.warning); - syncResult = SyncResult.AutoRetry; - } catch (System.Exception ex) { - log.Warn(ex.Message); - syncResult = SyncResult.AutoRetry; - } + while ((syncResult == SyncResult.Fail || syncResult == SyncResult.ReconnectThenRetry) && !Forms.Main.Instance.IsDisposed) { if (failedAttempts > (syncResult == SyncResult.ReconnectThenRetry ? 1 : 0)) { if (OgcsMessageBox.Show("The synchronisation failed - check the Sync tab for further details.\r\nDo you want to try again?", "Sync Failed", @@ -388,6 +377,7 @@ private SyncResult synchronize() { #region Read Google items console.Update("Scanning Google calendar..."); try { + GoogleOgcs.Calendar.Instance.GetSettings(); googleEntries = GoogleOgcs.Calendar.Instance.GetCalendarEntriesInRange(); } catch (AggregateException agex) { OGCSexception.AnalyseAggregate(agex); diff --git a/src/OutlookGoogleCalendarSync/Telemetry.cs b/src/OutlookGoogleCalendarSync/Telemetry.cs index 2329acc3..c1c5b6bf 100644 --- a/src/OutlookGoogleCalendarSync/Telemetry.cs +++ b/src/OutlookGoogleCalendarSync/Telemetry.cs @@ -76,7 +76,6 @@ public enum Action { uninstall, //squirrel upgrade, //squirrel version //outlook,ogcs - } - + } } } From 1dc494ed1af135dce66f35621f414a5acf88838a Mon Sep 17 00:00:00 2001 From: Paul Woolcock <11843015+phw198@users.noreply.github.com> Date: Sat, 10 Oct 2020 17:49:16 +0100 Subject: [PATCH 5/5] HandleAPIlimits() when authenticating. Allow x-thread retrieval of Console text. #1053 --- .../Console/Console.cs | 15 +++++- .../Extensions/Exception.cs | 12 ++++- .../GoogleOgcs/Authenticator.cs | 53 ++++++++++++++----- .../GoogleOgcs/GoogleCalendar.cs | 46 ++++++++++++---- src/OutlookGoogleCalendarSync/Sync/Engine.cs | 7 +-- 5 files changed, 105 insertions(+), 28 deletions(-) diff --git a/src/OutlookGoogleCalendarSync/Console/Console.cs b/src/OutlookGoogleCalendarSync/Console/Console.cs index 10409d54..e9be9725 100644 --- a/src/OutlookGoogleCalendarSync/Console/Console.cs +++ b/src/OutlookGoogleCalendarSync/Console/Console.cs @@ -15,7 +15,18 @@ public class Console { private String content = ""; public String DocumentText { get { - return (this.wb == null ? null : this.wb.DocumentText); + String documentText = ""; + if (this.wb == null) + return null; + else { + if (this.wb.InvokeRequired) { + this.wb.Invoke((MethodInvoker)(() => { + documentText = wb.DocumentText; + })); + } else + documentText = this.wb.DocumentText; + } + return documentText; } } @@ -271,7 +282,7 @@ public void Update(String moreOutput, Markup? markupPrefix = null, bool newLine } //Don't add append line break to Markup that's already wrapped in
tags - if (markupPrefix != null && (new Markup[] { Markup.info, Markup.warning, Markup.error }.ToList()).Contains((Markup)markupPrefix)) + if (markupPrefix != null && (new Markup[] { Markup.info, Markup.warning, Markup.fail, Markup.error }.ToList()).Contains((Markup)markupPrefix)) newLine = false; contentInnerHtml += htmlOutput + (newLine ? "
" : ""); diff --git a/src/OutlookGoogleCalendarSync/Extensions/Exception.cs b/src/OutlookGoogleCalendarSync/Extensions/Exception.cs index 3c0b3299..38a0f41f 100644 --- a/src/OutlookGoogleCalendarSync/Extensions/Exception.cs +++ b/src/OutlookGoogleCalendarSync/Extensions/Exception.cs @@ -129,7 +129,17 @@ public static System.Exception LogAsFail(System.Exception ex) { LogAsFail(ref ex); return ex; } - + + /// + /// Capture this exception as log4net FAIL (not ERROR) when logged + /// + public static void LogAsFail(ref Google.GoogleApiException ex) { + if (ex.Data.Contains(LogAs)) + ex.Data[LogAs] = OGCSexception.LogLevel.FAIL; + else + ex.Data.Add(LogAs, OGCSexception.LogLevel.FAIL); + } + /// /// Capture this exception as log4net FAIL (not ERROR) when logged /// diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/Authenticator.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/Authenticator.cs index 31c13b77..2985dfc7 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/Authenticator.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/Authenticator.cs @@ -90,7 +90,7 @@ private static ClientSecrets getCalendarClientSecrets() { return provider; } - private async Task getAuthenticated(ClientSecrets cs) { + private async Task getAuthenticated(ClientSecrets cs) { log.Debug("Authenticating with Google calendar service..."); FileDataStore tokenStore = new FileDataStore(Program.UserFilePath); @@ -141,17 +141,43 @@ private async Task getAuthenticated(ClientSecrets cs) { log.Debug("Access token needs refreshing."); //This will happen automatically when using the calendar service //But we need a valid token before we call getGaccountEmail() which doesn't use the service - try { - GoogleOgcs.Calendar.Instance.Service.Settings.Get("useKeyboardShortcuts").Execute(); - } catch (System.Exception ex) { - if (ex is Google.Apis.Auth.OAuth2.Responses.TokenResponseException) - OGCSexception.AnalyseTokenResponse(ex as Google.Apis.Auth.OAuth2.Responses.TokenResponseException, false); - else { - OGCSexception.Analyse(ex); - Forms.Main.Instance.Console.Update("Unable to communicate with Google services. " + (ex.InnerException != null ? ex.InnerException.Message : ex.Message), Console.Markup.warning); + int backoff = 0; + while (backoff < Calendar.backoffLimit) { + try { + GoogleOgcs.Calendar.Instance.Service.Settings.Get("useKeyboardShortcuts").Execute(); + } catch (Google.GoogleApiException ex) { + switch (Calendar.HandleAPIlimits(ex, null)) { + case Calendar.ApiException.throwException: throw; + case Calendar.ApiException.freeAPIexhausted: + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(Calendar.Instance.SubscriptionInvite); + OGCSexception.LogAsFail(ref aex); + authenticated = false; + return authenticated; + case Calendar.ApiException.backoffThenRetry: + backoff++; + if (backoff == Calendar.backoffLimit) { + log.Fail("API limit backoff was not successful. Retrieving useKeyboardShortcuts setting failed."); + authenticated = false; + return authenticated; + } else { + log.Warn("API rate limit reached. Backing off " + backoff + "sec before retry."); + System.Threading.Thread.Sleep(backoff * 1000); + } + break; + } + + } catch (System.Exception ex) { + if (ex is Google.Apis.Auth.OAuth2.Responses.TokenResponseException) + OGCSexception.AnalyseTokenResponse(ex as Google.Apis.Auth.OAuth2.Responses.TokenResponseException, false); + else { + OGCSexception.Analyse(ex); + Forms.Main.Instance.Console.Update("Unable to communicate with Google services. " + (ex.InnerException != null ? ex.InnerException.Message : ex.Message), Console.Markup.warning); + } + authenticated = false; + return authenticated; } - authenticated = false; - return; } log.Debug("Access token refreshed."); } @@ -159,6 +185,7 @@ private async Task getAuthenticated(ClientSecrets cs) { getGaccountEmail(credential.Token.AccessToken); authenticated = true; Forms.Main.Instance.Console.Update("Handshake successful.", verbose: true); + return authenticated; } public void Reset(Boolean reauthorise = true) { @@ -312,7 +339,9 @@ public Boolean UserSubscriptionCheck() { switch (GoogleOgcs.Calendar.HandleAPIlimits(ex, null)) { case Calendar.ApiException.throwException: throw; case Calendar.ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(GoogleOgcs.Calendar.Instance.SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(GoogleOgcs.Calendar.Instance.SubscriptionInvite); OGCSexception.LogAsFail(ref aex); GoogleOgcs.Calendar.Instance.Service = null; throw aex; diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index c4794624..6205f416 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -69,7 +69,7 @@ public CalendarService Service { set { service = value; } } public static Boolean APIlimitReached_attendee = false; - private const int backoffLimit = 5; + public const int backoffLimit = 5; public enum ApiException { justContinue, backoffThenRetry, @@ -105,7 +105,9 @@ public List GetCalendars() { switch (HandleAPIlimits(ex, null)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -156,7 +158,9 @@ public List GetCalendarEntriesInRecurrence(String recurringEventId) { switch (HandleAPIlimits(ex, null)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -207,7 +211,9 @@ public Event GetCalendarEntry(String eventId) { switch (HandleAPIlimits(ex, null)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -229,8 +235,8 @@ public Event GetCalendarEntry(String eventId) { else throw new System.Exception("Returned null"); } catch (System.Exception ex) { + if (ex is ApplicationException) throw; Forms.Main.Instance.Console.Update("Failed to retrieve Google event", Console.Markup.error); - log.Error(ex.Message); return null; } } @@ -265,7 +271,9 @@ public List GetCalendarEntriesInRange(DateTime from, DateTime to) { switch (HandleAPIlimits(ex, null)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -445,7 +453,9 @@ private Event createCalendarEntry_save(Event ev, AppointmentItem ai) { switch (HandleAPIlimits(ex, ev)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.justContinue: break; @@ -814,7 +824,9 @@ public void UpdateCalendarEntry_save(ref Event ev) { switch (HandleAPIlimits(ex, ev)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -906,7 +918,9 @@ private void deleteCalendarEntry_save(Event ev) { switch (HandleAPIlimits(ex, ev)) { case ApiException.throwException: throw; case ApiException.freeAPIexhausted: - System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite, ex); + OGCSexception.LogAsFail(ref ex); + OGCSexception.Analyse(ex); + System.ApplicationException aex = new System.ApplicationException(SubscriptionInvite); OGCSexception.LogAsFail(ref aex); throw aex; case ApiException.backoffThenRetry: @@ -1663,7 +1677,7 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e return ApiException.justContinue; } else if (ex.Message.Contains("Daily Limit Exceeded") || - (ex.Error.Errors.First().Reason == "rateLimitExceeded" && ex.Message.Contains("limit 'Queries per day'"))) { + (ex.Message.Contains("limit 'Queries per day'") && ex.Error != null && ex.Error.Errors != null && ex.Error.Errors.First().Reason == "rateLimitExceeded")) { log.Warn("Google's free Calendar quota has been exhausted! New quota comes into effect 08:00 GMT."); Forms.Main.Instance.SyncNote(Forms.Main.SyncNotes.QuotaExhaustedInfo, null); @@ -1696,5 +1710,17 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e } } #endregion + + /// + /// This is solely for purposefully causing an error to assist when developing + /// + private void throwApiException() { + Google.GoogleApiException ex = new Google.GoogleApiException("Service", "limit 'Queries per day'"); + Google.Apis.Requests.SingleError err = new Google.Apis.Requests.SingleError(); + err.Reason = "rateLimitExceeded"; + ex.Error = new Google.Apis.Requests.RequestError { Errors = new List() }; + ex.Error.Errors.Add(err); + throw ex; + } } } diff --git a/src/OutlookGoogleCalendarSync/Sync/Engine.cs b/src/OutlookGoogleCalendarSync/Sync/Engine.cs index 221211d6..481770b9 100644 --- a/src/OutlookGoogleCalendarSync/Sync/Engine.cs +++ b/src/OutlookGoogleCalendarSync/Sync/Engine.cs @@ -288,7 +288,8 @@ public void Start(Boolean updateSyncSchedule = true) { } } else { consecutiveSyncFails += failedAttempts; - mainFrm.Console.Update("Sync aborted after " + failedAttempts + " failed attempts!", syncResult == SyncResult.UserCancelled ? Console.Markup.fail : Console.Markup.error); + mainFrm.Console.Update("Sync aborted after " + failedAttempts + " failed attempts!", + new SyncResult[] { SyncResult.UserCancelled, SyncResult.Abandon }.Contains(syncResult) ? Console.Markup.fail : Console.Markup.error); } setNextSync(syncStarted, syncResult == SyncResult.OK, updateSyncSchedule, cacheNextSync); @@ -499,8 +500,8 @@ private SyncResult synchronize() { } } } - } catch (System.Exception) { - console.Update("Failed to retrieve master for Google recurring event outside of sync range.", Console.Markup.error); + } catch (System.Exception ex) { + console.Update("Failed to retrieve master for Google recurring event outside of sync range.", OGCSexception.LoggingAsFail(ex) ? Console.Markup.fail : Console.Markup.error); throw; } finally { oPattern = (RecurrencePattern)OutlookOgcs.Calendar.ReleaseObject(oPattern);