Skip to content

Commit

Permalink
Add rate limiting data to responses
Browse files Browse the repository at this point in the history
  • Loading branch information
bartekn committed Feb 18, 2016
1 parent 0ef2750 commit e0ee7f1
Show file tree
Hide file tree
Showing 18 changed files with 113 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public AccountResponse account(KeyPair account) throws IOException {
* Requests specific <code>uri</code> and returns {@link Page} of {@link AccountResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link AccountResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<AccountResponse> execute(URI uri) throws IOException {
Expand Down Expand Up @@ -90,6 +91,7 @@ public void onEvent(InboundEvent inboundEvent) {
/**
* Build and execute request. <strong>Warning!</strong> {@link AccountResponse}s in {@link Page} will contain only <code>keypair</code> field.
* @return {@link Page} of {@link AccountResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<AccountResponse> execute() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public EffectsRequestBuilder forOperation(long operationId) {
* Requests specific <code>uri</code> and returns {@link Page} of {@link EffectResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link EffectResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<EffectResponse> execute(URI uri) throws IOException {
Expand Down Expand Up @@ -112,6 +113,7 @@ public void onEvent(InboundEvent inboundEvent) {
/**
* Build and execute request.
* @return {@link Page} of {@link EffectResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<EffectResponse> execute() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public LedgerResponse ledger(long ledgerSeq) throws IOException {
* Requests specific <code>uri</code> and returns {@link Page} of {@link LedgerResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link LedgerResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<LedgerResponse> execute(URI uri) throws IOException {
Expand Down Expand Up @@ -89,6 +90,7 @@ public void onEvent(InboundEvent inboundEvent) {
/**
* Build and execute request.
* @return {@link Page} of {@link LedgerResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<LedgerResponse> execute() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public OperationsRequestBuilder forTransaction(String transactionId) {
* Requests specific <code>uri</code> and returns {@link Page} of {@link OperationResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link OperationResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<OperationResponse> execute(URI uri) throws IOException {
Expand All @@ -89,6 +90,7 @@ public static Page<OperationResponse> execute(URI uri) throws IOException {
/**
* Build and execute request.
* @return {@link Page} of {@link OperationResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<OperationResponse> execute() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,20 @@ public PathsRequestBuilder destinationAsset(Asset asset) {
return this;
}

/**
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<PathResponse> execute(URI uri) throws IOException {
TypeToken type = new TypeToken<Page<PathResponse>>() {};
ResponseHandler<Page<PathResponse>> responseHandler = new ResponseHandler<Page<PathResponse>>(type);
return (Page<PathResponse>) Request.Get(uri).execute().handleResponse(responseHandler);
}

/**
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<PathResponse> execute() throws IOException {
return this.execute(this.buildUri());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public PaymentsRequestBuilder forTransaction(String transactionId) {
* Requests specific <code>uri</code> and returns {@link Page} of {@link OperationResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link OperationResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<OperationResponse> execute(URI uri) throws IOException {
Expand Down Expand Up @@ -102,6 +103,7 @@ public void onEvent(InboundEvent inboundEvent) {
/**
* Build and execute request.
* @return {@link Page} of {@link OperationResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<OperationResponse> execute() throws IOException {
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/org/stellar/sdk/requests/ResponseHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import com.google.gson.reflect.TypeToken;

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.stellar.sdk.responses.GsonSingleton;
import org.stellar.sdk.responses.Response;

import java.io.IOException;
import java.io.StringWriter;
Expand All @@ -31,9 +33,17 @@ public ResponseHandler(TypeToken<T> type) {
public T handleResponse(final HttpResponse response) throws IOException {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();

// Too Many Requests
if (statusLine.getStatusCode() == 429) {
int retryAfter = Integer.parseInt(response.getFirstHeader("Retry-After").getValue());
throw new TooManyRequestsException(retryAfter);
}
// Other errors
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
// No content
if (entity == null) {
throw new ClientProtocolException("Response contains no content");
}
Expand All @@ -42,6 +52,14 @@ public T handleResponse(final HttpResponse response) throws IOException {
IOUtils.copy(entity.getContent(), writer);
String content = writer.toString();

return GsonSingleton.getInstance().fromJson(content, type.getType());
T object = GsonSingleton.getInstance().fromJson(content, type.getType());
if (object instanceof Response) {
((Response) object).setHeaders(
response.getFirstHeader("X-Ratelimit-Limit"),
response.getFirstHeader("X-Ratelimit-Remaining"),
response.getFirstHeader("X-Ratelimit-Reset")
);
}
return object;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.stellar.sdk.requests;

/**
* Exception thrown when too many requests were sent to the Horizon server.
* @see <a href="https://www.stellar.org/developers/horizon/learn/rate-limiting.html" target="_blank">Rate Limiting</a>
*/
public class TooManyRequestsException extends RuntimeException {
private int retryAfter;

public TooManyRequestsException(int retryAfter) {
super("The rate limit for the requesting IP address is over its alloted limit.");
this.retryAfter = retryAfter;
}

/**
* Returns number of seconds a client should wait before sending requests again.
* @return
*/
public int getRetryAfter() {
return retryAfter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public TransactionsRequestBuilder forLedger(long ledgerSeq) {
* Requests specific <code>uri</code> and returns {@link Page} of {@link TransactionResponse}.
* This method is helpful for getting the next set of results.
* @return {@link Page} of {@link TransactionResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public static Page<TransactionResponse> execute(URI uri) throws IOException {
Expand Down Expand Up @@ -113,6 +114,7 @@ public void onEvent(InboundEvent inboundEvent) {
/**
* Build and execute request.
* @return {@link Page} of {@link TransactionResponse}
* @throws TooManyRequestsException when too many requests were sent to the Horizon server.
* @throws IOException
*/
public Page<TransactionResponse> execute() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* @see org.stellar.sdk.requests.AccountsRequestBuilder
* @see org.stellar.sdk.Server#accounts()
*/
public class AccountResponse implements org.stellar.sdk.TransactionBuilderAccount {
public class AccountResponse extends Response implements org.stellar.sdk.TransactionBuilderAccount {
@SerializedName("account_id") /* KeyPairTypeAdapter used */
private KeyPair keypair;
@SerializedName("sequence")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @see org.stellar.sdk.requests.LedgersRequestBuilder
* @see org.stellar.sdk.Server#ledgers()
*/
public class LedgerResponse {
public class LedgerResponse extends Response {
@SerializedName("sequence")
private final Long sequence;
@SerializedName("hash")
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/stellar/sdk/responses/Page.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* Represents page of objects.
* @see <a href="https://www.stellar.org/developers/horizon/reference/resources/page.html" target="_blank">Page documentation</a>
*/
public class Page<T> {
public class Page<T> extends Response {
@SerializedName("records")
private ArrayList<T> records;
@SerializedName("links")
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/stellar/sdk/responses/PathResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* @see org.stellar.sdk.requests.PathsRequestBuilder
* @see org.stellar.sdk.Server#paths()
*/
public class PathResponse {
public class PathResponse extends Response {
@SerializedName("destination_amount")
private final String destinationAmount;
@SerializedName("destination_asset_type")
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/org/stellar/sdk/responses/Response.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.stellar.sdk.responses;

import org.apache.http.Header;

public abstract class Response {
protected int rateLimitLimit;
protected int rateLimitRemaining;
protected int rateLimitReset;

public void setHeaders(Header limit, Header remaining, Header reset) {
this.rateLimitLimit = Integer.parseInt(limit.getValue());
this.rateLimitRemaining = Integer.parseInt(remaining.getValue());
this.rateLimitReset = Integer.parseInt(reset.getValue());
}

/**
* Returns X-RateLimit-Limit header from the response.
* This number represents the he maximum number of requests that the current client can
* make in one hour.
* @see <a href="https://www.stellar.org/developers/horizon/learn/rate-limiting.html" target="_blank">Rate Limiting</a>
*/
public int getRateLimitLimit() {
return rateLimitLimit;
}

/**
* Returns X-RateLimit-Remaining header from the response.
* The number of remaining requests for the current window.
* @see <a href="https://www.stellar.org/developers/horizon/learn/rate-limiting.html" target="_blank">Rate Limiting</a>
*/
public int getRateLimitRemaining() {
return rateLimitRemaining;
}

/**
* Returns X-RateLimit-Reset header from the response. Seconds until a new window starts.
* @see <a href="https://www.stellar.org/developers/horizon/learn/rate-limiting.html" target="_blank">Rate Limiting</a>
*/
public int getRateLimitReset() {
return rateLimitReset;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Represents server response after submitting transaction.
* @see Server#submitTransaction(org.stellar.sdk.Transaction)
*/
public class SubmitTransactionResponse {
public class SubmitTransactionResponse extends Response {
@SerializedName("hash")
private final String hash;
@SerializedName("ledger")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @see org.stellar.sdk.requests.TransactionsRequestBuilder
* @see org.stellar.sdk.Server#transactions()
*/
public class TransactionResponse {
public class TransactionResponse extends Response {
@SerializedName("hash")
private final String hash;
@SerializedName("ledger")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

import org.stellar.sdk.KeyPair;
import org.stellar.sdk.responses.Link;
import org.stellar.sdk.responses.Response;

/**
* Abstract class for effect responses.
* @see <a href="https://www.stellar.org/developers/horizon/reference/resources/effect.html" target="_blank">Effect documentation</a>
* @see org.stellar.sdk.requests.EffectsRequestBuilder
* @see org.stellar.sdk.Server#effects()
*/
public abstract class EffectResponse {
public abstract class EffectResponse extends Response {
@SerializedName("id")
protected String id;
@SerializedName("account")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

import org.stellar.sdk.KeyPair;
import org.stellar.sdk.responses.Link;
import org.stellar.sdk.responses.Response;

/**
* Abstract class for operation responses.
* @see <a href="https://www.stellar.org/developers/horizon/reference/resources/operation.html" target="_blank">Operation documentation</a>
* @see org.stellar.sdk.requests.OperationsRequestBuilder
* @see org.stellar.sdk.Server#operations()
*/
public abstract class OperationResponse {
public abstract class OperationResponse extends Response {
@SerializedName("id")
protected Long id;
@SerializedName("source_account")
Expand Down

0 comments on commit e0ee7f1

Please sign in to comment.