http-service: switch to spring-web from sparkjava/guice

This commit is contained in:
Adam
2017-08-10 17:56:03 -04:00
parent a81935849d
commit b6a7108ca5
18 changed files with 339 additions and 801 deletions

View File

@@ -36,60 +36,39 @@
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
<jetty.version>9.3.6.v20151106</jetty.version> <!-- from Spark --> <spring.boot.version>1.5.6.RELEASE</spring.boot.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>net.runelite</groupId> <groupId>net.runelite</groupId>
<artifactId>http-api</artifactId> <artifactId>http-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.5.5</version>
<exclusions>
<!-- Spark includes Jetty, even if you are using
another servlet container, so we exclude it -->
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-servlet</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>org.sql2o</groupId> <groupId>org.sql2o</groupId>
<artifactId>sql2o</artifactId> <artifactId>sql2o</artifactId>
<version>1.5.4</version> <version>1.5.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId> <artifactId>commons-csv</artifactId>
@@ -100,30 +79,23 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>21.0</version> <version>21.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.1.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>1.7.12</version> <version>1.7.12</version>
</dependency> </dependency>
<dependency>
<groupId>com.commongroundpublishing</groupId>
<artifactId>slf4j-servletcontext</artifactId>
<version>1.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency> <dependency>
<groupId>com.github.scribejava</groupId> <groupId>com.github.scribejava</groupId>
<artifactId>scribejava-apis</artifactId> <artifactId>scribejava-apis</artifactId>
<version>4.1.0</version> <version>4.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
@@ -136,43 +108,10 @@
<version>1.10.19</version> <version>1.10.19</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Spark tests use Jetty though, so include it here -->
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>mysql</groupId>
<artifactId>jetty-server</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>${jetty.version}</version> <version>5.1.43</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-servlet</artifactId>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-testlib</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -187,6 +126,11 @@
<finalName>runelite-${project.version}</finalName> <finalName>runelite-${project.version}</finalName>
<plugins> <plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin> <plugin>
<groupId>org.apache.tomcat.maven</groupId> <groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId> <artifactId>tomcat7-maven-plugin</artifactId>

View File

@@ -1,155 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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;
import com.google.inject.Guice;
import com.google.inject.Inject;
import net.runelite.http.api.RuneliteAPI;
import net.runelite.http.service.account.AccountService;
import net.runelite.http.service.account.AuthFilter;
import net.runelite.http.service.config.ConfigService;
import net.runelite.http.service.examine.ExamineService;
import net.runelite.http.service.hiscore.HiscoreService;
import net.runelite.http.service.item.ItemService;
import net.runelite.http.service.updatecheck.UpdateCheckService;
import net.runelite.http.service.worlds.WorldsService;
import net.runelite.http.service.xtea.XteaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.Request;
import spark.Response;
import spark.servlet.SparkApplication;
import static spark.Spark.*;
public class Service implements SparkApplication
{
private static final Logger logger = LoggerFactory.getLogger(Service.class);
private final JsonTransformer transformer = new JsonTransformer();
@Inject
private AuthFilter authFilter;
@Inject
private AccountService accounts;
@Inject
private ConfigService config;
@Inject
private ExamineService examine;
@Inject
private HiscoreService hiscores;
@Inject
private ItemService item;
@Inject
private UpdateCheckService updateCheck;
@Inject
private WorldsService worlds;
@Inject
private XteaService xtea;
@Override
public void init()
{
Guice.createInjector(new ServiceModule(this));
setupRoutes();
}
public void setupRoutes()
{
xtea.init();
accounts.init();
config.init();
item.init();
examine.init();
get("/version", (request, response) -> RuneliteAPI.getVersion());
get("/update-check", updateCheck::check, transformer);
path("/hiscore", () ->
{
get("", hiscores::lookup, transformer);
get("/:skill", hiscores::singleSkillLookup, transformer);
});
get("/worlds", worlds::listWorlds, transformer);
post("/xtea", xtea::submit);
get("/xtea/:rev", xtea::get, transformer);
path("/account", () ->
{
get("/login", accounts::login, transformer);
get("/callback", accounts::callback);
before("/logout", authFilter);
get("/logout", accounts::logout);
before("/session-check", authFilter);
get("/session-check", accounts::sessionCheck);
});
before("/config", authFilter);
path("/config", () ->
{
// Just using before(authFilter); here doesn't work
before("/*", authFilter);
get("", config::get, transformer);
put("/:key", config::setKey);
delete("/:key", config::unsetKey);
});
path("/item", () ->
{
get("/search", item::search, transformer);
get("/:id", item::getItem, transformer);
get("/:id/icon", item::getIcon);
get("/:id/icon/large", item::getIconLarge);
get("/:id/price", item::getPrice, transformer);
get("/:id/price/:time", item::getPrice, transformer);
});
path("/examine", () ->
{
get("/npc/:id", examine::getNpc);
get("/object/:id", examine::getObject);
get("/item/:id", examine::getItem);
post("/npc/:id", examine::submitNpc);
post("/object/:id", examine::submitObject);
post("/item/:id", examine::submitItem);
});
exception(Exception.class, this::handleException);
}
private void handleException(Exception ex, Request request, Response response)
{
logger.warn("error processing request", ex);
response.status(500);
}
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import spark.globalstate.ServletFlag;
import spark.http.matching.MatcherFilter;
import spark.route.ServletRoutes;
import spark.servlet.SparkApplication;
import spark.staticfiles.StaticFilesConfiguration;
public class SparkServlet extends HttpServlet
{
private final SparkApplication service = new Service();
private final MatcherFilter matcherFilter;
public SparkServlet()
{
ServletFlag.runFromServlet();
service.init();
matcherFilter = new MatcherFilter(ServletRoutes.get(), StaticFilesConfiguration.servletInstance, true, false);
}
private void run(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
final String relativePath = req.getPathInfo();
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(req)
{
@Override
public String getPathInfo()
{
return relativePath;
}
@Override
public String getRequestURI()
{
return relativePath;
}
};
FilterChain chain = (req2, resp2) ->
{
// Called if the matcherFilter ends up not setting a body
// something might have changed changed the error from 200
if (resp.getStatus() == 200)
{
resp.setStatus(404);
}
};
matcherFilter.doFilter(requestWrapper, resp, chain);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
run(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
run(req, resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
run(req, resp);
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
run(req, resp);
}
}

View File

@@ -24,9 +24,6 @@
*/ */
package net.runelite.http.service; package net.runelite.http.service;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.name.Named;
import java.time.Instant; import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -34,99 +31,54 @@ import javax.naming.Context;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.sql.DataSource; import javax.sql.DataSource;
import net.runelite.http.service.account.AccountService; import org.springframework.boot.SpringApplication;
import net.runelite.http.service.account.AuthFilter; import org.springframework.boot.autoconfigure.SpringBootApplication;
import net.runelite.http.service.config.ConfigService; import org.springframework.boot.builder.SpringApplicationBuilder;
import net.runelite.http.service.examine.ExamineService; import org.springframework.boot.web.support.SpringBootServletInitializer;
import net.runelite.http.service.hiscore.HiscoreService; import org.springframework.context.annotation.Bean;
import net.runelite.http.service.item.ItemService;
import net.runelite.http.service.updatecheck.UpdateCheckService;
import net.runelite.http.service.worlds.WorldsService;
import net.runelite.http.service.xtea.XteaService;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import org.sql2o.converters.Converter; import org.sql2o.converters.Converter;
import org.sql2o.quirks.NoQuirks; import org.sql2o.quirks.NoQuirks;
public class ServiceModule extends AbstractModule @SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer
{ {
private final Service service;
public ServiceModule(Service service)
{
this.service = service;
}
private Context getContext() throws NamingException private Context getContext() throws NamingException
{ {
Context initCtx = new InitialContext(); Context initCtx = new InitialContext();
return (Context) initCtx.lookup("java:comp/env"); return (Context) initCtx.lookup("java:comp/env");
} }
@Provides @Bean("Runelite SQL2O")
@Named("Runelite JDBC") Sql2o sql2o() throws NamingException
DataSource provideDataSource()
{
try
{
return (DataSource) getContext().lookup("jdbc/runelite");
}
catch (NamingException ex)
{
throw new RuntimeException(ex);
}
}
@Provides
@Named("Runelite SQL2O")
Sql2o provideSql2o(@Named("Runelite JDBC") DataSource datasource)
{ {
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite");
Map<Class, Converter> converters = new HashMap<>(); Map<Class, Converter> converters = new HashMap<>();
converters.put(Instant.class, new InstantConverter()); converters.put(Instant.class, new InstantConverter());
return new Sql2o(datasource, new NoQuirks(converters)); return new Sql2o(dataSource, new NoQuirks(converters));
} }
@Provides @Bean("OAuth Client ID")
@Named("OAuth Client ID") String oauthClientId() throws NamingException
String provideOAuthClientID()
{ {
try return (String) getContext().lookup("runelite-oauth-client-id");
{
return (String) getContext().lookup("runelite-oauth-client-id");
}
catch (NamingException ex)
{
throw new RuntimeException(ex);
}
} }
@Provides @Bean("OAuth Client Secret")
@Named("OAuth Client Secret") String oauthClientSecret() throws NamingException
String provideOAuthClientSecret()
{ {
try return (String) getContext().lookup("runelite-oauth-client-secret");
{
return (String) getContext().lookup("runelite-oauth-client-secret");
}
catch (NamingException ex)
{
throw new RuntimeException(ex);
}
} }
@Override @Override
protected void configure() protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{ {
bind(Service.class).toInstance(service); return application.sources(SpringBootWebApplication.class);
}
bind(AuthFilter.class); public static void main(String[] args)
{
bind(AccountService.class); SpringApplication.run(SpringBootWebApplication.class, args);
bind(ConfigService.class);
bind(ExamineService.class);
bind(HiscoreService.class);
bind(ItemService.class);
bind(UpdateCheckService.class);
bind(WorldsService.class);
bind(XteaService.class);
} }
} }

View File

@@ -30,14 +30,15 @@ import com.github.scribejava.apis.GoogleApi20;
import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth20Service; import com.github.scribejava.core.oauth.OAuth20Service;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.RuneliteAPI; import net.runelite.http.api.RuneliteAPI;
import net.runelite.http.api.account.OAuthResponse; import net.runelite.http.api.account.OAuthResponse;
import net.runelite.http.api.ws.messages.LoginResponse; import net.runelite.http.api.ws.messages.LoginResponse;
@@ -46,12 +47,17 @@ import net.runelite.http.service.ws.WSService;
import net.runelite.http.service.ws.WSSession; import net.runelite.http.service.ws.WSSession;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import org.sql2o.Sql2oException; import org.sql2o.Sql2oException;
import spark.Request;
import spark.Response;
@RestController
@RequestMapping("/account")
public class AccountService public class AccountService
{ {
private static final Logger logger = LoggerFactory.getLogger(AccountService.class); private static final Logger logger = LoggerFactory.getLogger(AccountService.class);
@@ -86,21 +92,21 @@ public class AccountService
private final Sql2o sql2o; private final Sql2o sql2o;
private final String oauthClientId; private final String oauthClientId;
private final String oauthClientSecret; private final String oauthClientSecret;
private final AuthFilter auth;
@Inject @Autowired
public AccountService( public AccountService(
@Named("Runelite SQL2O") Sql2o sql2o, @Qualifier("Runelite SQL2O") Sql2o sql2o,
@Named("OAuth Client ID") String oauthClientId, @Qualifier("OAuth Client ID") String oauthClientId,
@Named("OAuth Client Secret") String oauthClientSecret @Qualifier("OAuth Client Secret") String oauthClientSecret,
AuthFilter auth
) )
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
this.oauthClientId = oauthClientId; this.oauthClientId = oauthClientId;
this.oauthClientSecret = oauthClientSecret; this.oauthClientSecret = oauthClientSecret;
} this.auth = auth;
public void init()
{
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery(CREATE_SESSIONS) con.createQuery(CREATE_SESSIONS)
@@ -121,7 +127,8 @@ public class AccountService
} }
} }
public OAuthResponse login(Request request, Response response) @RequestMapping("/login")
public OAuthResponse login()
{ {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
@@ -143,24 +150,25 @@ public class AccountService
lr.setOauthUrl(authorizationUrl); lr.setOauthUrl(authorizationUrl);
lr.setUid(uuid); lr.setUid(uuid);
response.type("application/json");
return lr; return lr;
} }
public Object callback(Request request, Response response) throws IOException, InterruptedException, ExecutionException @RequestMapping("/callback")
public Object callback(
HttpServletRequest request,
HttpServletResponse response,
@RequestParam String error,
@RequestParam String code,
@RequestParam State state
) throws InterruptedException, ExecutionException, IOException
{ {
String error = request.queryParams("error");
if (error != null) if (error != null)
{ {
logger.info("Error in oauth callback: {}", error); logger.info("Error in oauth callback: {}", error);
return null; return null;
} }
String authorizationCode = request.queryParams("code"); logger.info("Got authorization code {} for uuid {}", code, state.getUuid());
State state = gson.fromJson(request.queryParams("state"), State.class);
logger.info("Got authorization code {} for uuid {}", authorizationCode, state.getUuid());
OAuth20Service service = new ServiceBuilder() OAuth20Service service = new ServiceBuilder()
.apiKey(oauthClientId) .apiKey(oauthClientId)
@@ -170,13 +178,13 @@ public class AccountService
.state(gson.toJson(state)) .state(gson.toJson(state))
.build(GoogleApi20.instance()); .build(GoogleApi20.instance());
OAuth2AccessToken accessToken = service.getAccessToken(authorizationCode); OAuth2AccessToken accessToken = service.getAccessToken(code);
// Access user info // Access user info
OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO); OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO);
service.signRequest(accessToken, orequest); service.signRequest(accessToken, orequest);
com.github.scribejava.core.model.Response oresponse = service.execute(orequest); Response oresponse = service.execute(orequest);
if (oresponse.getCode() / 100 != 2) if (oresponse.getCode() / 100 != 2)
{ {
@@ -213,7 +221,7 @@ public class AccountService
logger.info("Created session for user {}", userInfo.getEmail()); logger.info("Created session for user {}", userInfo.getEmail());
} }
response.redirect(RL_REDIR); response.sendRedirect(RL_REDIR);
notifySession(state.getUuid(), userInfo.getEmail()); notifySession(state.getUuid(), userInfo.getEmail());
@@ -237,9 +245,15 @@ public class AccountService
service.send(response); service.send(response);
} }
public Object logout(Request request, Response response) @RequestMapping("/logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException
{ {
SessionEntry session = request.session().attribute("session"); SessionEntry session = auth.handle(request, response);
if (session == null)
{
return;
}
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
@@ -247,13 +261,11 @@ public class AccountService
.addParameter("uuid", session.getUuid().toString()) .addParameter("uuid", session.getUuid().toString())
.executeUpdate(); .executeUpdate();
} }
return "";
} }
public Object sessionCheck(Request request, Response response) @RequestMapping("/session-check")
public void sessionCheck(HttpServletRequest request, HttpServletResponse response) throws IOException
{ {
// Auth filter would kick this out before here auth.handle(request, response);
return "";
} }
} }

View File

@@ -24,39 +24,38 @@
*/ */
package net.runelite.http.service.account; package net.runelite.http.service.account;
import java.io.IOException;
import net.runelite.http.service.account.beans.SessionEntry; import net.runelite.http.service.account.beans.SessionEntry;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Instant; import java.time.Instant;
import java.util.UUID; import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.RuneliteAPI; import net.runelite.http.api.RuneliteAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import spark.Filter;
import spark.Request;
import spark.Response;
import spark.Session;
import static spark.Spark.halt;
public class AuthFilter implements Filter @Service
public class AuthFilter
{ {
private final Sql2o sql2o; private final Sql2o sql2o;
@Inject @Autowired
public AuthFilter(@Named("Runelite SQL2O") Sql2o sql2o) public AuthFilter(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
} }
@Override public SessionEntry handle(HttpServletRequest request, HttpServletResponse response) throws IOException
public void handle(Request request, Response response) throws Exception
{ {
String runeliteAuth = request.headers(RuneliteAPI.RUNELITE_AUTH); String runeliteAuth = request.getHeader(RuneliteAPI.RUNELITE_AUTH);
if (runeliteAuth == null) if (runeliteAuth == null)
{ {
halt(401, "Access denied"); response.sendError(401, "Access denied");
return; return null;
} }
UUID uuid = UUID.fromString(runeliteAuth); UUID uuid = UUID.fromString(runeliteAuth);
@@ -69,8 +68,8 @@ public class AuthFilter implements Filter
if (sessionEntry == null) if (sessionEntry == null)
{ {
halt(401, "Access denied"); response.sendError(401, "Access denied");
return; return null;
} }
Instant now = Instant.now(); Instant now = Instant.now();
@@ -82,8 +81,7 @@ public class AuthFilter implements Filter
sessionEntry.setLastUsed(now); sessionEntry.setLastUsed(now);
Session session = request.session(); return sessionEntry;
session.attribute("session", sessionEntry);
} }
} }

View File

@@ -24,18 +24,28 @@
*/ */
package net.runelite.http.service.config; package net.runelite.http.service.config;
import com.google.inject.Inject; import java.io.IOException;
import com.google.inject.name.Named;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.config.ConfigEntry; import net.runelite.http.api.config.ConfigEntry;
import net.runelite.http.api.config.Configuration; import net.runelite.http.api.config.Configuration;
import net.runelite.http.service.account.AuthFilter;
import net.runelite.http.service.account.beans.SessionEntry; import net.runelite.http.service.account.beans.SessionEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import org.springframework.web.bind.annotation.RestController;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import org.sql2o.Sql2oException; import org.sql2o.Sql2oException;
import spark.Request;
import spark.Response;
@RestController
@RequestMapping("/config")
public class ConfigService public class ConfigService
{ {
private static final String CREATE_CONFIG = "CREATE TABLE IF NOT EXISTS `config` (\n" private static final String CREATE_CONFIG = "CREATE TABLE IF NOT EXISTS `config` (\n"
@@ -49,15 +59,17 @@ public class ConfigService
+ " ADD CONSTRAINT `user_fk` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;"; + " ADD CONSTRAINT `user_fk` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;";
private final Sql2o sql2o; private final Sql2o sql2o;
private final AuthFilter auth;
@Inject @Autowired
public ConfigService(@Named("Runelite SQL2O") Sql2o sql2o) public ConfigService(
@Qualifier("Runelite SQL2O") Sql2o sql2o,
AuthFilter auth
)
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
} this.auth = auth;
public void init()
{
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery(CREATE_CONFIG) con.createQuery(CREATE_CONFIG)
@@ -75,9 +87,15 @@ public class ConfigService
} }
} }
public Configuration get(Request request, Response response) @RequestMapping
public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException
{ {
SessionEntry session = request.session().attribute("session"); SessionEntry session = auth.handle(request, response);
if (session == null)
{
return null;
}
List<ConfigEntry> config; List<ConfigEntry> config;
@@ -88,38 +106,54 @@ public class ConfigService
.executeAndFetch(ConfigEntry.class); .executeAndFetch(ConfigEntry.class);
} }
response.type("application/json");
return new Configuration(config); return new Configuration(config);
} }
public Object setKey(Request request, Response response) @RequestMapping(path = "/{key}", method = PUT)
public void setKey(
HttpServletRequest request,
HttpServletResponse response,
@PathVariable String key,
@RequestBody String value
) throws IOException
{ {
SessionEntry session = request.session().attribute("session"); SessionEntry session = auth.handle(request, response);
if (session == null)
{
return;
}
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery("insert into config (user, `key`, value) values (:user, :key, :value) on duplicate key update value = :value") con.createQuery("insert into config (user, `key`, value) values (:user, :key, :value) on duplicate key update value = :value")
.addParameter("user", session.getUser()) .addParameter("user", session.getUser())
.addParameter("key", request.params("key")) .addParameter("key", key)
.addParameter("value", request.body()) .addParameter("value", value)
.executeUpdate(); .executeUpdate();
} }
return "";
} }
public Object unsetKey(Request request, Response response) @RequestMapping(path = "/{key}", method = DELETE)
public void unsetKey(
HttpServletRequest request,
HttpServletResponse response,
@PathVariable String key
) throws IOException
{ {
SessionEntry session = request.session().attribute("session"); SessionEntry session = auth.handle(request, response);
if (session == null)
{
return;
}
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery("delete from config where user = :user and `key` = :key") con.createQuery("delete from config where user = :user and `key` = :key")
.addParameter("user", session.getUser()) .addParameter("user", session.getUser())
.addParameter("key", request.params("key")) .addParameter("key", key)
.executeUpdate(); .executeUpdate();
} }
return "";
} }
} }

View File

@@ -24,8 +24,6 @@
*/ */
package net.runelite.http.service.examine; package net.runelite.http.service.examine;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Instant; import java.time.Instant;
import static net.runelite.http.service.examine.ExamineType.ITEM; import static net.runelite.http.service.examine.ExamineType.ITEM;
@@ -33,11 +31,18 @@ import static net.runelite.http.service.examine.ExamineType.NPC;
import static net.runelite.http.service.examine.ExamineType.OBJECT; import static net.runelite.http.service.examine.ExamineType.OBJECT;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import org.springframework.web.bind.annotation.RestController;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import spark.Request;
import spark.Response;
@RestController
@RequestMapping("/examine")
public class ExamineService public class ExamineService
{ {
private static final Logger logger = LoggerFactory.getLogger(ExamineService.class); private static final Logger logger = LoggerFactory.getLogger(ExamineService.class);
@@ -53,14 +58,11 @@ public class ExamineService
private final Sql2o sql2o; private final Sql2o sql2o;
@Inject @Autowired
public ExamineService(@Named("Runelite SQL2O") Sql2o sql2o) public ExamineService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
}
public void init()
{
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery(CREATE_EXAMINE) con.createQuery(CREATE_EXAMINE)
@@ -68,49 +70,40 @@ public class ExamineService
} }
} }
public String getNpc(Request request, Response response) @RequestMapping("/npc/{id}")
public String getNpc(@PathVariable int id)
{ {
int id = Integer.parseInt(request.params("id"));
return get(NPC, id); return get(NPC, id);
} }
public String getObject(Request request, Response response) @RequestMapping("/object/{id}")
public String getObject(@PathVariable int id)
{ {
int id = Integer.parseInt(request.params("id"));
return get(OBJECT, id); return get(OBJECT, id);
} }
public String getItem(Request request, Response response) @RequestMapping("/item/{id}")
public String getItem(@PathVariable int id)
{ {
int id = Integer.parseInt(request.params("id"));
return get(ITEM, id); return get(ITEM, id);
} }
public Object submitNpc(Request request, Response response) @RequestMapping(path = "/npc/{id}", method = POST)
public void submitNpc(@PathVariable int id, @RequestBody String examine)
{ {
int id = Integer.parseInt(request.params("id"));
String examine = request.body();
insert(NPC, id, examine); insert(NPC, id, examine);
return "";
} }
public Object submitObject(Request request, Response response) @RequestMapping(path = "/object/{id}", method = POST)
public void submitObject(@PathVariable int id, @RequestBody String examine)
{ {
int id = Integer.parseInt(request.params("id"));
String examine = request.body();
insert(OBJECT, id, examine); insert(OBJECT, id, examine);
return "";
} }
public Object submitItem(Request request, Response response) @RequestMapping(path = "/item/{id}", method = POST)
public void submitItem(@PathVariable int id, @RequestBody String examine)
{ {
int id = Integer.parseInt(request.params("id"));
String examine = request.body();
insert(ITEM, id, examine); insert(ITEM, id, examine);
return "";
} }
private String get(ExamineType type, int id) private String get(ExamineType type, int id)

View File

@@ -31,30 +31,42 @@ import net.runelite.http.api.hiscore.SingleHiscoreSkillResult;
import net.runelite.http.api.hiscore.Skill; import net.runelite.http.api.hiscore.Skill;
import net.runelite.http.api.hiscore.HiscoreSkill; import net.runelite.http.api.hiscore.HiscoreSkill;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import spark.Request; import org.slf4j.Logger;
import spark.Response; import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hiscore")
public class HiscoreService public class HiscoreService
{ {
private static final Logger logger = LoggerFactory.getLogger(HiscoreService.class);
private static final HttpUrl RUNESCAPE_HISCORE_SERVICE = HttpUrl.parse("http://services.runescape.com/m=hiscore_oldschool/index_lite.ws"); private static final HttpUrl RUNESCAPE_HISCORE_SERVICE = HttpUrl.parse("http://services.runescape.com/m=hiscore_oldschool/index_lite.ws");
private HttpUrl url = RUNESCAPE_HISCORE_SERVICE; private HttpUrl url = RUNESCAPE_HISCORE_SERVICE;
private HiscoreResultBuilder lookup(String username) throws IOException private HiscoreResultBuilder lookupUsername(String username) throws IOException
{ {
HttpUrl hiscoreUrl = url.newBuilder() HttpUrl hiscoreUrl = url.newBuilder()
.addQueryParameter("player", username) .addQueryParameter("player", username)
.build(); .build();
okhttp3.Request okrequest = new okhttp3.Request.Builder() logger.info("Built URL {}", hiscoreUrl);
Request okrequest = new Request.Builder()
.url(hiscoreUrl) .url(hiscoreUrl)
.build(); .build();
okhttp3.Response okresponse = RuneliteAPI.CLIENT.newCall(okrequest).execute(); Response okresponse = RuneliteAPI.CLIENT.newCall(okrequest).execute();
String responseStr; String responseStr;
try (ResponseBody body = okresponse.body()) try (ResponseBody body = okresponse.body())
@@ -88,24 +100,20 @@ public class HiscoreService
return hiscoreBuilder; return hiscoreBuilder;
} }
public HiscoreResult lookup(Request request, Response response) throws IOException @RequestMapping
public HiscoreResult lookup(@RequestParam String username) throws IOException
{ {
String username = request.queryParams("username"); HiscoreResultBuilder result = lookupUsername(username);
HiscoreResultBuilder result = lookup(username);
response.type("application/json");
return result.build(); return result.build();
} }
public SingleHiscoreSkillResult singleSkillLookup(Request request, Response response) throws IOException @RequestMapping("/{skillName}")
public SingleHiscoreSkillResult singleSkillLookup(@PathVariable String skillName, @RequestParam String username) throws IOException
{ {
String username = request.queryParams("username");
String skillName = request.params("skill");
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 = lookup(username); HiscoreResultBuilder result = lookupUsername(username);
// Find the skill to return // Find the skill to return
Skill requested = result.getSkill(skill.ordinal()); Skill requested = result.getSkill(skill.ordinal());
@@ -115,7 +123,6 @@ public class HiscoreService
skillResult.setSkillName(skillName); skillResult.setSkillName(skillName);
skillResult.setSkill(requested); skillResult.setSkill(requested);
response.type("application/json");
return skillResult; return skillResult;
} }

View File

@@ -27,8 +27,6 @@ package net.runelite.http.service.item;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -38,22 +36,31 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.RuneliteAPI; import net.runelite.http.api.RuneliteAPI;
import net.runelite.http.api.item.Item; import net.runelite.http.api.item.Item;
import net.runelite.http.api.item.ItemPrice; import net.runelite.http.api.item.ItemPrice;
import net.runelite.http.api.item.ItemType; import net.runelite.http.api.item.ItemType;
import net.runelite.http.api.item.SearchResult; import net.runelite.http.api.item.SearchResult;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Query; import org.sql2o.Query;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import org.sql2o.Sql2oException; import org.sql2o.Sql2oException;
import spark.Request;
import spark.Response;
@RestController
@RequestMapping("/item")
public class ItemService public class ItemService
{ {
private static final Logger logger = LoggerFactory.getLogger(ItemService.class); private static final Logger logger = LoggerFactory.getLogger(ItemService.class);
@@ -94,14 +101,11 @@ public class ItemService
.maximumSize(1024L) .maximumSize(1024L)
.build(); .build();
@Inject @Autowired
public ItemService(@Named("Runelite SQL2O") Sql2o sql2o) public ItemService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
}
public void init()
{
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
con.createQuery(CREATE_ITEMS) con.createQuery(CREATE_ITEMS)
@@ -132,91 +136,79 @@ public class ItemService
} }
} }
public Item getItem(Request request, Response response) @RequestMapping("/{itemId}")
public Item getItem(HttpServletResponse response, @PathVariable int itemId)
{ {
int itemId = Integer.parseInt(request.params("id"));
ItemEntry item = getItem(itemId); ItemEntry item = getItem(itemId);
if (item != null) if (item != null)
{ {
response.type("application/json"); response.setHeader(RUNELITE_CACHE, "HIT");
response.header(RUNELITE_CACHE, "HIT");
return item.toItem(); return item.toItem();
} }
item = fetchItem(itemId); item = fetchItem(itemId);
if (item != null) if (item != null)
{ {
response.type("application/json"); response.setHeader(RUNELITE_CACHE, "MISS");
response.header(RUNELITE_CACHE, "MISS");
return item.toItem(); return item.toItem();
} }
return null; return null;
} }
public byte[] getIcon(Request request, Response response) @RequestMapping(path = "/{itemId}/icon", produces = "image/gif")
public byte[] getIcon(HttpServletResponse response, @PathVariable int itemId)
{ {
int itemId = Integer.parseInt(request.params("id"));
ItemEntry item = getItem(itemId); ItemEntry item = getItem(itemId);
if (item != null && item.getIcon() != null) if (item != null && item.getIcon() != null)
{ {
response.type("image/gif"); response.setHeader(RUNELITE_CACHE, "HIT");
response.header(RUNELITE_CACHE, "HIT");
return item.getIcon(); return item.getIcon();
} }
item = fetchItem(itemId); item = fetchItem(itemId);
if (item != null) if (item != null)
{ {
response.type("image/gif"); response.setHeader(RUNELITE_CACHE, "MISS");
response.header(RUNELITE_CACHE, "MISS");
return item.getIcon(); return item.getIcon();
} }
return null; return null;
} }
public byte[] getIconLarge(Request request, Response response) @RequestMapping(path = "/{itemId}/icon/large", produces = "image/gif")
public byte[] getIconLarge(HttpServletResponse response, @PathVariable int itemId)
{ {
int itemId = Integer.parseInt(request.params("id"));
ItemEntry item = getItem(itemId); ItemEntry item = getItem(itemId);
if (item != null && item.getIcon_large() != null) if (item != null && item.getIcon_large() != null)
{ {
response.type("image/gif"); response.setHeader(RUNELITE_CACHE, "HIT");
response.header(RUNELITE_CACHE, "HIT");
return item.getIcon_large(); return item.getIcon_large();
} }
item = fetchItem(itemId); item = fetchItem(itemId);
if (item != null) if (item != null)
{ {
response.type("image/gif"); response.setHeader(RUNELITE_CACHE, "MISS");
response.header(RUNELITE_CACHE, "MISS");
return item.getIcon_large(); return item.getIcon_large();
} }
return null; return null;
} }
public ItemPrice getPrice(Request request, Response response) @RequestMapping("/{itemId}/price")
public ItemPrice getPrice(
HttpServletResponse response,
@PathVariable int itemId,
@RequestParam(required = false) Instant time
)
{ {
int itemId = Integer.parseInt(request.params("id"));
String ptime = request.params("time");
Instant time = null;
Instant now = Instant.now(); Instant now = Instant.now();
boolean hit = true; boolean hit = true;
if (ptime != null) if (time != null && time.isAfter(now))
{ {
time = Instant.ofEpochMilli(Long.parseLong(ptime)); time = now;
if (time.isAfter(now))
{
time = now;
}
} }
ItemEntry item = getItem(itemId); ItemEntry item = getItem(itemId);
@@ -263,23 +255,20 @@ public class ItemService
itemPrice.setPrice(priceEntry.getPrice()); itemPrice.setPrice(priceEntry.getPrice());
itemPrice.setTime(priceEntry.getTime()); itemPrice.setTime(priceEntry.getTime());
response.type("application/json"); response.setHeader(RUNELITE_CACHE, hit ? "HIT" : "MISS");
response.header(RUNELITE_CACHE, hit ? "HIT" : "MISS");
return itemPrice; return itemPrice;
} }
public SearchResult search(Request request, Response response) @RequestMapping("/search")
public SearchResult search(HttpServletResponse response, @RequestParam String query)
{ {
String query = request.queryParams("query");
// rs api seems to require lowercase // rs api seems to require lowercase
query = query.toLowerCase(); query = query.toLowerCase();
SearchResult searchResult = cachedSearches.getIfPresent(query); SearchResult searchResult = cachedSearches.getIfPresent(query);
if (searchResult != null) if (searchResult != null)
{ {
response.type("application/json"); response.setHeader(RUNELITE_CACHE, "HIT");
response.header(RUNELITE_CACHE, "HIT");
return searchResult; return searchResult;
} }
@@ -314,8 +303,7 @@ public class ItemService
con.commit(); con.commit();
} }
response.type("application/json"); response.setHeader(RUNELITE_CACHE, "MISS");
response.header(RUNELITE_CACHE, "MISS");
return searchResult; return searchResult;
} }
catch (IOException ex) catch (IOException ex)
@@ -460,7 +448,7 @@ public class ItemService
.addQueryParameter("item", "" + itemId) .addQueryParameter("item", "" + itemId)
.build(); .build();
okhttp3.Request request = new okhttp3.Request.Builder() Request request = new Request.Builder()
.url(itemUrl) .url(itemUrl)
.build(); .build();
@@ -476,7 +464,7 @@ public class ItemService
.addPathSegment(itemId + ".json") .addPathSegment(itemId + ".json")
.build(); .build();
okhttp3.Request request = new okhttp3.Request.Builder() Request request = new Request.Builder()
.url(priceUrl) .url(priceUrl)
.build(); .build();
@@ -490,16 +478,16 @@ public class ItemService
.addQueryParameter("alpha", query) .addQueryParameter("alpha", query)
.build(); .build();
okhttp3.Request request = new okhttp3.Request.Builder() Request request = new Request.Builder()
.url(searchUrl) .url(searchUrl)
.build(); .build();
return fetchJson(request, RSSearch.class); return fetchJson(request, RSSearch.class);
} }
private <T> T fetchJson(okhttp3.Request request, Class<T> clazz) throws IOException private <T> T fetchJson(Request request, Class<T> clazz) throws IOException
{ {
okhttp3.Response response = RuneliteAPI.CLIENT.newCall(request).execute(); Response response = RuneliteAPI.CLIENT.newCall(request).execute();
if (!response.isSuccessful()) if (!response.isSuccessful())
{ {
@@ -521,11 +509,11 @@ public class ItemService
{ {
HttpUrl httpUrl = HttpUrl.parse(url); HttpUrl httpUrl = HttpUrl.parse(url);
okhttp3.Request request = new okhttp3.Request.Builder() Request request = new Request.Builder()
.url(httpUrl) .url(httpUrl)
.build(); .build();
okhttp3.Response response = RuneliteAPI.CLIENT.newCall(request).execute(); Response response = RuneliteAPI.CLIENT.newCall(request).execute();
if (!response.isSuccessful()) if (!response.isSuccessful())
{ {

View File

@@ -25,7 +25,6 @@
package net.runelite.http.service.updatecheck; package net.runelite.http.service.updatecheck;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.inject.Inject;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@@ -41,9 +40,12 @@ import net.runelite.http.api.worlds.WorldResult;
import net.runelite.http.service.worlds.WorldsService; import net.runelite.http.service.worlds.WorldsService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import spark.Request; import org.springframework.beans.factory.annotation.Autowired;
import spark.Response; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/update-check")
public class UpdateCheckService public class UpdateCheckService
{ {
private static final Logger logger = LoggerFactory.getLogger(UpdateCheckService.class); private static final Logger logger = LoggerFactory.getLogger(UpdateCheckService.class);
@@ -58,15 +60,15 @@ public class UpdateCheckService
private final WorldsService worldsService; private final WorldsService worldsService;
private final Supplier<Boolean> updateAvailable = Suppliers.memoizeWithExpiration(this::checkUpdate, 1, TimeUnit.MINUTES); private final Supplier<Boolean> updateAvailable = Suppliers.memoizeWithExpiration(this::checkUpdate, 1, TimeUnit.MINUTES);
@Inject @Autowired
public UpdateCheckService(WorldsService worldsService) public UpdateCheckService(WorldsService worldsService)
{ {
this.worldsService = worldsService; this.worldsService = worldsService;
} }
public Boolean check(Request request, Response response) @RequestMapping
public Boolean check()
{ {
response.type("application/json");
return updateAvailable.get(); return updateAvailable.get();
} }

View File

@@ -32,30 +32,28 @@ import net.runelite.http.api.RuneliteAPI;
import net.runelite.http.api.worlds.World; import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldResult; import net.runelite.http.api.worlds.WorldResult;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import spark.Request; import org.springframework.web.bind.annotation.RequestMapping;
import spark.Response; import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/worlds")
public class WorldsService public class WorldsService
{ {
private static final HttpUrl WORLD_URL = HttpUrl.parse("http://www.runescape.com/g=oldscape/slr.ws?order=LPWM"); private static final HttpUrl WORLD_URL = HttpUrl.parse("http://www.runescape.com/g=oldscape/slr.ws?order=LPWM");
private HttpUrl url = WORLD_URL; private HttpUrl url = WORLD_URL;
public WorldResult listWorlds(Request request, Response response) throws IOException @RequestMapping
{
WorldResult result = listWorlds();
response.type("application/json");
return result;
}
public WorldResult listWorlds() throws IOException public WorldResult listWorlds() throws IOException
{ {
okhttp3.Request okrequest = new okhttp3.Request.Builder() Request okrequest = new Request.Builder()
.url(url) .url(url)
.build(); .build();
okhttp3.Response okresponse = RuneliteAPI.CLIENT.newCall(okrequest).execute(); Response okresponse = RuneliteAPI.CLIENT.newCall(okrequest).execute();
byte[] b; byte[] b;
try (ResponseBody body = okresponse.body()) try (ResponseBody body = okresponse.body())

View File

@@ -24,21 +24,25 @@
*/ */
package net.runelite.http.service.xtea; package net.runelite.http.service.xtea;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.runelite.http.api.xtea.XteaKey; import net.runelite.http.api.xtea.XteaKey;
import net.runelite.http.api.xtea.XteaRequest; import net.runelite.http.api.xtea.XteaRequest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import org.springframework.web.bind.annotation.RestController;
import org.sql2o.Connection; import org.sql2o.Connection;
import org.sql2o.Query; import org.sql2o.Query;
import org.sql2o.Sql2o; import org.sql2o.Sql2o;
import spark.Request;
import spark.Response;
@RestController
@RequestMapping("/xtea")
public class XteaService public class XteaService
{ {
private static final Logger logger = LoggerFactory.getLogger(XteaService.class); private static final Logger logger = LoggerFactory.getLogger(XteaService.class);
@@ -54,16 +58,12 @@ public class XteaService
+ ") ENGINE=InnoDB;"; + ") ENGINE=InnoDB;";
private final Sql2o sql2o; private final Sql2o sql2o;
private final Gson gson = new Gson();
@Inject @Autowired
public XteaService(@Named("Runelite SQL2O") Sql2o sql2o) public XteaService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{ {
this.sql2o = sql2o; this.sql2o = sql2o;
}
public void init()
{
try (Connection con = sql2o.beginTransaction()) try (Connection con = sql2o.beginTransaction())
{ {
con.createQuery(CREATE_SQL) con.createQuery(CREATE_SQL)
@@ -71,10 +71,9 @@ public class XteaService
} }
} }
public Object submit(Request request, Response response) @RequestMapping(method = POST)
public Object submit(@RequestBody XteaRequest xteaRequest)
{ {
XteaRequest xteaRequest = gson.fromJson(request.body(), XteaRequest.class);
try (Connection con = sql2o.beginTransaction()) try (Connection con = sql2o.beginTransaction())
{ {
Query query = con.createQuery("insert ignore into xtea (rev, region, key1, key2, key3, key4) values (:rev, :region, :key1, :key2, :key3, :key4)"); Query query = con.createQuery("insert ignore into xtea (rev, region, key1, key2, key3, key4) values (:rev, :region, :key1, :key2, :key3, :key4)");
@@ -97,19 +96,15 @@ public class XteaService
return ""; return "";
} }
public List<XteaKey> get(Request request, Response response) @RequestMapping("/{revision}")
public List<XteaKey> get(@PathVariable int revision)
{ {
String revStr = request.params("rev");
int revision = Integer.parseInt(revStr);
try (Connection con = sql2o.open()) try (Connection con = sql2o.open())
{ {
List<XteaEntry> entries = con.createQuery("select * from xtea where rev = :rev") List<XteaEntry> entries = con.createQuery("select * from xtea where rev = :rev")
.addParameter("rev", revision) .addParameter("rev", revision)
.executeAndFetch(XteaEntry.class); .executeAndFetch(XteaEntry.class);
response.type("application/json");
return entries.stream() return entries.stream()
.map(XteaService::entryToKey) .map(XteaService::entryToKey)
.collect(Collectors.toList()); .collect(Collectors.toList());

View File

@@ -29,23 +29,4 @@
version="3.1"> version="3.1">
<display-name>Runelite API</display-name> <display-name>Runelite API</display-name>
<servlet>
<servlet-name>SparkServlet</servlet-name>
<servlet-class>net.runelite.http.service.SparkServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SparkServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.commongroundpublishing.slf4j.impl.ServletContextLoggerSCL</listener-class>
</listener>
<context-param>
<param-name>ServletContextLogger.LEVEL</param-name>
<param-value>INFO</param-value>
</context-param>
</web-app> </web-app>

View File

@@ -1,121 +0,0 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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;
import com.commongroundpublishing.slf4j.impl.ServletContextLogger;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletContext;
import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.hiscore.Skill;
import net.runelite.http.service.hiscore.HiscoreService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.Matchers;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.MockitoAnnotations;
import org.sql2o.Sql2o;
import spark.Request;
import spark.Response;
import spark.Spark;
public class ServiceTest
{
private static final String URL_BASE = "http://localhost:4567";
private Service service;
@Bind
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@Named("Runelite SQL2O")
private Sql2o sql2o;
@Bind
@Named("OAuth Client ID")
private String clientId = "test";
@Bind
@Named("OAuth Client Secret")
private String clientSecret = "test";
@Bind
@Mock
private HiscoreService hiscoreService;
@Before
public void before()
{
// Init mocks first, else we're binding null objects
MockitoAnnotations.initMocks(this);
// Inject everything in the test object
Injector injector = Guice.createInjector(BoundFieldModule.of(this));
injector.injectMembers(this);
ServletContextLogger.setServletContext(mock(ServletContext.class));
service = injector.getInstance(Service.class);
service.setupRoutes();
Spark.awaitInitialization();
}
@After
public void after()
{
Spark.stop();
}
@Test
public void testInit() throws Exception
{
HiscoreResult result = new HiscoreResult();
result.setAttack(new Skill(1, 99, 42));
when(hiscoreService.lookup(Matchers.any(Request.class), Matchers.any(Response.class))).thenReturn(result);
URL url = new URL(URL_BASE + "/hiscore?username=zezima");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
Gson gson = new Gson();
HiscoreResult res = gson.fromJson(new InputStreamReader(connection.getInputStream()), HiscoreResult.class);
Assert.assertEquals(result, res);
}
}

View File

@@ -24,23 +24,50 @@
*/ */
package net.runelite.http.service; package net.runelite.http.service;
import com.google.gson.Gson; import java.time.Instant;
import spark.ResponseTransformer; import java.util.HashMap;
import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.sql2o.Sql2o;
import org.sql2o.converters.Converter;
import org.sql2o.quirks.NoQuirks;
public class JsonTransformer implements ResponseTransformer @SpringBootApplication
public class SpringBootWebApplicationTest
{ {
private final Gson gson = new Gson(); @Bean("Runelite SQL2O")
Sql2o sql2o()
@Override
public String render(Object model) throws Exception
{ {
if (model == null) Map<Class, Converter> converters = new HashMap<>();
{ converters.put(Instant.class, new InstantConverter());
// gson turns a null object into "null" which return new Sql2o("jdbc:mysql://192.168.1.2/runelite", "adam", "", new NoQuirks(converters));
// causes spark to return http 200 instead of 404
return null;
}
return gson.toJson(model); }
@Bean("OAuth Client ID")
String oauthClientId()
{
return "moo";
}
@Bean("OAuth Client Secret")
String oauthClientSecret()
{
return "moo2";
}
@Test
@Ignore
public void test() throws InterruptedException
{
SpringApplication.run(SpringBootWebApplicationTest.class, new String[0]);
for (;;)
{
Thread.sleep(100L);
}
} }
} }

View File

@@ -32,9 +32,6 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.mockito.Mockito.mock;
import spark.Request;
import spark.Response;
public class HiscoreServiceTest public class HiscoreServiceTest
{ {
@@ -94,10 +91,7 @@ public class HiscoreServiceTest
HiscoreService hiscores = new HiscoreService(); HiscoreService hiscores = new HiscoreService();
hiscores.setUrl(server.url("/")); hiscores.setUrl(server.url("/"));
Request request = mock(Request.class); HiscoreResult result = hiscores.lookup("zezima");
Response response = mock(Response.class);
HiscoreResult result = hiscores.lookup(request, response);
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

@@ -34,7 +34,7 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import spark.utils.IOUtils; import org.sql2o.tools.IOUtils;
public class WorldsServiceTest public class WorldsServiceTest
{ {