/// <summary> /// Callback method which will perform a new login to refresh the token /// </summary> /// <param name="state">Not used</param> private void TokenExpireTimer_Callback(Object state) { try { var loginInfo = Login(); if (String.IsNullOrEmpty(loginInfo.Token)) { throw new Exception("Got blank token when trying to refresh"); } OnTokenRefreshed.Invoke(this, loginInfo.Token); } catch (Exception e) { CancelCallbackTimer(); throw new Exception("Error refreshing token: " + e.Message); } }
private void _connection_OnTokenRefreshed(object sender, string e) { OnTokenRefreshed.Invoke(this, e); }
/// <summary> /// Submits a HTTP request to the specified Uri and returns the response. /// </summary> /// <remarks> /// Non-JSON responses are converted to the standard <c>{status,error,message}</c> format. /// /// If a 401 is returned, one attempt will be made to refresh the OAuth token and try again. /// The <paramref name="session"/> object is updated and <see cref="OnTokenRefreshed"/> is called on refresh success. /// </remarks> /// <param name="method">The <see cref="HttpMethod"/> of the request.</param> /// <param name="uri">The Uri to request. Relative Uris resolve against the Helix base.</param> /// <param name="session">The <see cref="TwitchSession"/> to authorize the request.</param> /// <param name="content">The body of the request, for methods that require it.</param> /// <returns>A <see cref="HttpResponseMessage"/> containing the response data.</returns> /// <exception cref="InvalidOperationException">Did not call <see cref="Init(string)"/> with a valid Client Id or <paramref name="session"/> does not have an OAuth token.</exception> internal static async Task <HttpResponseMessage> PerformHttpRequest(HttpMethod method, Uri uri, TwitchSession session, HttpContent?content = null) { if (!_httpClient.DefaultRequestHeaders.Contains("Client-Id")) { throw new InvalidOperationException("Must call TwitchAPI.Init."); } if (string.IsNullOrWhiteSpace(session.Token?.OAuth)) { throw new InvalidOperationException("Invalid OAuth token in session."); } bool retry = false; performhttprequest_start: try { await session.RateLimiter.WaitForRateLimit(TimeSpan.FromSeconds(30)).ConfigureAwait(false); using HttpRequestMessage request = new(method, uri) { Version = _httpClient.DefaultRequestVersion, VersionPolicy = _httpClient.DefaultVersionPolicy }; request.Content = content; if (session.Token.OAuth != "__NEW") { request.Headers.Add("Authorization", "Bearer " + session.Token.OAuth); } HttpResponseMessage response = await _httpClient.SendAsync(request, CancellationToken.None).ConfigureAwait(false); if (!retry && response.StatusCode == System.Net.HttpStatusCode.Unauthorized && session.Token.OAuth != "__NEW") { Token?refresh = await Token.RefreshOAuth(session).ConfigureAwait(false); if (refresh is not null && refresh.IsSuccessStatusCode) { session.Token = new() { OAuth = refresh.AccessToken, Refresh = refresh.RefreshToken, Expires = refresh.Expires }; _ = (OnTokenRefreshed?.InvokeAsync(null, session)); retry = true; goto performhttprequest_start; } } if (response.Content.Headers?.ContentType?.MediaType != "application/json") { string rcontent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (!Regex.IsMatch(rcontent, @"\s*{.*}\s*")) { response.Content = new StringContent(JsonSerializer.Serialize(new TwitchResponse() { Status = (int)response.StatusCode, Message = rcontent }, new JsonSerializerOptions())); } } session.RateLimiter.ParseHeaders(response.Headers); return(response); } catch (Exception ex) when(ex is HttpRequestException or TimeoutException) { return(new(0) { ReasonPhrase = ex.GetType().Name, Content = new StringContent(ex.Message) });