Skip to content

Commit

Permalink
HandleAPIlimits() when authenticating.
Browse files Browse the repository at this point in the history
Allow x-thread retrieval of Console text.
#1053
  • Loading branch information
phw198 committed Oct 10, 2020
1 parent b92a311 commit 1dc494e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 28 deletions.
15 changes: 13 additions & 2 deletions src/OutlookGoogleCalendarSync/Console/Console.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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 <div> 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 ? "<br/>" : "");

Expand Down
12 changes: 11 additions & 1 deletion src/OutlookGoogleCalendarSync/Extensions/Exception.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,17 @@ public static System.Exception LogAsFail(System.Exception ex) {
LogAsFail(ref ex);
return ex;
}


/// <summary>
/// Capture this exception as log4net FAIL (not ERROR) when logged
/// </summary>
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);
}

/// <summary>
/// Capture this exception as log4net FAIL (not ERROR) when logged
/// </summary>
Expand Down
53 changes: 41 additions & 12 deletions src/OutlookGoogleCalendarSync/GoogleOgcs/Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private static ClientSecrets getCalendarClientSecrets() {
return provider;
}

private async Task getAuthenticated(ClientSecrets cs) {
private async Task<bool> getAuthenticated(ClientSecrets cs) {
log.Debug("Authenticating with Google calendar service...");

FileDataStore tokenStore = new FileDataStore(Program.UserFilePath);
Expand Down Expand Up @@ -141,24 +141,51 @@ 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.");
}

getGaccountEmail(credential.Token.AccessToken);
authenticated = true;
Forms.Main.Instance.Console.Update("Handshake successful.", verbose: true);
return authenticated;
}

public void Reset(Boolean reauthorise = true) {
Expand Down Expand Up @@ -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;
Expand Down
46 changes: 36 additions & 10 deletions src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -105,7 +105,9 @@ public List<GoogleCalendarListEntry> 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:
Expand Down Expand Up @@ -156,7 +158,9 @@ public List<Event> 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:
Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -265,7 +271,9 @@ public List<Event> 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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1696,5 +1710,17 @@ public static ApiException HandleAPIlimits(Google.GoogleApiException ex, Event e
}
}
#endregion

/// <summary>
/// This is solely for purposefully causing an error to assist when developing
/// </summary>
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<Google.Apis.Requests.SingleError>() };
ex.Error.Errors.Add(err);
throw ex;
}
}
}
7 changes: 4 additions & 3 deletions src/OutlookGoogleCalendarSync/Sync/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1dc494e

Please sign in to comment.