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>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@@ -24,51 +24,28 @@
*/
package net.runelite.http.api.hiscore;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import lombok.extern.slf4j.Slf4j;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
@Slf4j
public class HiscoreClient
{
private static final Logger logger = LoggerFactory.getLogger(HiscoreClient.class);
public HiscoreResult lookup(String username, HiscoreEndpoint endpoint) throws IOException
{
HttpUrl.Builder builder = RuneLiteAPI.getApiBase().newBuilder()
.addPathSegment("hiscore")
.addPathSegment(endpoint.name().toLowerCase())
.addQueryParameter("username", username);
return lookup(username, endpoint.getHiscoreURL());
}
HttpUrl url = builder.build();
logger.debug("Built URI: {}", url);
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, HttpUrl endpoint) throws IOException
{
HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint);
return resultBuilder.build();
}
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
{
HttpUrl.Builder builder = RuneLiteAPI.getApiBase().newBuilder()
.addPathSegment("hiscore")
.addPathSegment(endpoint.name())
.addPathSegment(skill.toString().toLowerCase())
.addQueryParameter("username", username);
HiscoreResultBuilder resultBuilder = lookupUsername(username, endpoint.getHiscoreURL());
HiscoreResult result = resultBuilder.build();
HttpUrl url = builder.build();
logger.debug("Built URI: {}", url);
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), SingleHiscoreSkillResult.class);
}
catch (JsonParseException ex)
{
throw new IOException(ex);
}
Skill requested = result.getSkill(skill);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
skillResult.setPlayer(username);
skillResult.setSkillName(skill.getName());
skillResult.setSkill(requested);
return skillResult;
}
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill) throws IOException
{
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
* 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.List;

View File

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

View File

@@ -53,8 +53,7 @@ public class HiscoreController
@RequestMapping("/{endpoint}")
public HiscoreResult lookup(@PathVariable HiscoreEndpoint endpoint, @RequestParam String username) throws ExecutionException
{
HiscoreResultBuilder resultBuilder = hiscoreService.lookupUsername(username, endpoint);
HiscoreResult result = resultBuilder.build();
HiscoreResult result = hiscoreService.lookupUsername(username, endpoint);
// Submit to xp tracker?
switch (endpoint)
@@ -75,10 +74,10 @@ public class HiscoreController
HiscoreSkill skill = HiscoreSkill.valueOf(skillName.toUpperCase());
// 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
Skill requested = result.getSkill(skill.ordinal());
Skill requested = result.getSkill(skill);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
skillResult.setPlayer(username);

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.http.service.hiscore;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@@ -31,104 +32,38 @@ import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
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.HiscoreSkill;
import net.runelite.http.api.hiscore.Skill;
import net.runelite.http.service.util.exception.InternalServerErrorException;
import net.runelite.http.service.util.exception.NotFoundException;
import net.runelite.http.api.hiscore.HiscoreResult;
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;
@Service
@Slf4j
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)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(
new CacheLoader<HiscoreKey, HiscoreResultBuilder>()
new CacheLoader<HiscoreKey, HiscoreResult>()
{
@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));
}
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.HiscoreResult;
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.xp.beans.PlayerEntity;
import net.runelite.http.service.xp.beans.XpEntity;
@@ -53,8 +52,7 @@ public class XpTrackerService
public void update(String username) throws ExecutionException
{
HiscoreResultBuilder hiscoreResultBuilder = hiscoreService.lookupUsername(username, HiscoreEndpoint.NORMAL);
HiscoreResult hiscoreResult = hiscoreResultBuilder.build();
HiscoreResult hiscoreResult = hiscoreService.lookupUsername(username, HiscoreEndpoint.NORMAL);
update(username, hiscoreResult);
}

View File

@@ -91,7 +91,7 @@ public class HiscoreServiceTest
{
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(159727L, result.getFishing().getExperience());

View File

@@ -27,7 +27,7 @@ package net.runelite.http.service.hiscore;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreResult;
import okhttp3.HttpUrl;
class HiscoreTestService extends HiscoreService
@@ -40,15 +40,8 @@ class HiscoreTestService extends HiscoreService
}
@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);
}
catch (IOException e)
{
throw new ExecutionException(e);
}
return super.lookupUsername(username, testUrl);
}
}