From 689fff4eaccc30dd2d9f31274d3cc97ba8172a19 Mon Sep 17 00:00:00 2001 From: David Esner Date: Fri, 17 Aug 2018 14:48:51 +0200 Subject: [PATCH 1/2] UPDATE ratelimit details support, bugfixes --- CHANGES.md | 6 ++++ .../main/java/io/intercom/api/HttpClient.java | 20 +++++++++++++ .../main/java/io/intercom/api/Intercom.java | 16 ++++++++++ .../src/main/java/io/intercom/api/Job.java | 30 +++++++++++-------- .../src/main/java/io/intercom/api/User.java | 4 ++- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 164238af..9480ad56 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ ### Changes +#### 2.5.0 (modified) +- Add ratelimit info into core class +- Bugfix - parsing User object, invalid companies field definition +- Bugfix - Job.listJobErrorFeed - proper JSON object initialization + + #### 2.5.0 - Fix for #207 to remove a non-existent API call (PR #211) - Fix for #197 to prioritise user_id when tagging users (PR #199) diff --git a/intercom-java/src/main/java/io/intercom/api/HttpClient.java b/intercom-java/src/main/java/io/intercom/api/HttpClient.java index 74f36400..44d96ad1 100644 --- a/intercom-java/src/main/java/io/intercom/api/HttpClient.java +++ b/intercom-java/src/main/java/io/intercom/api/HttpClient.java @@ -25,6 +25,15 @@ import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +/** + * Customized class originally developed by Intercom Inc.,2014, under the ASF 2 + * license. The original source code available at + * https://github.com/intercom/intercom-java. + * + * Minor change adding means to manage current API rate limit details. + * + * @author David Esner + */ class HttpClient { private static final Logger logger = LoggerFactory.getLogger("intercom-java"); @@ -146,9 +155,19 @@ private HttpURLConnection initializeConnection(URI uri, String method) throws IO return conn; } + /* Store API rate limit on each request + */ private T runRequest(URI uri, JavaType javaType, HttpURLConnection conn) throws IOException { conn.connect(); final int responseCode = conn.getResponseCode(); + //get response headers + String ratelimit = conn.getHeaderField(RATE_LIMIT_HEADER); + String rateLimitRemaining = conn.getHeaderField(RATE_LIMIT_REMAINING_HEADER); + String rateLimitReset = conn.getHeaderField(RATE_LIMIT_RESET_HEADER); + //set current rate limit + if (ratelimit != null && rateLimitRemaining != null && rateLimitReset != null) { + Intercom.getRateLimitDetails().updateLimit(Integer.valueOf(ratelimit), Integer.valueOf(rateLimitRemaining), Long.valueOf(rateLimitReset)); + } if (responseCode >= 200 && responseCode < 300) { return handleSuccess(javaType, conn, responseCode); } else { @@ -156,6 +175,7 @@ private T runRequest(URI uri, JavaType javaType, HttpURLConnection conn) thr } } + private T handleError(URI uri, HttpURLConnection conn, int responseCode) throws IOException { ErrorCollection errors; try { diff --git a/intercom-java/src/main/java/io/intercom/api/Intercom.java b/intercom-java/src/main/java/io/intercom/api/Intercom.java index 0b4f1f6c..52e7c419 100644 --- a/intercom-java/src/main/java/io/intercom/api/Intercom.java +++ b/intercom-java/src/main/java/io/intercom/api/Intercom.java @@ -2,6 +2,15 @@ import java.net.URI; +/** + * Customized class originally developed by Intercom Inc.,2014, under the ASF 2 + * license. The original source code available at + * https://github.com/intercom/intercom-java. (v.2.5.0) + * + * Minor change adding means to manage current API rate limit details. + * + * @author David Esner + */ public class Intercom { private static final URI API_BASE_URI = URI.create("https://api.intercom.io/"); @@ -33,6 +42,13 @@ enum AuthKeyType { private static volatile HttpConnectorSupplier httpConnectorSupplier = HttpConnectorSupplier.defaultSupplier; + //new rateLimitDetails object + private static volatile RateLimitDetails rateLimitDetails = new RateLimitDetails(); + + public static RateLimitDetails getRateLimitDetails() { + return Intercom.rateLimitDetails; + } + public static long currentTimestamp() { return System.currentTimeMillis()/1000; } diff --git a/intercom-java/src/main/java/io/intercom/api/Job.java b/intercom-java/src/main/java/io/intercom/api/Job.java index ab7f1756..576285a6 100644 --- a/intercom-java/src/main/java/io/intercom/api/Job.java +++ b/intercom-java/src/main/java/io/intercom/api/Job.java @@ -1,5 +1,10 @@ package io.intercom.api; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,11 +12,6 @@ import com.fasterxml.jackson.databind.JavaType; import com.google.common.collect.Maps; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @SuppressWarnings("UnusedDeclaration") @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @@ -60,13 +60,17 @@ static JobItemCollection listJobErrorFeed(String jobID, final TypeReference> typeReference = new TypeReference>() { }; - - final JavaType type = MapperSupport - .objectMapper() - .getTypeFactory() - .constructParametricType(JobItemCollection.class, c); - return resource.get(type); - } + /* BugFix of original lib. */ + final JavaType type1 = MapperSupport + .objectMapper() + .getTypeFactory() + .constructParametricType(JobItem.class, c); + final JavaType type = MapperSupport + .objectMapper() + .getTypeFactory() + .constructParametricType(JobItemCollection.class, type1); + return resource.get(type); + } @JsonProperty("type") @@ -213,4 +217,4 @@ public int hashCode() { result = 31 * result + (links != null ? links.hashCode() : 0); return result; } -} +} \ No newline at end of file diff --git a/intercom-java/src/main/java/io/intercom/api/User.java b/intercom-java/src/main/java/io/intercom/api/User.java index 4964f5d5..aff7dc60 100644 --- a/intercom-java/src/main/java/io/intercom/api/User.java +++ b/intercom-java/src/main/java/io/intercom/api/User.java @@ -368,9 +368,11 @@ public Avatar getAvatar() { private LocationData locationData; @JsonIgnoreProperties(ignoreUnknown = false) - @JsonProperty("companies") + //@JsonProperty("companies") bugfix original sdk + @JsonIgnore private CompanyCollection companyCollection = new CompanyCollection(); + @JsonProperty("social_profiles") private SocialProfileCollection socialProfileCollection = new SocialProfileCollection(); From 4da6b4ec5c22b449137d8f3b43621f7bb624d73e Mon Sep 17 00:00:00 2001 From: David Esner Date: Fri, 17 Aug 2018 14:57:14 +0200 Subject: [PATCH 2/2] UPDATE ratelimit details support, bugfixes --- .../io/intercom/api/RateLimitDetails.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 intercom-java/src/main/java/io/intercom/api/RateLimitDetails.java diff --git a/intercom-java/src/main/java/io/intercom/api/RateLimitDetails.java b/intercom-java/src/main/java/io/intercom/api/RateLimitDetails.java new file mode 100644 index 00000000..fdf863dc --- /dev/null +++ b/intercom-java/src/main/java/io/intercom/api/RateLimitDetails.java @@ -0,0 +1,93 @@ +/* + */ +package io.intercom.api; + +import java.time.Instant; + +/** + * Class maintaining the APIs rate limit details; + * author David Esner + * created 2016 + */ +public class RateLimitDetails { + + //init default values + private static int limit = 500; + private static int remaining = 500; + private static long reset_at = 0; + + protected void updateLimit(int limit, int remaining, long reset_at) { + RateLimitDetails.remaining = remaining; + RateLimitDetails.reset_at = reset_at; + } + + /** + * Returns remaining time in seconds + * + * @return + */ + public Long getRemainingSeconds() { + long remains = 0; + if (reset_at != 0) { + remains = Instant.ofEpochSecond(reset_at).getEpochSecond() - Instant.now().getEpochSecond(); + } + return remains; + } + + /** + * Returns remaining time in miliseconds + * + * @return + */ + public long getRemainingMilis() { + long remains = 11; + if (reset_at != 0) { + remains = 1000 * (Instant.ofEpochSecond(reset_at).getEpochSecond() - Instant.now().getEpochSecond()); + } + return remains; + } + + /** + * Indicates if the limit is not exceeded yet. + * + * @return + */ + public boolean canSubmit() { + refreshIfNeeded(); + long remains = this.getRemainingMilis(); + if (RateLimitDetails.remaining > 2) { + return true; + } else { + return remains <= 0; + } + } + + /** + * Reset rate limit if needed + */ + private void refreshIfNeeded() { + if (getRemainingSeconds() <= 0) { + RateLimitDetails.remaining = limit; + } + } + + public long getReset_at() { + return reset_at; + } + + public int getLimit() { + refreshIfNeeded(); + return limit; + } + + public int getRemaining() { + return remaining; + } + + @Override + public String toString() { + refreshIfNeeded(); + return "\nlimit: " + limit + "\nremaining: " + remaining + "\nremaining milis: " + getRemainingMilis() + "\nreset at: " + reset_at; + } + +}