diff --git a/src/main/java/no/stelar7/api/l4j8/basic/cache/CacheProvider.java b/src/main/java/no/stelar7/api/l4j8/basic/cache/CacheProvider.java index b90bd3f6..99398e88 100644 --- a/src/main/java/no/stelar7/api/l4j8/basic/cache/CacheProvider.java +++ b/src/main/java/no/stelar7/api/l4j8/basic/cache/CacheProvider.java @@ -16,6 +16,15 @@ public abstract class CacheProvider */ public abstract void store(URLEndpoint type, Object obj); + + /** + * Updates the TTL for this object + * + * @param type the endpoint to store the cache in + * @param obj the object to store + */ + public abstract void update(URLEndpoint type, Object obj); + /** * Returns data from the cache if found, otherwise Optional.empty(); * @@ -41,10 +50,12 @@ public abstract class CacheProvider private ScheduledFuture clearTask; protected long timeToLive; - public long getTimeToLive() - { - return timeToLive; - } + /** + * Returns the time in seconds the items are alloweed to live in the cache + * + * @return long + */ + public abstract long getTimeToLive(); /** * Returns the count of items in the cache @@ -85,7 +96,11 @@ private EmptyProvider() } @Override - public void store(URLEndpoint clazz, Object obj) { /*void cache*/} + public void store(URLEndpoint clazz, Object obj) {/*void cache*/} + + @Override + public void update(URLEndpoint type, Object obj) + {/*void cache*/} @Override public Optional get(URLEndpoint type, Object... data) @@ -95,12 +110,18 @@ public Optional get(URLEndpoint type, Object... data) @Override public void clear(URLEndpoint type) - {/*void*/} + {/*void cache*/} @Override public void clearOldCache() - {/*void*/} - + {/*void cache*/} + + @Override + public long getTimeToLive() + { + return 0; + } + @Override public long getSize() { diff --git a/src/main/java/no/stelar7/api/l4j8/basic/cache/MemoryCacheProvider.java b/src/main/java/no/stelar7/api/l4j8/basic/cache/MemoryCacheProvider.java index 0c7c4630..3534ecd0 100644 --- a/src/main/java/no/stelar7/api/l4j8/basic/cache/MemoryCacheProvider.java +++ b/src/main/java/no/stelar7/api/l4j8/basic/cache/MemoryCacheProvider.java @@ -41,6 +41,13 @@ public void store(URLEndpoint type, Object obj) } } + + @Override + public void update(URLEndpoint type, Object obj) + { + store(type, obj); + } + @Override public Optional get(URLEndpoint type, Object... data) { @@ -86,6 +93,12 @@ public void clearOldCache() clearOldCache(matches); } + @Override + public long getTimeToLive() + { + return timeToLive; + } + @Override public long getSize() { diff --git a/src/main/java/no/stelar7/api/l4j8/basic/cache/TieredCacheProvider.java b/src/main/java/no/stelar7/api/l4j8/basic/cache/TieredCacheProvider.java index 41981287..d645eff6 100644 --- a/src/main/java/no/stelar7/api/l4j8/basic/cache/TieredCacheProvider.java +++ b/src/main/java/no/stelar7/api/l4j8/basic/cache/TieredCacheProvider.java @@ -6,7 +6,7 @@ public class TieredCacheProvider extends CacheProvider { - List providers = new LinkedList<>(); + private final List providers = new LinkedList<>(); public TieredCacheProvider(CacheProvider... provs) { @@ -15,9 +15,15 @@ public TieredCacheProvider(CacheProvider... provs) @Override - public void store(URLEndpoint clazz, Object obj) + public void store(URLEndpoint type, Object obj) { - providers.forEach(p -> p.store(clazz, obj)); + providers.forEach(p -> p.store(type, obj)); + } + + @Override + public void update(URLEndpoint type, Object obj) + { + providers.forEach(p -> p.update(type, obj)); } @Override @@ -40,14 +46,24 @@ public Optional get(URLEndpoint type, Object... data) private void restoreCache(CacheProvider stoppingPoint, URLEndpoint type, Object obj) { + + boolean inTheFuture = false; + for (CacheProvider provider : providers) { if (provider.equals(stoppingPoint)) { - return; + inTheFuture = true; } - provider.store(type, obj); + + if (!inTheFuture) + { + provider.store(type, obj); + } else + { + provider.update(type, obj); + } } } @@ -63,6 +79,12 @@ public void clearOldCache() providers.forEach(CacheProvider::clearOldCache); } + @Override + public long getTimeToLive() + { + return providers.stream().mapToLong(CacheProvider::getTimeToLive).sum(); + } + @Override public long getSize() { diff --git a/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCall.java b/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCall.java index 0ab9252d..18509bb6 100644 --- a/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCall.java +++ b/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCall.java @@ -15,16 +15,17 @@ public final class DataCall private static final Map> limiter = new HashMap<>(); private static final Map>> callData = new HashMap<>(); + private static APICredentials creds; + private static CacheProvider cache = CacheProvider.EmptyProvider.INSTANCE; + private static LogLevel logLevel = LogLevel.NONE; + private final Map urlParams = new TreeMap<>(); private final Map urlData = new TreeMap<>(); private final Map urlHeaders = new TreeMap<>(); private Platform platform; private URLEndpoint endpoint; - - private static APICredentials creds; - private static CacheProvider cache = CacheProvider.EmptyProvider.INSTANCE; - private static LogLevel logLevel = LogLevel.NONE; + private static String urlProxy = Constants.REQUEST_URL; public static Map> getLimiter() @@ -98,6 +99,24 @@ public static CacheProvider getCacheProvider() return cache; } + /** + * Takes in a proxy for the api. + * The URL should contain the parts: + * {platform} + * {game} + * {service} + * {version} + * {resource} + *

+ * The default is https://{platform}.api.riotgames.com/{game}/{service}/{version}/{resource} + * + * @param proxy the url + */ + public static void setProxy(@Nullable String proxy) + { + urlProxy = proxy == null ? Constants.REQUEST_URL : proxy; + } + public static void setCacheProvider(@Nullable CacheProvider provider) { cache = provider == null ? CacheProvider.EmptyProvider.INSTANCE : provider; @@ -108,4 +127,8 @@ public static void setCredentials(final APICredentials creds) DataCall.creds = creds; } + public String getProxy() + { + return urlProxy; + } } diff --git a/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCallBuilder.java b/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCallBuilder.java index 7eb47a8c..19900803 100644 --- a/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCallBuilder.java +++ b/src/main/java/no/stelar7/api/l4j8/basic/calling/DataCallBuilder.java @@ -22,7 +22,6 @@ public class DataCallBuilder private static final BiFunction MERGE = (o, n) -> o + "," + n; private static final BiFunction MERGE_AS_SET = (o, n) -> o + n; - private String BASE_URL = Constants.REQUEST_URL; private String requestMethod = "GET"; private String postData = ""; @@ -64,30 +63,30 @@ public Object build(int... retrys) System.err.println(response); } - switch (response.getResponseCode()) + try { - case 200: - case 204: + switch (response.getResponseCode()) { - final Object returnType = this.dc.getEndpoint().getType(); - Object dtoobj = Utils.getGson().fromJson(response.getResponseData(), (returnType instanceof Class) ? (Class) returnType : (Type) returnType); + case 200: + case 204: + { + final Object returnType = this.dc.getEndpoint().getType(); + Object dtoobj = Utils.getGson().fromJson(response.getResponseData(), (returnType instanceof Class) ? (Class) returnType : (Type) returnType); + + return process(dtoobj); + } - return process(dtoobj); - } - - case 403: - { - throw new APIResponseException(APIHTTPErrorReason.ERROR_403, "Your Api key is invalid! If you just regenerated it, wait a few seconds, then try again. " + response.getResponseData()); - } - - case 404: - { - throw new APIResponseException(APIHTTPErrorReason.ERROR_400, "L4J8 error.. contact developer to get this fixed ..." + response.getResponseData()); - } - - case 429: - try + case 403: + { + throw new APIResponseException(APIHTTPErrorReason.ERROR_403, "Your Api key is invalid! If you just regenerated it, wait a few seconds, then try again. " + response.getResponseData()); + } + + case 404: { + return null; + } + + case 429: if (response.getResponseData().startsWith(RateLimitType.LIMIT_UNDERLYING.getReason()) || response.getResponseData().startsWith(RateLimitType.LIMIT_SERVICE.getReason())) { int attempts = (retrys != null && retrys.length == 1) ? ++retrys[0] : 1; @@ -109,30 +108,33 @@ public Object build(int... retrys) } return this.build(); - } catch (InterruptedException e) + + case 500: + case 502: + case 503: + case 504: { - e.printStackTrace(); - break; + int attempts = (retrys != null && retrys.length == 1) ? ++retrys[0] : 1; + System.err.format("Server error, waiting 1 second and retrying%n"); + Thread.sleep(1000); + + if (attempts > 3) + { + throw new APIResponseException(APIHTTPErrorReason.ERROR_500, response.getResponseData()); + } + + return this.build(attempts); } - - case 500: - case 502: - case 503: - case 504: - { - int attempts = (retrys != null && retrys.length == 1) ? ++retrys[0] : 1; - if (attempts > 3) + + default: { - throw new APIResponseException(APIHTTPErrorReason.ERROR_500, response.getResponseData()); + break; } - - return this.build(attempts); } - default: - { - break; - } + } catch (InterruptedException e) + { + e.printStackTrace(); } System.err.println("Response Code:" + response.getResponseCode()); @@ -268,7 +270,6 @@ private DataCallResponse getResponse(final String url) if (limitType == RateLimitType.LIMIT_METHOD) { - // TODO RateLimiter limter = DataCall.getLimiter().get(this.dc.getPlatform()).get(this.dc.getEndpoint()); limter.updateSleep(con.getHeaderField("Retry-After")); limter.resetCalls(); @@ -328,15 +329,6 @@ private void saveHeaderRateLimit(String limitCount, Enum platform, Enum endpoint DataCall.getCallData().put(platform, parent); updateRatelimiter(platform, endpoint); - - /* - private void saveHeaderRateLimit(String limitCount, Enum type) - { - Map timeout = parseLimitFromHeader(limitCount); - DataCall.getCallData().put(type, timeout); - updateRatelimiter(type); - } - */ } private Map parseLimitFromHeader(String headerValue) @@ -382,7 +374,7 @@ public RateLimiter createLimiter(Enum key, String limitCount) */ private String getURL() { - String[] url = {BASE_URL}; + String[] url = {dc.getProxy()}; url[0] = url[0].replace(Constants.PLATFORM_PLACEHOLDER, dc.getPlatform().toString()); url[0] = url[0].replace(Constants.GAME_PLACEHOLDER, dc.getEndpoint().getGame()); url[0] = url[0].replace(Constants.SERVICE_PLACEHOLDER, dc.getEndpoint().getService()); @@ -511,7 +503,7 @@ public DataCallBuilder withURLParameter(final String key, final String value) public DataCallBuilder withURL(String url) { - this.BASE_URL = url; + dc.setProxy(url); return this; } diff --git a/src/main/java/no/stelar7/api/l4j8/impl/SpectatorAPI.java b/src/main/java/no/stelar7/api/l4j8/impl/SpectatorAPI.java index 94c4823f..4b8978ef 100644 --- a/src/main/java/no/stelar7/api/l4j8/impl/SpectatorAPI.java +++ b/src/main/java/no/stelar7/api/l4j8/impl/SpectatorAPI.java @@ -48,10 +48,12 @@ public List getFeaturedGames(Platform server) /** * The response object contains the CurrentGame of the summoner. + *

+ * returns null if not in game * * @param server the region to execute against * @param summonerId the summonerId - * @return Optional FeaturedGames + * @return SpectatorGameInfo */ public SpectatorGameInfo getCurrentGame(Platform server, long summonerId) { diff --git a/src/test/java/no/stelar7/api/l4j8/tests/cache/CacheTest.java b/src/test/java/no/stelar7/api/l4j8/tests/cache/CacheTest.java index 91a8645b..9504ba38 100644 --- a/src/test/java/no/stelar7/api/l4j8/tests/cache/CacheTest.java +++ b/src/test/java/no/stelar7/api/l4j8/tests/cache/CacheTest.java @@ -27,6 +27,13 @@ public void testMemoryCache() throws InterruptedException doCacheStuff(); } + @Test + public void testTieredMemoryCache() throws InterruptedException + { + DataCall.setCacheProvider(new TieredCacheProvider(new MemoryCacheProvider(5), new MemoryCacheProvider(20))); + doCacheStuff(); + } + @After public void clearCacheProvider() { @@ -43,18 +50,18 @@ private void doCacheStuff() throws InterruptedException long start = stopwatch.runtime(TimeUnit.MICROSECONDS); ref.getFullMatch(); - System.out.println("1x url fetch time: " + (stopwatch.runtime(TimeUnit.MICROSECONDS) - start) + "µs"); + System.out.printf("1x url fetch time: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); start = stopwatch.runtime(TimeUnit.MICROSECONDS); ref.getFullMatch(); - System.out.println("1x memory fetch time: " + (stopwatch.runtime(TimeUnit.MICROSECONDS) - start) + "µs"); + System.out.printf("1x memory fetch time: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); start = stopwatch.runtime(TimeUnit.MICROSECONDS); for (int i = 0; i < 10; i++) { ref.getFullMatch(); } - System.out.println("10x memory fetch time: " + (stopwatch.runtime(TimeUnit.MICROSECONDS) - start) + "µs"); + System.out.printf("10x memory fetch time: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); System.out.println(); System.out.println("clearing cache"); @@ -63,14 +70,14 @@ private void doCacheStuff() throws InterruptedException start = stopwatch.runtime(TimeUnit.MICROSECONDS); ref.getFullMatch(); - System.out.println("1x url fetch time: " + (stopwatch.runtime(TimeUnit.MICROSECONDS) - start) + "µs"); + System.out.printf("1x url fetch time: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); start = stopwatch.runtime(TimeUnit.MICROSECONDS); for (int i = 0; i < 10; i++) { ref.getFullMatch(); } - System.out.println("10x memory fetch time: " + (stopwatch.runtime(TimeUnit.MICROSECONDS) - start) + "µs"); + System.out.printf("10x memory fetch time: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); System.out.println(); System.out.println("Fetching 3 aditional matches"); @@ -78,20 +85,22 @@ private void doCacheStuff() throws InterruptedException recents.get(2).getFullMatch(); recents.get(3).getFullMatch(); - System.out.println("Cache size: " + DataCall.getCacheProvider().getSize()); + System.out.printf("Cache size: %d%n", DataCall.getCacheProvider().getSize()); System.out.println("Waiting for cache timeout"); - TimeUnit.SECONDS.sleep(DataCall.getCacheProvider().getTimeToLive() - stopwatch.runtime(TimeUnit.SECONDS)); + TimeUnit.SECONDS.sleep(5); - System.out.println("Cache size: " + DataCall.getCacheProvider().getSize()); + System.out.printf("Cache size: %d%n", DataCall.getCacheProvider().getSize()); System.out.println("Re-fetching cached items"); + start = stopwatch.runtime(TimeUnit.MICROSECONDS); recents.get(0).getFullMatch(); recents.get(1).getFullMatch(); recents.get(2).getFullMatch(); recents.get(3).getFullMatch(); + System.out.printf("4x fetches took: %dµs%n", stopwatch.runtime(TimeUnit.MICROSECONDS) - start); - System.out.println("Cache size: " + DataCall.getCacheProvider().getSize()); + System.out.printf("Cache size: %d%n", DataCall.getCacheProvider().getSize()); System.out.println(); } diff --git a/src/test/java/no/stelar7/api/l4j8/tests/spectator/CurrentGameTest.java b/src/test/java/no/stelar7/api/l4j8/tests/spectator/CurrentGameTest.java index f60e572c..c64db1a3 100644 --- a/src/test/java/no/stelar7/api/l4j8/tests/spectator/CurrentGameTest.java +++ b/src/test/java/no/stelar7/api/l4j8/tests/spectator/CurrentGameTest.java @@ -1,6 +1,6 @@ package no.stelar7.api.l4j8.tests.spectator; -import no.stelar7.api.l4j8.basic.constants.api.Platform; +import no.stelar7.api.l4j8.basic.constants.api.*; import no.stelar7.api.l4j8.impl.*; import no.stelar7.api.l4j8.pojo.spectator.SpectatorGameInfo; import no.stelar7.api.l4j8.pojo.summoner.Summoner; @@ -17,8 +17,6 @@ public class CurrentGameTest { Assert.assertNotNull("bannedchampion is null", currentGame.getBannedChampions()); - Assert.assertNotNull("gameid is null", currentGame.getGameId()); - Assert.assertNotNull("gamelength is null", currentGame.getGameLength()); Assert.assertNotNull("gamemode is null", currentGame.getGameMode()); Assert.assertNotNull("gamequeuecongifid is null", currentGame.getGameQueueConfig()); Assert.assertNotNull("gamestarttime is null", currentGame.getGameStartTimeAsDate()); @@ -34,7 +32,7 @@ public void testCurrentGame() { final L4J8 l4j8 = new L4J8(SecretFile.CREDS); SpectatorAPI api = l4j8.getSpectatorAPI(); - + // Get a game in progess final List game = api.getFeaturedGames(Platform.EUW1); @@ -46,4 +44,15 @@ public void testCurrentGame() final SpectatorGameInfo currentGame = api.getCurrentGame(Platform.EUW1, sum.getSummonerId()); doAssertions.accept(currentGame); } + + @Test + public void testCurrentlyNotInGame() + { + final L4J8 l4j8 = new L4J8(SecretFile.CREDS); + SpectatorAPI api = l4j8.getSpectatorAPI(); + + SpectatorGameInfo game = api.getCurrentGame(Constants.TEST_PLATFORM[0], Constants.TEST_SUMMONER_IDS[0]); + + System.out.format("%s is %sin game", Constants.TEST_SUMMONER_NAMES[0], game != null ? "" : "not "); + } }