internal static async Task InformLastContactAsync(string command) { command += $" Client ip: {GetClientIp()}"; await HomeObject.SetValueAsync("LastHeardFromAlexa", DateTime.Now.ToString(CultureInfo.CurrentCulture)).ConfigureAwait(false); await HomeObject.SetValueAsync("LastHeardCommand", command).ConfigureAwait(false); }
public static async Task IncrementCounterAsync(string property) { int count = await HomeObject.GetValueAsync <int>(property).ConfigureAwait(false); count++; await HomeObject.SetValueAsync(property, count.ToString()).ConfigureAwait(false); }
public static async Task NotifyErrorAsync(EventLogEntryType errorType, string errorMessage, int id) { await HomeObject.SetValueAsync("AlexaLastCommunicationsError", errorMessage).ConfigureAwait(false); await IncrementCounterAsync("AlexaCommunicationsErrorCount").ConfigureAwait(false); WriteToWindowsApplicationEventLog(errorType, errorMessage, id); Debug.WriteLine(errorMessage); }
private static void SendStateChangeReportsToAlexa() { const int eventID = 20; const string errorPrefix = "Proactive state update error:"; // This queue blocks in the enumerator so this is essentially an infinite loop. foreach (StateChangeReportWrapper item in stateReportQueue) { if (BackgroundTaskManager.Shutdown.IsCancellationRequested) { BackgroundTaskManager.Shutdown.ThrowIfCancellationRequested(); return; } WebRequest request; try { string expiry; using (asyncObjectsLock.Lock()) { expiry = HomeObject.GetValueAsync <string>("AlexaAsyncAuthorizationCodeExpiry").GetAwaiter() .GetResult(); } if (string.IsNullOrEmpty(expiry)) { Task.Run(async() => { await HomeObject.SetValueAsync("SendAsyncEventsToAlexa", "False").ConfigureAwait(false); }); NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix}: no PSU expiry datetime. PSUs are now disabled. Enable premise skill.", eventID + 1).GetAwaiter().GetResult(); } if (!DateTime.TryParse(expiry, out var expiryDateTime)) { Task.Run(async() => { await HomeObject.SetValueAsync("SendAsyncEventsToAlexa", "False").ConfigureAwait(false); }); NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Cannot parse expiry date. PSUs are now disabled. Enable premise skill.", eventID + 1).GetAwaiter().GetResult(); continue; } // refresh auth token if expired if (DateTime.Compare(DateTime.UtcNow, expiryDateTime) >= 0) { RefreshAsyncToken(out string newToken); if (string.IsNullOrEmpty(newToken) ) // Error occurred during refresh - error logged in that method. { continue; } [email protected] = newToken; foreach (var queuedItem in stateReportQueue.InternalQueue) { [email protected] = newToken; } } request = WebRequest.Create(item.uri); request.Method = WebRequestMethods.Http.Post; request.ContentType = @"application/json"; request.ContentLength = item.Json.Length; Stream stream = request.GetRequestStream(); stream.Write(item.Bytes, 0, (int)request.ContentLength); stream.Close(); } catch (Exception ex) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix}: Unexpected error: {ex.Message}", eventID + 1) .GetAwaiter().GetResult(); continue; } try { using (HttpWebResponse httpResponse = request.GetResponse() as HttpWebResponse) { if (httpResponse == null || !(httpResponse.StatusCode == HttpStatusCode.OK || httpResponse.StatusCode == HttpStatusCode.Accepted)) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected status ({httpResponse?.StatusCode})", eventID + 2) .GetAwaiter().GetResult(); continue; } string responseString; using (Stream response = httpResponse.GetResponseStream()) { if (response == null) { NotifyErrorAsync(EventLogEntryType.Warning, $"{errorPrefix} Null response from request.", eventID + 3).GetAwaiter().GetResult(); continue; } StreamReader reader = new StreamReader(response, Encoding.UTF8); responseString = reader.ReadToEnd(); } IncrementCounterAsync("AlexaAsyncUpdateCount").GetAwaiter().GetResult(); Debug.WriteLine($"PSU Response Status ({httpResponse.StatusCode}) ContentLength: {httpResponse.ContentLength} Content: {responseString}"); Debug.WriteLine(item.Json); } } catch (WebException e) { using (WebResponse webresponse = e.Response) { HttpWebResponse httpResponse = (HttpWebResponse)webresponse; switch (httpResponse.StatusCode) { case HttpStatusCode.Unauthorized : // The skill is enabled, but the authentication token has expired. RefreshAsyncToken(out string newToken); if (string.IsNullOrEmpty(newToken) ) // Error occurred during refresh - error logged in that method. { continue; } [email protected] = newToken; foreach (var queuedItem in stateReportQueue.InternalQueue) { [email protected] = newToken; } stateReportQueue.Enqueue(item); continue; case HttpStatusCode.Forbidden : // The skill is disabled so disable sending Async events to Alexa Task.Run(async() => { await HomeObject.SetValueAsync("SendAsyncEventsToAlexa", "False").ConfigureAwait(false); }); NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Premise skill has been disabled. PSUs are now disabled. Enable premise skill.", eventID + 4).GetAwaiter().GetResult(); continue; case HttpStatusCode.BadRequest: NotifyErrorAsync(EventLogEntryType.Warning, $"{errorPrefix} The message contains invalid identifying information such as a invalid endpoint Id or correlation token. Message:\r\n {item.Json}", eventID + 5).GetAwaiter().GetResult(); continue; default: NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected status: {e.Message}", eventID + 6).GetAwaiter().GetResult(); continue; } } } catch (Exception ex) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected error: {ex.Message}", eventID + 7) .GetAwaiter().GetResult(); continue; } Thread.Sleep(100); // throttle per spec } }
private static void RefreshAsyncToken(out string newToken) { const int eventID = 10; const string errorPrefix = "Refresh async token error:"; using (asyncObjectsLock.Lock()) { string previousToken; WebRequest refreshRequest; newToken = ""; try { refreshRequest = WebRequest.Create(AlexaEventTokenRefreshEndpoint); refreshRequest.Method = WebRequestMethods.Http.Post; refreshRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8"; previousToken = HomeObject.GetValueAsync <string>("AlexaAsyncAuthorizationCode").GetAwaiter().GetResult(); string refresh_token = HomeObject.GetValueAsync <string>("AlexaAsyncAuthorizationRefreshToken").GetAwaiter().GetResult(); string client_id = HomeObject.GetValueAsync <string>("AlexaAsyncAuthorizationClientId").GetAwaiter().GetResult(); string client_secret = HomeObject.GetValueAsync <string>("AlexaAsyncAuthorizationSecret").GetAwaiter().GetResult(); if (string.IsNullOrEmpty(refresh_token) || string.IsNullOrEmpty(client_id) || string.IsNullOrEmpty(client_secret)) { Task.Run(async() => { await HomeObject.SetValueAsync("SendAsyncEventsToAlexa", "False").ConfigureAwait(false); }); NotifyErrorAsync(EventLogEntryType.Warning, $"{errorPrefix} Alexa authorization token is missing. PSUs are now disabled. Re-enable Premise skill.", eventID + 1).GetAwaiter().GetResult(); return; } string refreshData = $"grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}"; Stream stream = refreshRequest.GetRequestStream(); stream.Write(Encoding.UTF8.GetBytes(refreshData), 0, Encoding.UTF8.GetByteCount(refreshData)); stream.Close(); } catch (Exception e) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected error: {e.Message}", eventID + 2).GetAwaiter().GetResult(); return; } try { using (HttpWebResponse httpResponse = refreshRequest.GetResponse() as HttpWebResponse) { if (httpResponse == null || !(httpResponse.StatusCode == HttpStatusCode.OK || httpResponse.StatusCode == HttpStatusCode.Accepted)) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Null response or unexpected status: ({httpResponse?.StatusCode})", eventID + 3).GetAwaiter().GetResult(); return; } string responseString; using (Stream response = httpResponse.GetResponseStream()) { if (response == null) { NotifyErrorAsync(EventLogEntryType.Warning, $"{errorPrefix} Null response from Amazon.", eventID + 4).GetAwaiter().GetResult(); return; } StreamReader reader = new StreamReader(response, Encoding.UTF8); responseString = reader.ReadToEnd(); } JObject json = JObject.Parse(responseString); newToken = json["access_token"].ToString(); HomeObject.SetValueAsync("AlexaAsyncAuthorizationCode", newToken).GetAwaiter().GetResult(); HomeObject.SetValueAsync("AlexaAsyncAuthorizationRefreshToken", json["refresh_token"].ToString()).GetAwaiter().GetResult(); DateTime expiry = DateTime.UtcNow.AddSeconds((double)json["expires_in"]); HomeObject.SetValueAsync("AlexaAsyncAuthorizationCodeExpiry", expiry.ToString(CultureInfo.InvariantCulture)).GetAwaiter().GetResult(); Debug.WriteLine("async token refresh response:" + responseString); WriteToWindowsApplicationEventLog(EventLogEntryType.Information, $"Alexa async auth token successfully refreshed. Previous Token (hash):{previousToken.GetHashCode()} New Token (hash):{newToken.GetHashCode()}", eventID); } } catch (WebException e) { using (WebResponse webresponse = e.Response) { HttpWebResponse httpResponse = (HttpWebResponse)webresponse; if (httpResponse.StatusCode == HttpStatusCode.Unauthorized ) // skill has ben disabled so disable sending Async events to Alexa { Task.Run(async() => { await HomeObject.SetValueAsync("SendAsyncEventsToAlexa", "False").ConfigureAwait(false); }); string responseString; using (Stream response = e.Response.GetResponseStream()) { if (response == null) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Null response.", eventID + 5).GetAwaiter().GetResult(); return; } StreamReader reader = new StreamReader(response, Encoding.UTF8); responseString = reader.ReadToEnd(); } JObject json = JObject.Parse(responseString); string message = $"{errorPrefix} PSUs are disabled. ErrorInfo: {json["error"]} Description: {json["error_description"]} More info: {json["error_uri"]}"; NotifyErrorAsync(EventLogEntryType.Error, message, eventID + 6).GetAwaiter().GetResult(); return; } NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected error status ({httpResponse.StatusCode})", eventID + 7).GetAwaiter().GetResult(); } } catch (Exception e) { NotifyErrorAsync(EventLogEntryType.Error, $"{errorPrefix} Unexpected error: {e.Message}", eventID + 8).GetAwaiter().GetResult(); } } }