Make HiscoreClient call the OSRS hiscore API directly

This commit is contained in:
Tomas Slusny
2018-09-14 21:31:50 +02:00
committed by Adam
parent db70df613e
commit 89b8bc52ca
9 changed files with 111 additions and 166 deletions

View File

@@ -53,6 +53,11 @@
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.4</version>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>

View File

@@ -24,51 +24,28 @@
*/ */
package net.runelite.http.api.hiscore; package net.runelite.http.api.hiscore;
import com.google.gson.JsonParseException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import lombok.extern.slf4j.Slf4j;
import java.io.InputStreamReader;
import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.RuneLiteAPI;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import org.slf4j.Logger; import org.apache.commons.csv.CSVFormat;
import org.slf4j.LoggerFactory; import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
@Slf4j
public class HiscoreClient public class HiscoreClient
{ {
private static final Logger logger = LoggerFactory.getLogger(HiscoreClient.class);
public HiscoreResult lookup(String username, HiscoreEndpoint endpoint) throws IOException public HiscoreResult lookup(String username, HiscoreEndpoint endpoint) throws IOException
{ {
HttpUrl.Builder builder = RuneLiteAPI.getApiBase().newBuilder() return lookup(username, endpoint.getHiscoreURL());
.addPathSegment("hiscore") }
.addPathSegment(endpoint.name().toLowerCase())
.addQueryParameter("username", username);
HttpUrl url = builder.build(); public HiscoreResult lookup(String username, HttpUrl endpoint) throws IOException
{
logger.debug("Built URI: {}", url); HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint);
return resultBuilder.build();
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{
if (!response.isSuccessful())
{
logger.debug("unsuccessful lookup for {}", username);
return null;
}
InputStream in = response.body().byteStream();
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), HiscoreResult.class);
}
catch (JsonParseException ex)
{
throw new IOException(ex);
}
} }
public HiscoreResult lookup(String username) throws IOException public HiscoreResult lookup(String username) throws IOException
@@ -78,39 +55,82 @@ public class HiscoreClient
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill, HiscoreEndpoint endpoint) throws IOException public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill, HiscoreEndpoint endpoint) throws IOException
{ {
HttpUrl.Builder builder = RuneLiteAPI.getApiBase().newBuilder() HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint.getHiscoreURL());
.addPathSegment("hiscore") HiscoreResult result = resultBuilder.build();
.addPathSegment(endpoint.name())
.addPathSegment(skill.toString().toLowerCase())
.addQueryParameter("username", username);
HttpUrl url = builder.build(); Skill requested = result.getSkill(skill);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
logger.debug("Built URI: {}", url); skillResult.setPlayer(username);
skillResult.setSkillName(skill.getName());
Request request = new Request.Builder() skillResult.setSkill(requested);
.url(url) return skillResult;
.build();
try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{
if (!response.isSuccessful())
{
logger.debug("unsuccessful lookup for {}", username);
return null;
}
InputStream in = response.body().byteStream();
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), SingleHiscoreSkillResult.class);
}
catch (JsonParseException ex)
{
throw new IOException(ex);
}
} }
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill) throws IOException public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill) throws IOException
{ {
return lookup(username, skill, HiscoreEndpoint.NORMAL); return lookup(username, skill, HiscoreEndpoint.NORMAL);
} }
private HiscoreResultBuilder lookupUsername(String username, HttpUrl hiscoreUrl) throws IOException
{
HttpUrl url = hiscoreUrl.newBuilder()
.addQueryParameter("player", username)
.build();
log.debug("Built URL {}", url);
Request okrequest = new Request.Builder()
.url(url)
.build();
String responseStr;
try (Response okresponse = RuneLiteAPI.CLIENT.newCall(okrequest).execute())
{
if (!okresponse.isSuccessful())
{
switch (okresponse.code())
{
case 404:
throw new IllegalArgumentException();
default:
throw new IOException("Error retrieving data from Jagex Hiscores: " + okresponse.message());
}
}
responseStr = okresponse.body().string();
}
CSVParser parser = CSVParser.parse(responseStr, CSVFormat.DEFAULT);
HiscoreResultBuilder hiscoreBuilder = new HiscoreResultBuilder();
hiscoreBuilder.setPlayer(username);
int count = 0;
for (CSVRecord record : parser.getRecords())
{
if (count++ >= HiscoreSkill.values().length)
{
log.warn("Jagex Hiscore API returned unexpected data");
break; // rest is other things?
}
// rank, level, experience
int rank = Integer.parseInt(record.get(0));
int level = Integer.parseInt(record.get(1));
// items that are not skills do not have an experience parameter
long experience = -1;
if (record.size() == 3)
{
experience = Long.parseLong(record.get(2));
}
Skill skill = new Skill(rank, level, experience);
hiscoreBuilder.setNextSkill(skill);
}
return hiscoreBuilder;
}
} }

View File

@@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.http.service.hiscore; package net.runelite.http.api.hiscore;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -83,11 +83,6 @@
<artifactId>sql2o</artifactId> <artifactId>sql2o</artifactId>
<version>1.5.4</version> <version>1.5.4</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.4</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>

View File

@@ -53,8 +53,7 @@ public class HiscoreController
@RequestMapping("/{endpoint}") @RequestMapping("/{endpoint}")
public HiscoreResult lookup(@PathVariable HiscoreEndpoint endpoint, @RequestParam String username) throws ExecutionException public HiscoreResult lookup(@PathVariable HiscoreEndpoint endpoint, @RequestParam String username) throws ExecutionException
{ {
HiscoreResultBuilder resultBuilder = hiscoreService.lookupUsername(username, endpoint); HiscoreResult result = hiscoreService.lookupUsername(username, endpoint);
HiscoreResult result = resultBuilder.build();
// Submit to xp tracker? // Submit to xp tracker?
switch (endpoint) switch (endpoint)
@@ -75,10 +74,10 @@ public class HiscoreController
HiscoreSkill skill = HiscoreSkill.valueOf(skillName.toUpperCase()); HiscoreSkill skill = HiscoreSkill.valueOf(skillName.toUpperCase());
// RS api only supports looking up all stats // RS api only supports looking up all stats
HiscoreResultBuilder result = hiscoreService.lookupUsername(username, endpoint); HiscoreResult result = hiscoreService.lookupUsername(username, endpoint);
// Find the skill to return // Find the skill to return
Skill requested = result.getSkill(skill.ordinal()); Skill requested = result.getSkill(skill);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult(); SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
skillResult.setPlayer(username); skillResult.setPlayer(username);

View File

@@ -24,6 +24,7 @@
*/ */
package net.runelite.http.service.hiscore; package net.runelite.http.service.hiscore;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
@@ -31,104 +32,38 @@ import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreSkill; import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.hiscore.Skill;
import net.runelite.http.service.util.exception.InternalServerErrorException;
import net.runelite.http.service.util.exception.NotFoundException;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@Slf4j @Slf4j
public class HiscoreService public class HiscoreService
{ {
private final LoadingCache<HiscoreKey, HiscoreResultBuilder> hiscoreCache = CacheBuilder.newBuilder() private final HiscoreClient hiscoreClient = new HiscoreClient();
private final LoadingCache<HiscoreKey, HiscoreResult> hiscoreCache = CacheBuilder.newBuilder()
.maximumSize(128) .maximumSize(128)
.expireAfterWrite(1, TimeUnit.MINUTES) .expireAfterWrite(1, TimeUnit.MINUTES)
.build( .build(
new CacheLoader<HiscoreKey, HiscoreResultBuilder>() new CacheLoader<HiscoreKey, HiscoreResult>()
{ {
@Override @Override
public HiscoreResultBuilder load(HiscoreKey key) throws IOException public HiscoreResult load(HiscoreKey key) throws IOException
{ {
return lookupUsername(key.getUsername(), key.getEndpoint().getHiscoreURL()); return hiscoreClient.lookup(key.getUsername(), key.getEndpoint());
} }
}); });
public HiscoreResultBuilder lookupUsername(String username, HiscoreEndpoint endpoint) throws ExecutionException @VisibleForTesting
HiscoreResult lookupUsername(String username, HttpUrl httpUrl) throws IOException
{
return hiscoreClient.lookup(username, httpUrl);
}
public HiscoreResult lookupUsername(String username, HiscoreEndpoint endpoint) throws ExecutionException
{ {
return hiscoreCache.get(new HiscoreKey(username, endpoint)); return hiscoreCache.get(new HiscoreKey(username, endpoint));
} }
HiscoreResultBuilder lookupUsername(String username, HttpUrl hiscoreUrl) throws IOException
{
HttpUrl url = hiscoreUrl.newBuilder()
.addQueryParameter("player", username)
.build();
log.debug("Built URL {}", url);
Request okrequest = new Request.Builder()
.url(url)
.build();
String responseStr;
try (Response okresponse = RuneLiteAPI.CLIENT.newCall(okrequest).execute())
{
if (!okresponse.isSuccessful())
{
switch (HttpStatus.valueOf(okresponse.code()))
{
case NOT_FOUND:
throw new NotFoundException();
default:
throw new InternalServerErrorException("Error retrieving data from Jagex Hiscores: " + okresponse.message());
}
}
responseStr = okresponse.body().string();
}
CSVParser parser = CSVParser.parse(responseStr, CSVFormat.DEFAULT);
HiscoreResultBuilder hiscoreBuilder = new HiscoreResultBuilder();
hiscoreBuilder.setPlayer(username);
int count = 0;
for (CSVRecord record : parser.getRecords())
{
if (count++ >= HiscoreSkill.values().length)
{
log.warn("Jagex Hiscore API returned unexpected data");
break; // rest is other things?
}
// rank, level, experience
int rank = Integer.parseInt(record.get(0));
int level = Integer.parseInt(record.get(1));
// items that are not skills do not have an experience parameter
long experience = -1;
if (record.size() == 3)
{
experience = Long.parseLong(record.get(2));
}
Skill skill = new Skill(rank, level, experience);
hiscoreBuilder.setNextSkill(skill);
}
return hiscoreBuilder;
}
} }

View File

@@ -30,7 +30,6 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreResult; import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.xp.XpData; import net.runelite.http.api.xp.XpData;
import net.runelite.http.service.hiscore.HiscoreResultBuilder;
import net.runelite.http.service.hiscore.HiscoreService; import net.runelite.http.service.hiscore.HiscoreService;
import net.runelite.http.service.xp.beans.PlayerEntity; import net.runelite.http.service.xp.beans.PlayerEntity;
import net.runelite.http.service.xp.beans.XpEntity; import net.runelite.http.service.xp.beans.XpEntity;
@@ -53,8 +52,7 @@ public class XpTrackerService
public void update(String username) throws ExecutionException public void update(String username) throws ExecutionException
{ {
HiscoreResultBuilder hiscoreResultBuilder = hiscoreService.lookupUsername(username, HiscoreEndpoint.NORMAL); HiscoreResult hiscoreResult = hiscoreService.lookupUsername(username, HiscoreEndpoint.NORMAL);
HiscoreResult hiscoreResult = hiscoreResultBuilder.build();
update(username, hiscoreResult); update(username, hiscoreResult);
} }

View File

@@ -91,7 +91,7 @@ public class HiscoreServiceTest
{ {
HiscoreTestService hiscores = new HiscoreTestService(server.url("/")); HiscoreTestService hiscores = new HiscoreTestService(server.url("/"));
HiscoreResult result = hiscores.lookupUsername("zezima", HiscoreEndpoint.NORMAL).build(); HiscoreResult result = hiscores.lookupUsername("zezima", HiscoreEndpoint.NORMAL.getHiscoreURL());
Assert.assertEquals(50, result.getAttack().getLevel()); Assert.assertEquals(50, result.getAttack().getLevel());
Assert.assertEquals(159727L, result.getFishing().getExperience()); Assert.assertEquals(159727L, result.getFishing().getExperience());

View File

@@ -27,7 +27,7 @@ package net.runelite.http.service.hiscore;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreResult;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
class HiscoreTestService extends HiscoreService class HiscoreTestService extends HiscoreService
@@ -40,15 +40,8 @@ class HiscoreTestService extends HiscoreService
} }
@Override @Override
public HiscoreResultBuilder lookupUsername(String username, HiscoreEndpoint endpoint) throws ExecutionException public HiscoreResult lookupUsername(String username, HttpUrl endpoint) throws IOException
{ {
try return super.lookupUsername(username, testUrl);
{
return super.lookupUsername(username, testUrl);
}
catch (IOException e)
{
throw new ExecutionException(e);
}
} }
} }