static bool LimitExceeded(OAuthTokens tokens) { TwitterResponse <TwitterRateLimitStatus> response = TwitterRateLimitStatus.GetStatus(tokens); if (response.RateLimiting.Remaining == 0) { Console.Out.WriteLine($"Twitter rate limit hit. Will resume pulling @ {response.RateLimiting.ResetDate.ToString("hh:mm:ss")}"); } return(response.RateLimiting.Remaining == 0); }
/// <summary> /// Executes the command. /// </summary> /// <returns>The results of the command.</returns> public TwitterResponse <T> ExecuteCommand() { TwitterResponse <T> twitterResponse = new TwitterResponse <T>(); if (this.OptionalProperties.UseSSL) { this.Uri = new Uri(this.Uri.AbsoluteUri.Replace("http://", "https://")); } // Loop through all of the custom attributes assigned to the command class foreach (Attribute attribute in this.GetType().GetCustomAttributes(false)) { if (attribute is AuthorizedCommandAttribute) { if (this.Tokens == null) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Tokens are required for the \"{0}\" command.", this.GetType())); } if (string.IsNullOrEmpty(this.Tokens.ConsumerKey) || string.IsNullOrEmpty(this.Tokens.ConsumerSecret) || string.IsNullOrEmpty(this.Tokens.AccessToken) || string.IsNullOrEmpty(this.Tokens.AccessTokenSecret)) { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Token values cannot be null when executing the \"{0}\" command.", this.GetType())); } } else if (attribute is RateLimitedAttribute) { // Get the rate limiting status if (TwitterRateLimitStatus.GetStatus(this.Tokens).ResponseObject.RemainingHits == 0) { throw new TwitterizerException("You are being rate limited."); } } } // Prepare the query parameters Dictionary <string, object> queryParameters = new Dictionary <string, object>(); foreach (KeyValuePair <string, object> item in this.RequestParameters) { queryParameters.Add(item.Key, item.Value); } // Declare the variable to be returned twitterResponse.ResponseObject = default(T); twitterResponse.RequestUrl = this.Uri.AbsoluteUri; RateLimiting rateLimiting; AccessLevel accessLevel; byte[] responseData; try { WebRequestBuilder requestBuilder = new WebRequestBuilder(this.Uri, this.Verb, this.Tokens) { Multipart = this.Multipart }; #if !SILVERLIGHT if (this.OptionalProperties != null) { requestBuilder.Proxy = this.OptionalProperties.Proxy; } #endif foreach (var item in queryParameters) { requestBuilder.Parameters.Add(item.Key, item.Value); } HttpWebResponse response = requestBuilder.ExecuteRequest(); if (response == null) { twitterResponse.Result = RequestResult.Unknown; return(twitterResponse); } responseData = ConversionUtility.ReadStream(response.GetResponseStream()); twitterResponse.Content = Encoding.UTF8.GetString(responseData, 0, responseData.Length); twitterResponse.RequestUrl = requestBuilder.RequestUri.AbsoluteUri; #if !SILVERLIGHT // Parse the rate limiting HTTP Headers rateLimiting = ParseRateLimitHeaders(response.Headers); // Parse Access Level accessLevel = ParseAccessLevel(response.Headers); #else rateLimiting = null; accessLevel = AccessLevel.Unknown; #endif // Lookup the status code and set the status accordingly SetStatusCode(twitterResponse, response.StatusCode, rateLimiting); twitterResponse.RateLimiting = rateLimiting; twitterResponse.AccessLevel = accessLevel; } catch (WebException wex) { if (new[] { #if !SILVERLIGHT WebExceptionStatus.Timeout, WebExceptionStatus.ConnectionClosed, #endif WebExceptionStatus.ConnectFailure }.Contains(wex.Status)) { twitterResponse.Result = RequestResult.ConnectionFailure; twitterResponse.ErrorMessage = wex.Message; return(twitterResponse); } // The exception response should always be an HttpWebResponse, but we check for good measure. HttpWebResponse exceptionResponse = wex.Response as HttpWebResponse; if (exceptionResponse == null) { throw; } responseData = ConversionUtility.ReadStream(exceptionResponse.GetResponseStream()); twitterResponse.Content = Encoding.UTF8.GetString(responseData, 0, responseData.Length); #if !SILVERLIGHT rateLimiting = ParseRateLimitHeaders(exceptionResponse.Headers); // Parse Access Level accessLevel = ParseAccessLevel(exceptionResponse.Headers); #else rateLimiting = null; accessLevel = AccessLevel.Unknown; #endif // Try to read the error message, if there is one. try { TwitterErrorDetails errorDetails = SerializationHelper <TwitterErrorDetails> .Deserialize(responseData); twitterResponse.ErrorMessage = errorDetails.ErrorMessage; } catch (Exception) { // Occasionally, Twitter responds with XML error data even though we asked for json. // This is that scenario. We will deal with it by doing nothing. It's up to the developer to deal with it. } // Lookup the status code and set the status accordingly SetStatusCode(twitterResponse, exceptionResponse.StatusCode, rateLimiting); twitterResponse.RateLimiting = rateLimiting; twitterResponse.AccessLevel = accessLevel; if (wex.Status == WebExceptionStatus.UnknownError) { throw; } return(twitterResponse); } try { twitterResponse.ResponseObject = SerializationHelper <T> .Deserialize(responseData, this.DeserializationHandler); } catch (Newtonsoft.Json.JsonReaderException) { twitterResponse.ErrorMessage = "Unable to parse JSON"; twitterResponse.Result = RequestResult.Unknown; return(twitterResponse); } catch (Newtonsoft.Json.JsonSerializationException) { twitterResponse.ErrorMessage = "Unable to parse JSON"; twitterResponse.Result = RequestResult.Unknown; return(twitterResponse); } // Pass the current oauth tokens into the new object, so method calls from there will keep the authentication. twitterResponse.Tokens = this.Tokens; return(twitterResponse); }