From e092a109eae71b706092489ccee867181a2763df Mon Sep 17 00:00:00 2001 From: Mark Taylor Date: Sun, 26 Jul 2015 22:03:19 +0100 Subject: [PATCH] Additional changes to support rate_limit API call --- .../Clients/IObservableMiscellaneousClient.cs | 4 +- .../Clients/ObservableMiscellaneousClient.cs | 4 +- .../Clients/MiscellaneousClientTests.cs | 12 +++--- .../Clients/MiscellaneousClientTests.cs | 28 ++++++------- Octokit/Clients/IMiscellaneousClient.cs | 4 +- Octokit/Clients/MiscellaneousClient.cs | 8 ++-- Octokit/Helpers/UnixTimeStampExtensions.cs | 9 ++++ Octokit/Http/RateLimit.cs | 31 ++++++++++++++ ...ateLimits.cs => MiscellaneousRateLimit.cs} | 10 ++--- Octokit/Models/Response/ResourceRateLimit.cs | 41 +++++++----------- Octokit/Models/Response/ResourceRateLimits.cs | 42 ------------------- Octokit/Octokit-Mono.csproj | 3 +- Octokit/Octokit-MonoAndroid.csproj | 3 +- Octokit/Octokit-Monotouch.csproj | 3 +- Octokit/Octokit-Portable.csproj | 3 +- Octokit/Octokit-netcore45.csproj | 3 +- Octokit/Octokit.csproj | 3 +- 17 files changed, 94 insertions(+), 117 deletions(-) rename Octokit/Models/Response/{MiscRateLimits.cs => MiscellaneousRateLimit.cs} (76%) delete mode 100644 Octokit/Models/Response/ResourceRateLimits.cs diff --git a/Octokit.Reactive/Clients/IObservableMiscellaneousClient.cs b/Octokit.Reactive/Clients/IObservableMiscellaneousClient.cs index 2b5a8b64..56ac658a 100644 --- a/Octokit.Reactive/Clients/IObservableMiscellaneousClient.cs +++ b/Octokit.Reactive/Clients/IObservableMiscellaneousClient.cs @@ -55,9 +55,9 @@ namespace Octokit.Reactive /// Gets API Rate Limits (API service rather than header info). /// /// Thrown when a general API error occurs. - /// An of Rate Limits. + /// An of Rate Limits. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - IObservable GetRateLimits(); + IObservable GetRateLimits(); } } diff --git a/Octokit.Reactive/Clients/ObservableMiscellaneousClient.cs b/Octokit.Reactive/Clients/ObservableMiscellaneousClient.cs index 8f0a4ae3..0675437f 100644 --- a/Octokit.Reactive/Clients/ObservableMiscellaneousClient.cs +++ b/Octokit.Reactive/Clients/ObservableMiscellaneousClient.cs @@ -79,9 +79,9 @@ namespace Octokit.Reactive /// Gets API Rate Limits (API service rather than header info). /// /// Thrown when a general API error occurs. - /// An of Rate Limits. + /// An of Rate Limits. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IObservable GetRateLimits() + public IObservable GetRateLimits() { return _client.GetRateLimits().ToObservable(); } diff --git a/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs b/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs index 451b30c6..cc37a98a 100644 --- a/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs +++ b/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs @@ -91,24 +91,24 @@ public class MiscellaneousClientTests Assert.True(result.Resources.Core.Limit > 0); Assert.True(result.Resources.Core.Remaining > -1); Assert.True(result.Resources.Core.Remaining <= result.Resources.Core.Limit); - Assert.True(result.Resources.Core.Reset > 0); - Assert.NotNull(result.Resources.Core.ResetAsDateTimeOffset); + Assert.True(result.Resources.Core.ResetAsUtcEpochSeconds > 0); + Assert.NotNull(result.Resources.Core.Reset); // Test the search limits Assert.NotNull(result.Resources.Search); Assert.True(result.Resources.Search.Limit > 0); Assert.True(result.Resources.Search.Remaining > -1); Assert.True(result.Resources.Search.Remaining <= result.Resources.Search.Limit); - Assert.True(result.Resources.Search.Reset > 0); - Assert.NotNull(result.Resources.Search.ResetAsDateTimeOffset); + Assert.True(result.Resources.Search.ResetAsUtcEpochSeconds > 0); + Assert.NotNull(result.Resources.Search.Reset); // Test the depreciated rate limits Assert.NotNull(result.Rate); Assert.True(result.Rate.Limit > 0); Assert.True(result.Rate.Remaining > -1); Assert.True(result.Rate.Remaining <= result.Rate.Limit); - Assert.True(result.Resources.Search.Reset > 0); - Assert.NotNull(result.Resources.Search.ResetAsDateTimeOffset); + Assert.True(result.Resources.Search.ResetAsUtcEpochSeconds > 0); + Assert.NotNull(result.Resources.Search.Reset); } } diff --git a/Octokit.Tests/Clients/MiscellaneousClientTests.cs b/Octokit.Tests/Clients/MiscellaneousClientTests.cs index 48fe696b..7e1c0308 100644 --- a/Octokit.Tests/Clients/MiscellaneousClientTests.cs +++ b/Octokit.Tests/Clients/MiscellaneousClientTests.cs @@ -64,19 +64,19 @@ namespace Octokit.Tests.Clients [Fact] public async Task RequestsTheRecourceRateLimitEndpoint() { - IApiResponse response = new ApiResponse + IApiResponse response = new ApiResponse ( new Response(), - new MiscRateLimits( - new ResourceRateLimits( - new ResourceRateLimit(5000, 4999, 1372700873), - new ResourceRateLimit(30, 18, 1372700873) + new MiscellaneousRateLimit( + new ResourceRateLimit( + new RateLimit(5000, 4999, 1372700873), + new RateLimit(30, 18, 1372700873) ), - new ResourceRateLimit(100, 75, 1372700873) + new RateLimit(100, 75, 1372700873) ) ); var connection = Substitute.For(); - connection.Get(Args.Uri, null, null).Returns(Task.FromResult(response)); + connection.Get(Args.Uri, null, null).Returns(Task.FromResult(response)); var client = new MiscellaneousClient(connection); var result = await client.GetRateLimits(); @@ -91,37 +91,37 @@ namespace Octokit.Tests.Clients Assert.NotNull(result.Resources.Core); Assert.Equal(5000, result.Resources.Core.Limit); Assert.Equal(4999, result.Resources.Core.Remaining); - Assert.Equal(1372700873, result.Resources.Core.Reset); + Assert.Equal(1372700873, result.Resources.Core.ResetAsUtcEpochSeconds); var expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); - Assert.Equal(expectedReset, result.Resources.Core.ResetAsDateTimeOffset); + Assert.Equal(expectedReset, result.Resources.Core.Reset); // Test the search limits Assert.NotNull(result.Resources.Search); Assert.Equal(30, result.Resources.Search.Limit); Assert.Equal(18, result.Resources.Search.Remaining); - Assert.Equal(1372700873, result.Resources.Search.Reset); + Assert.Equal(1372700873, result.Resources.Search.ResetAsUtcEpochSeconds); expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); - Assert.Equal(expectedReset, result.Resources.Search.ResetAsDateTimeOffset); + Assert.Equal(expectedReset, result.Resources.Search.Reset); // Test the depreciated rate limits Assert.NotNull(result.Rate); Assert.Equal(100, result.Rate.Limit); Assert.Equal(75, result.Rate.Remaining); - Assert.Equal(1372700873, result.Rate.Reset); + Assert.Equal(1372700873, result.Rate.ResetAsUtcEpochSeconds); expectedReset = DateTimeOffset.ParseExact( "Mon 01 Jul 2013 5:47:53 PM -00:00", "ddd dd MMM yyyy h:mm:ss tt zzz", CultureInfo.InvariantCulture); - Assert.Equal(expectedReset, result.Rate.ResetAsDateTimeOffset); + Assert.Equal(expectedReset, result.Rate.Reset); connection.Received() - .Get(Arg.Is(u => u.ToString() == "rate_limit"), null, null); + .Get(Arg.Is(u => u.ToString() == "rate_limit"), null, null); } } diff --git a/Octokit/Clients/IMiscellaneousClient.cs b/Octokit/Clients/IMiscellaneousClient.cs index 75b40a31..ef3a1696 100644 --- a/Octokit/Clients/IMiscellaneousClient.cs +++ b/Octokit/Clients/IMiscellaneousClient.cs @@ -64,8 +64,8 @@ namespace Octokit /// Gets API Rate Limits (API service rather than header info). /// /// Thrown when a general API error occurs. - /// An of Rate Limits. + /// An of Rate Limits. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - Task GetRateLimits(); + Task GetRateLimits(); } } diff --git a/Octokit/Clients/MiscellaneousClient.cs b/Octokit/Clients/MiscellaneousClient.cs index f4fec16a..10011656 100644 --- a/Octokit/Clients/MiscellaneousClient.cs +++ b/Octokit/Clients/MiscellaneousClient.cs @@ -121,15 +121,13 @@ namespace Octokit /// Gets API Rate Limits (API service rather than header info). /// /// Thrown when a general API error occurs. - /// An of Rate Limits. + /// An of Rate Limits. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public async Task GetRateLimits() + public async Task GetRateLimits() { var endpoint = new Uri("rate_limit", UriKind.Relative); - var response = await _connection.Get(endpoint, null, null).ConfigureAwait(false); - //var response = await _connection.Get(endpoint, null, null).ConfigureAwait(false); + var response = await _connection.Get(endpoint, null, null).ConfigureAwait(false); return response.Body; - //return null; } } } \ No newline at end of file diff --git a/Octokit/Helpers/UnixTimeStampExtensions.cs b/Octokit/Helpers/UnixTimeStampExtensions.cs index 397c155f..70ec92b3 100644 --- a/Octokit/Helpers/UnixTimeStampExtensions.cs +++ b/Octokit/Helpers/UnixTimeStampExtensions.cs @@ -18,5 +18,14 @@ namespace Octokit.Helpers { return new DateTimeOffset(unixTime * TimeSpan.TicksPerSecond + unixEpochTicks, TimeSpan.Zero); } + + /// + /// Convert with UTC offset to a Unix tick + /// + /// Date Time with UTC offset + public static long ToUnixTime(this DateTimeOffset date) + { + return (date.Ticks - unixEpochTicks) / TimeSpan.TicksPerSecond; + } } } diff --git a/Octokit/Http/RateLimit.cs b/Octokit/Http/RateLimit.cs index 44b572da..f6621b57 100644 --- a/Octokit/Http/RateLimit.cs +++ b/Octokit/Http/RateLimit.cs @@ -2,17 +2,22 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Octokit.Helpers; +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; namespace Octokit { #if !NETFX_CORE [Serializable] #endif + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class RateLimit #if !NETFX_CORE : ISerializable #endif { + public RateLimit() {} public RateLimit(IDictionary responseHeaders) { @@ -23,6 +28,17 @@ namespace Octokit Reset = GetHeaderValueAsInt32Safe(responseHeaders, "X-RateLimit-Reset").FromUnixTime(); } + public RateLimit(int limit, int remaining, long reset) + { + Ensure.ArgumentNotNull(limit, "limit"); + Ensure.ArgumentNotNull(remaining, "remaining"); + Ensure.ArgumentNotNull(reset, "reset"); + + Limit = limit; + Remaining = remaining; + Reset = reset.FromUnixTime(); + } + /// /// The maximum number of requests that the consumer is permitted to make per hour. /// @@ -36,8 +52,16 @@ namespace Octokit /// /// The date and time at which the current rate limit window resets /// + [ParameterAttribute(Key = "ignoreThisField")] public DateTimeOffset Reset { get; private set; } + /// + /// The date and time at which the current rate limit window resets - in UTC epoch seconds + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [ParameterAttribute(Key = "reset")] + public long ResetAsUtcEpochSeconds { get { return Reset.ToUnixTime(); } private set { Reset = value.FromUnixTime(); } } + static long GetHeaderValueAsInt32Safe(IDictionary responseHeaders, string key) { string value; @@ -66,5 +90,12 @@ namespace Octokit info.AddValue("Reset", Reset.Ticks); } #endif + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Limit {0}, Remaining {1}, Reset {2} ", Limit, Remaining, Reset); + } + } } } diff --git a/Octokit/Models/Response/MiscRateLimits.cs b/Octokit/Models/Response/MiscellaneousRateLimit.cs similarity index 76% rename from Octokit/Models/Response/MiscRateLimits.cs rename to Octokit/Models/Response/MiscellaneousRateLimit.cs index 1a0ac285..707e0d53 100644 --- a/Octokit/Models/Response/MiscRateLimits.cs +++ b/Octokit/Models/Response/MiscellaneousRateLimit.cs @@ -9,11 +9,11 @@ using System.Threading.Tasks; namespace Octokit { [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class MiscRateLimits + public class MiscellaneousRateLimit { - public MiscRateLimits() {} + public MiscellaneousRateLimit() {} - public MiscRateLimits(ResourceRateLimits resources, ResourceRateLimit rate) + public MiscellaneousRateLimit(ResourceRateLimit resources, RateLimit rate) { Ensure.ArgumentNotNull(resources, "resource"); Ensure.ArgumentNotNull(rate, "rate"); @@ -25,12 +25,12 @@ namespace Octokit /// /// Object of resources rate limits /// - public ResourceRateLimits Resources { get; private set; } + public ResourceRateLimit Resources { get; private set; } /// /// Legacy rate limit - to be depreciated - https://developer.github.com/v3/rate_limit/#deprecation-notice /// - public ResourceRateLimit Rate { get; private set; } + public RateLimit Rate { get; private set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Response/ResourceRateLimit.cs b/Octokit/Models/Response/ResourceRateLimit.cs index 15995e87..99bd74f1 100644 --- a/Octokit/Models/Response/ResourceRateLimit.cs +++ b/Octokit/Models/Response/ResourceRateLimit.cs @@ -9,47 +9,34 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class ResourceRateLimit { - public ResourceRateLimit() { } + public ResourceRateLimit() {} - public ResourceRateLimit(int limit, int remaining, long reset) + public ResourceRateLimit(RateLimit core, RateLimit search) { - Ensure.ArgumentNotNull(limit, "limit"); - Ensure.ArgumentNotNull(remaining, "remaining"); - Ensure.ArgumentNotNull(reset, "reset"); + Ensure.ArgumentNotNull(core, "core"); + Ensure.ArgumentNotNull(search, "search"); - Limit = limit; - Remaining = remaining; - Reset = reset; + Core = core; + Search = search; } + /// + /// Rate limits for core API (rate limit for everything except Search API) + /// + public RateLimit Core { get; private set; } /// - /// The maximum number of requests that the consumer is permitted to make per hour. + /// Rate Limits for Search API /// - public int Limit { get; private set; } - - /// - /// The number of requests remaining in the current rate limit window. - /// - public int Remaining { get; private set; } - - /// - /// The date and time at which the current rate limit window resets - in UTC epoch seconds - /// - public long Reset { get; private set; } - - /// - /// The date and time at which the current rate limit window resets - as DateTimeOffset - /// - public DateTimeOffset ResetAsDateTimeOffset { get { return Reset.FromUnixTime(); } } - + public RateLimit Search { get; private set; } internal string DebuggerDisplay { get { - return String.Format(CultureInfo.InvariantCulture, "Limit {0}, Remaining {1}, Reset {2} ", Limit, Remaining, Reset); + return String.Format(CultureInfo.InvariantCulture, "Core: {0}; Search: {1} ", Core.DebuggerDisplay, Search.DebuggerDisplay); } } } + } diff --git a/Octokit/Models/Response/ResourceRateLimits.cs b/Octokit/Models/Response/ResourceRateLimits.cs deleted file mode 100644 index 70c5d2cb..00000000 --- a/Octokit/Models/Response/ResourceRateLimits.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Diagnostics; -using System.Globalization; - -using Octokit.Helpers; - -namespace Octokit -{ - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class ResourceRateLimits - { - public ResourceRateLimits() {} - - public ResourceRateLimits(ResourceRateLimit core, ResourceRateLimit search) - { - Ensure.ArgumentNotNull(core, "core"); - Ensure.ArgumentNotNull(search, "search"); - - Core = core; - Search = search; - } - - /// - /// Rate limits for core API (rate limit for everything except Search API) - /// - public ResourceRateLimit Core { get; private set; } - - /// - /// Rate Limits for Search API - /// - public ResourceRateLimit Search { get; private set; } - - internal string DebuggerDisplay - { - get - { - return String.Format(CultureInfo.InvariantCulture, "Core: {0}; Search: {1} ", Core.DebuggerDisplay, Search.DebuggerDisplay); - } - } - } - -} diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index c3e9f989..d2d5776f 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -396,9 +396,8 @@ - - + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index fb756b17..81444b5f 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -412,9 +412,8 @@ - - + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index e82708dd..2e68fd10 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -405,9 +405,8 @@ - - + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index f3586321..042dcc35 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -394,9 +394,8 @@ - - + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index fc2a20fa..f0827838 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -398,9 +398,8 @@ - - + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index bb4ef867..09b0b40a 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -116,10 +116,9 @@ - + -