From 37d538f0dbf2f0f626f6614f902490e8c0e97a63 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Dec 2021 16:12:58 -0500 Subject: [PATCH 01/34] Move http-api clients to rl-client --- .../net/runelite/http/api/RuneLiteAPI.java | 67 +------------------ .../runelite/client/ClientSessionManager.java | 5 +- .../net/runelite/client/RuneLiteModule.java | 35 ++++++++-- .../runelite/client/RuneLiteProperties.java | 6 ++ .../net/runelite/client/SessionClient.java | 28 +++++--- .../client}/account/AccountClient.java | 23 ++++--- .../client/account/SessionManager.java | 6 +- .../net/runelite/client}/chat/ChatClient.java | 49 ++++++++------ .../runelite/client}/config/ConfigClient.java | 28 +++++--- .../runelite/client/config/ConfigManager.java | 21 +++--- .../externalplugins/ExternalPluginClient.java | 12 +++- .../net/runelite/client/game}/ItemClient.java | 24 +++++-- .../net/runelite/client/game/ItemManager.java | 6 +- .../net/runelite/client/game/NPCManager.java | 11 ++- .../net/runelite/client/game}/NpcInfo.java | 2 +- .../runelite/client/game}/NpcInfoClient.java | 16 +++-- .../runelite/client/game}/WorldClient.java | 6 +- .../runelite/client/game/WorldService.java | 7 +- .../chatcommands/ChatCommandsPlugin.java | 2 +- .../client/plugins}/feed/FeedClient.java | 17 +++-- .../client/plugins/feed/FeedPlugin.java | 8 --- .../grandexchange}/GrandExchangeClient.java | 17 +++-- .../grandexchange/GrandExchangePlugin.java | 8 --- .../loottracker/LootTrackerClient.java | 23 +++++-- .../plugins/loottracker/LootTrackerPanel.java | 1 - .../loottracker/LootTrackerPlugin.java | 8 --- .../client/plugins/raids/RaidsPlugin.java | 2 +- .../client/plugins/slayer/SlayerPlugin.java | 2 +- .../client/plugins/xptracker}/XpClient.java | 12 ++-- .../plugins/xptracker/XpTrackerPlugin.java | 8 --- .../client/plugins}/xtea/XteaClient.java | 28 +++++--- .../client/plugins/xtea/XteaPlugin.java | 9 --- .../net/runelite/client/rs/WorldSupplier.java | 8 ++- .../java/net/runelite/client/ws/WSClient.java | 8 ++- .../net/runelite/client/runelite.properties | 6 +- .../client/config/ConfigManagerTest.java | 4 ++ .../client/hiscore/HiscoreClientTest.java | 4 +- .../chatcommands/ChatCommandsPluginTest.java | 7 +- .../GrandExchangePluginTest.java | 1 - .../loottracker/LootTrackerPluginTest.java | 1 - .../client/plugins/raids/RaidsPluginTest.java | 35 ++++++---- .../plugins/slayer/SlayerPluginTest.java | 6 +- .../SpecialCounterPluginTest.java | 5 ++ .../xptracker/XpTrackerPluginTest.java | 1 - 44 files changed, 324 insertions(+), 259 deletions(-) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client}/account/AccountClient.java (87%) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client}/chat/ChatClient.java (91%) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client}/config/ConfigClient.java (91%) rename {http-api/src/main/java/net/runelite/http/api/item => runelite-client/src/main/java/net/runelite/client/game}/ItemClient.java (85%) rename {http-api/src/main/java/net/runelite/http/api/npc => runelite-client/src/main/java/net/runelite/client/game}/NpcInfo.java (97%) rename {http-api/src/main/java/net/runelite/http/api/npc => runelite-client/src/main/java/net/runelite/client/game}/NpcInfoClient.java (88%) rename {http-api/src/main/java/net/runelite/http/api/worlds => runelite-client/src/main/java/net/runelite/client/game}/WorldClient.java (94%) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client/plugins}/feed/FeedClient.java (86%) rename {http-api/src/main/java/net/runelite/http/api/ge => runelite-client/src/main/java/net/runelite/client/plugins/grandexchange}/GrandExchangeClient.java (87%) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client/plugins}/loottracker/LootTrackerClient.java (89%) rename {http-api/src/main/java/net/runelite/http/api/xp => runelite-client/src/main/java/net/runelite/client/plugins/xptracker}/XpClient.java (88%) rename {http-api/src/main/java/net/runelite/http/api => runelite-client/src/main/java/net/runelite/client/plugins}/xtea/XteaClient.java (86%) diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 6304d59b46..99c699da51 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -32,10 +32,10 @@ import java.io.InputStream; import java.time.Instant; import java.util.Properties; import java.util.concurrent.TimeUnit; +import lombok.Getter; import net.runelite.http.api.gson.ColorTypeAdapter; -import net.runelite.http.api.gson.InstantTypeAdapter; import net.runelite.http.api.gson.IllegalReflectionExclusion; -import okhttp3.HttpUrl; +import net.runelite.http.api.gson.InstantTypeAdapter; import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -56,10 +56,8 @@ public class RuneLiteAPI public static final MediaType JSON = MediaType.parse("application/json"); public static String userAgent; - private static final String BASE = "https://api.runelite.net"; - private static final String WSBASE = "https://api.runelite.net/ws"; - private static final String STATICBASE = "https://static.runelite.net"; private static final Properties properties = new Properties(); + @Getter private static String version; static @@ -118,63 +116,4 @@ public class RuneLiteAPI GSON = gsonBuilder.create(); } - - public static HttpUrl getSessionBase() - { - final String prop = System.getProperty("runelite.session.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(BASE + "/session"); - } - - public static HttpUrl getApiBase() - { - final String prop = System.getProperty("runelite.http-service.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(BASE + "/runelite-" + getVersion()); - } - - public static HttpUrl getStaticBase() - { - final String prop = System.getProperty("runelite.static.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(STATICBASE); - } - - public static HttpUrl getWsEndpoint() - { - final String prop = System.getProperty("runelite.ws.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(WSBASE); - } - - public static String getVersion() - { - return version; - } - - public static void setVersion(String version) - { - RuneLiteAPI.version = version; - } - } diff --git a/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java b/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java index 588a1ad006..3f884b092a 100644 --- a/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ClientSessionManager.java @@ -38,7 +38,6 @@ import net.runelite.api.GameState; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ClientShutdown; import net.runelite.client.util.RunnableExceptionLogger; -import okhttp3.OkHttpClient; @Singleton @Slf4j @@ -54,11 +53,11 @@ public class ClientSessionManager @Inject ClientSessionManager(ScheduledExecutorService executorService, @Nullable Client client, - OkHttpClient okHttpClient) + SessionClient sessionClient) { this.executorService = executorService; this.client = client; - this.sessionClient = new SessionClient(okHttpClient); + this.sessionClient = sessionClient; } public void start() diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java index 8c80c67a37..569f05e20d 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java @@ -24,6 +24,7 @@ */ package net.runelite.client; +import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -35,6 +36,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Supplier; import javax.annotation.Nullable; +import javax.inject.Named; import javax.inject.Singleton; import lombok.AllArgsConstructor; import net.runelite.api.Client; @@ -53,7 +55,7 @@ import net.runelite.client.task.Scheduler; import net.runelite.client.util.DeferredEventBus; import net.runelite.client.util.ExecutorServiceExceptionLogger; import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.chat.ChatClient; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @AllArgsConstructor @@ -129,9 +131,34 @@ public class RuneLiteModule extends AbstractModule } @Provides - @Singleton - ChatClient provideChatClient(OkHttpClient okHttpClient) + @Named("runelite.api.base") + HttpUrl provideApiBase(@Named("runelite.api.base") String s) { - return new ChatClient(okHttpClient); + final String prop = System.getProperty("runelite.http-service.url"); + return HttpUrl.get(Strings.isNullOrEmpty(prop) ? s : prop); + } + + @Provides + @Named("runelite.session") + HttpUrl provideSession(@Named("runelite.session") String s) + { + final String prop = System.getProperty("runelite.session.url"); + return HttpUrl.get(Strings.isNullOrEmpty(prop) ? s : prop); + } + + @Provides + @Named("runelite.static.base") + HttpUrl provideStaticBase(@Named("runelite.static.base") String s) + { + final String prop = System.getProperty("runelite.static.url"); + return HttpUrl.get(Strings.isNullOrEmpty(prop) ? s : prop); + } + + @Provides + @Named("runelite.ws") + HttpUrl provideWs(@Named("runelite.ws") String s) + { + final String prop = System.getProperty("runelite.ws.url"); + return HttpUrl.get(Strings.isNullOrEmpty(prop) ? s : prop); } } diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index 2be480f85e..1f878b26cc 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -45,6 +45,7 @@ public class RuneLiteProperties private static final String JAV_CONFIG_BACKUP = "runelite.jav_config_backup"; private static final String PLUGINHUB_BASE = "runelite.pluginhub.url"; private static final String PLUGINHUB_VERSION = "runelite.pluginhub.version"; + private static final String API_BASE = "runelite.api.base"; @Getter(AccessLevel.PACKAGE) private static final Properties properties = new Properties(); @@ -112,4 +113,9 @@ public class RuneLiteProperties String version = System.getProperty(PLUGINHUB_VERSION, properties.getProperty(PLUGINHUB_VERSION)); return HttpUrl.parse(properties.get(PLUGINHUB_BASE) + "/" + version); } + + public static String getApiBase() + { + return properties.getProperty(API_BASE); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/SessionClient.java b/runelite-client/src/main/java/net/runelite/client/SessionClient.java index ea75fc5f79..5727af1f7b 100644 --- a/runelite-client/src/main/java/net/runelite/client/SessionClient.java +++ b/runelite-client/src/main/java/net/runelite/client/SessionClient.java @@ -30,7 +30,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.UUID; -import lombok.AllArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import net.runelite.http.api.RuneLiteAPI; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @@ -39,14 +40,21 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -@AllArgsConstructor class SessionClient { - private final OkHttpClient okHttpClient; + private final OkHttpClient client; + private final HttpUrl sessionUrl; + + @Inject + private SessionClient(OkHttpClient client, @Named("runelite.session") HttpUrl sessionUrl) + { + this.client = client; + this.sessionUrl = sessionUrl; + } UUID open() throws IOException { - HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder() + HttpUrl url = sessionUrl.newBuilder() .build(); Request request = new Request.Builder() @@ -54,10 +62,10 @@ class SessionClient .url(url) .build(); - try (Response response = okHttpClient.newCall(request).execute()) + try (Response response = client.newCall(request).execute()) { ResponseBody body = response.body(); - + InputStream in = body.byteStream(); return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), UUID.class); } @@ -69,7 +77,7 @@ class SessionClient void ping(UUID uuid, boolean loggedIn) throws IOException { - HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder() + HttpUrl url = sessionUrl.newBuilder() .addPathSegment("ping") .addQueryParameter("session", uuid.toString()) .addQueryParameter("logged-in", String.valueOf(loggedIn)) @@ -80,7 +88,7 @@ class SessionClient .url(url) .build(); - try (Response response = okHttpClient.newCall(request).execute()) + try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { @@ -91,7 +99,7 @@ class SessionClient void delete(UUID uuid) throws IOException { - HttpUrl url = RuneLiteAPI.getSessionBase().newBuilder() + HttpUrl url = sessionUrl.newBuilder() .addQueryParameter("session", uuid.toString()) .build(); @@ -100,6 +108,6 @@ class SessionClient .url(url) .build(); - okHttpClient.newCall(request).execute().close(); + client.newCall(request).execute().close(); } } diff --git a/http-api/src/main/java/net/runelite/http/api/account/AccountClient.java b/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java similarity index 87% rename from http-api/src/main/java/net/runelite/http/api/account/AccountClient.java rename to runelite-client/src/main/java/net/runelite/client/account/AccountClient.java index ff999c6d71..4c26a60170 100644 --- a/http-api/src/main/java/net/runelite/http/api/account/AccountClient.java +++ b/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java @@ -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.api.account; +package net.runelite.client.account; import com.google.gson.JsonParseException; import java.io.IOException; @@ -30,29 +30,36 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.UUID; -import lombok.RequiredArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.account.OAuthResponse; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @Slf4j -@RequiredArgsConstructor public class AccountClient { private final OkHttpClient client; + private final HttpUrl apiBase; + + @Setter private UUID uuid; - public void setUuid(UUID uuid) + @Inject + private AccountClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) { - this.uuid = uuid; + this.client = client; + this.apiBase = apiBase; } public OAuthResponse login() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("account") .addPathSegment("login") .addQueryParameter("uuid", uuid.toString()) @@ -77,7 +84,7 @@ public class AccountClient public void logout() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("account") .addPathSegment("logout") .build(); @@ -97,7 +104,7 @@ public class AccountClient public boolean sessionCheck() { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("account") .addPathSegment("session-check") .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java index 93c1f8f584..c9f432db02 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java @@ -47,10 +47,8 @@ import net.runelite.client.events.SessionClose; import net.runelite.client.events.SessionOpen; import net.runelite.client.util.LinkBrowser; import net.runelite.client.ws.WSClient; -import net.runelite.http.api.account.AccountClient; import net.runelite.http.api.account.OAuthResponse; import net.runelite.http.api.ws.messages.LoginResponse; -import okhttp3.OkHttpClient; @Singleton @Slf4j @@ -72,14 +70,14 @@ public class SessionManager ConfigManager configManager, EventBus eventBus, WSClient wsClient, - OkHttpClient okHttpClient, + AccountClient accountClient, Gson gson) { this.configManager = configManager; this.eventBus = eventBus; this.wsClient = wsClient; this.sessionFile = sessionfile; - this.accountClient = new AccountClient(okHttpClient); + this.accountClient = accountClient; this.gson = gson; eventBus.register(this); diff --git a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatClient.java similarity index 91% rename from http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java rename to runelite-client/src/main/java/net/runelite/client/chat/ChatClient.java index 06ca9bb623..2b599b47e0 100644 --- a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatClient.java @@ -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.api.chat; +package net.runelite.client.chat; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; @@ -32,22 +32,33 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Set; -import lombok.AllArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.chat.Duels; +import net.runelite.http.api.chat.LayoutRoom; +import net.runelite.http.api.chat.Task; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; -@AllArgsConstructor public class ChatClient { private final OkHttpClient client; + private final HttpUrl apiBase; + + @Inject + private ChatClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } public boolean submitKc(String username, String boss, int kc) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("kc") .addQueryParameter("name", username) @@ -68,7 +79,7 @@ public class ChatClient public int getKc(String username, String boss) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("kc") .addQueryParameter("name", username) @@ -91,7 +102,7 @@ public class ChatClient public boolean submitQp(String username, int qp) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("qp") .addQueryParameter("name", username) @@ -111,7 +122,7 @@ public class ChatClient public int getQp(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("qp") .addQueryParameter("name", username) @@ -133,7 +144,7 @@ public class ChatClient public boolean submitTask(String username, String task, int amount, int initialAmount, String location) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("task") .addQueryParameter("name", username) @@ -156,7 +167,7 @@ public class ChatClient public Task getTask(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("task") .addQueryParameter("name", username) @@ -184,7 +195,7 @@ public class ChatClient public boolean submitPb(String username, String boss, double pb) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("pb") .addQueryParameter("name", username) @@ -205,7 +216,7 @@ public class ChatClient public double getPb(String username, String boss) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("pb") .addQueryParameter("name", username) @@ -228,7 +239,7 @@ public class ChatClient public boolean submitGc(String username, int gc) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("gc") .addQueryParameter("name", username) @@ -248,7 +259,7 @@ public class ChatClient public int getGc(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("gc") .addQueryParameter("name", username) @@ -270,7 +281,7 @@ public class ChatClient public boolean submitDuels(String username, int wins, int losses, int winningStreak, int losingStreak) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("duels") .addQueryParameter("name", username) @@ -293,7 +304,7 @@ public class ChatClient public Duels getDuels(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("duels") .addQueryParameter("name", username) @@ -321,7 +332,7 @@ public class ChatClient public boolean submitLayout(String username, LayoutRoom[] rooms) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("layout") .addQueryParameter("name", username) @@ -340,7 +351,7 @@ public class ChatClient public LayoutRoom[] getLayout(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("layout") .addQueryParameter("name", username) @@ -368,7 +379,7 @@ public class ChatClient public boolean submitPetList(String username, Collection petList) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("pets") .addQueryParameter("name", username) @@ -387,7 +398,7 @@ public class ChatClient public Set getPetList(String username) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("chat") .addPathSegment("pets") .addQueryParameter("name", username) diff --git a/http-api/src/main/java/net/runelite/http/api/config/ConfigClient.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigClient.java similarity index 91% rename from http-api/src/main/java/net/runelite/http/api/config/ConfigClient.java rename to runelite-client/src/main/java/net/runelite/client/config/ConfigClient.java index b66b802399..a973d3c9a8 100644 --- a/http-api/src/main/java/net/runelite/http/api/config/ConfigClient.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigClient.java @@ -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.api.config; +package net.runelite.client.config; import com.google.gson.Gson; import com.google.gson.JsonParseException; @@ -32,9 +32,12 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import lombok.AllArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.config.Configuration; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -44,7 +47,6 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; -@AllArgsConstructor @Slf4j public class ConfigClient { @@ -52,11 +54,21 @@ public class ConfigClient private static final Gson GSON = RuneLiteAPI.GSON; private final OkHttpClient client; - private final UUID uuid; + private final HttpUrl apiBase; + + @Setter + private UUID uuid; + + @Inject + private ConfigClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } public Configuration get() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("config") .build(); @@ -82,7 +94,7 @@ public class ConfigClient { CompletableFuture future = new CompletableFuture<>(); - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("config") .addPathSegment(key) .build(); @@ -120,7 +132,7 @@ public class ConfigClient { CompletableFuture future = new CompletableFuture<>(); - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("config") .build(); @@ -173,7 +185,7 @@ public class ConfigClient { CompletableFuture future = new CompletableFuture<>(); - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("config") .addPathSegment(key) .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index b9b3a8503b..fd6e492d39 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -72,6 +72,7 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; @@ -92,10 +93,8 @@ import net.runelite.client.events.ClientShutdown; import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.RuneScapeProfileChanged; import net.runelite.client.util.ColorUtil; -import net.runelite.http.api.config.ConfigClient; import net.runelite.http.api.config.ConfigEntry; import net.runelite.http.api.config.Configuration; -import okhttp3.OkHttpClient; @Singleton @Slf4j @@ -116,11 +115,11 @@ public class ConfigManager private final File settingsFileInput; private final EventBus eventBus; - private final OkHttpClient okHttpClient; private final Gson gson; + @Nonnull + private final ConfigClient configClient; private AccountSession session; - private ConfigClient configClient; private File propertiesFile; @Nullable @@ -140,16 +139,16 @@ public class ConfigManager @Named("config") File config, ScheduledExecutorService scheduledExecutorService, EventBus eventBus, - OkHttpClient okHttpClient, @Nullable Client client, - Gson gson) + Gson gson, + ConfigClient configClient) { this.settingsFileInput = config; this.eventBus = eventBus; - this.okHttpClient = okHttpClient; this.client = client; this.propertiesFile = getPropertiesFile(); this.gson = gson; + this.configClient = configClient; scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 5 * 60, TimeUnit.SECONDS); } @@ -167,12 +166,12 @@ public class ConfigManager if (session == null) { this.session = null; - this.configClient = null; + configClient.setUuid(null); } else { this.session = session; - this.configClient = new ConfigClient(okHttpClient, session.getUuid()); + configClient.setUuid(session.getUuid()); } this.propertiesFile = getPropertiesFile(); @@ -201,7 +200,7 @@ public class ConfigManager public void load() { - if (configClient == null) + if (session == null) { loadFromFile(); return; @@ -909,7 +908,7 @@ public class ConfigManager return null; } - if (configClient != null) + if (session != null) { Configuration patch = new Configuration(pendingChanges.entrySet().stream() .map(e -> new ConfigEntry(e.getKey(), e.getValue())) diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java index d101cc22bb..6bea4781c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.client.RuneLiteProperties; import net.runelite.client.util.VerificationException; @@ -62,12 +63,17 @@ public class ExternalPluginClient { private final OkHttpClient okHttpClient; private final Gson gson; + private final HttpUrl apiBase; @Inject - private ExternalPluginClient(OkHttpClient okHttpClient, Gson gson) + private ExternalPluginClient(OkHttpClient okHttpClient, + Gson gson, + @Named("runelite.api.base") HttpUrl apiBase + ) { this.okHttpClient = okHttpClient; this.gson = gson; + this.apiBase = apiBase; } public List downloadManifest() throws IOException, VerificationException @@ -153,7 +159,7 @@ public class ExternalPluginClient return; } - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("pluginhub") .build(); @@ -181,7 +187,7 @@ public class ExternalPluginClient public Map getPluginCounts() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase() + HttpUrl url = apiBase .newBuilder() .addPathSegments("pluginhub") .build(); diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemClient.java b/runelite-client/src/main/java/net/runelite/client/game/ItemClient.java similarity index 85% rename from http-api/src/main/java/net/runelite/http/api/item/ItemClient.java rename to runelite-client/src/main/java/net/runelite/client/game/ItemClient.java index 37fb27fc24..f48be2532d 100644 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemClient.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemClient.java @@ -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.api.item; +package net.runelite.client.game; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; @@ -32,23 +32,37 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Map; -import lombok.AllArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.item.ItemPrice; +import net.runelite.http.api.item.ItemStats; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @Slf4j -@AllArgsConstructor public class ItemClient { private final OkHttpClient client; + private final HttpUrl apiBase, staticBase; + + @Inject + private ItemClient(OkHttpClient client, + @Named("runelite.api.base") HttpUrl apiBase, + @Named("runelite.static.base") HttpUrl staticBase + ) + { + this.client = client; + this.apiBase = apiBase; + this.staticBase = staticBase; + } public ItemPrice[] getPrices() throws IOException { - HttpUrl.Builder urlBuilder = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl.Builder urlBuilder = apiBase.newBuilder() .addPathSegment("item") .addPathSegment("prices.js"); @@ -79,7 +93,7 @@ public class ItemClient public Map getStats() throws IOException { - HttpUrl.Builder urlBuilder = RuneLiteAPI.getStaticBase().newBuilder() + HttpUrl.Builder urlBuilder = staticBase.newBuilder() .addPathSegment("item") // TODO: Change this to stats.min.json later after release is undeployed .addPathSegment("stats.ids.min.json"); diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java index edb1659b89..b02b332ef2 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemManager.java @@ -55,10 +55,8 @@ import net.runelite.api.SpritePixels; import net.runelite.client.callback.ClientThread; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.util.AsyncBufferedImage; -import net.runelite.http.api.item.ItemClient; import net.runelite.http.api.item.ItemPrice; import net.runelite.http.api.item.ItemStats; -import okhttp3.OkHttpClient; @Singleton @Slf4j @@ -167,11 +165,11 @@ public class ItemManager @Inject public ItemManager(Client client, ScheduledExecutorService scheduledExecutorService, ClientThread clientThread, - OkHttpClient okHttpClient, RuneLiteConfig runeLiteConfig) + ItemClient itemClient, RuneLiteConfig runeLiteConfig) { this.client = client; this.clientThread = clientThread; - this.itemClient = new ItemClient(okHttpClient); + this.itemClient = itemClient; this.runeLiteConfig = runeLiteConfig; scheduledExecutorService.scheduleWithFixedDelay(this::loadPrices, 0, 30, TimeUnit.MINUTES); diff --git a/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java b/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java index 1a51afea3f..c1d182be38 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/NPCManager.java @@ -32,21 +32,18 @@ import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.npc.NpcInfo; -import net.runelite.http.api.npc.NpcInfoClient; -import okhttp3.OkHttpClient; @Singleton @Slf4j public class NPCManager { - private final OkHttpClient okHttpClient; + private final NpcInfoClient npcInfoClient; private Map npcMap = Collections.emptyMap(); @Inject - private NPCManager(OkHttpClient okHttpClient, ScheduledExecutorService scheduledExecutorService) + private NPCManager(NpcInfoClient npcInfoClient, ScheduledExecutorService scheduledExecutorService) { - this.okHttpClient = okHttpClient; + this.npcInfoClient = npcInfoClient; scheduledExecutorService.execute(this::loadNpcs); } @@ -67,7 +64,7 @@ public class NPCManager { try { - npcMap = new NpcInfoClient(okHttpClient).getNpcs(); + npcMap = npcInfoClient.getNpcs(); } catch (IOException e) { diff --git a/http-api/src/main/java/net/runelite/http/api/npc/NpcInfo.java b/runelite-client/src/main/java/net/runelite/client/game/NpcInfo.java similarity index 97% rename from http-api/src/main/java/net/runelite/http/api/npc/NpcInfo.java rename to runelite-client/src/main/java/net/runelite/client/game/NpcInfo.java index 091f36e471..c33832c75c 100644 --- a/http-api/src/main/java/net/runelite/http/api/npc/NpcInfo.java +++ b/runelite-client/src/main/java/net/runelite/client/game/NpcInfo.java @@ -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.api.npc; +package net.runelite.client.game; import lombok.Data; diff --git a/http-api/src/main/java/net/runelite/http/api/npc/NpcInfoClient.java b/runelite-client/src/main/java/net/runelite/client/game/NpcInfoClient.java similarity index 88% rename from http-api/src/main/java/net/runelite/http/api/npc/NpcInfoClient.java rename to runelite-client/src/main/java/net/runelite/client/game/NpcInfoClient.java index d7c4396625..aa625e4928 100644 --- a/http-api/src/main/java/net/runelite/http/api/npc/NpcInfoClient.java +++ b/runelite-client/src/main/java/net/runelite/client/game/NpcInfoClient.java @@ -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.api.npc; +package net.runelite.client.game; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; @@ -32,7 +32,8 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Map; -import lombok.Value; +import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import okhttp3.HttpUrl; @@ -41,14 +42,21 @@ import okhttp3.Request; import okhttp3.Response; @Slf4j -@Value public class NpcInfoClient { private final OkHttpClient client; + private final HttpUrl staticBase; + + @Inject + private NpcInfoClient(OkHttpClient client, @Named("runelite.static.base") HttpUrl staticBase) + { + this.client = client; + this.staticBase = staticBase; + } public Map getNpcs() throws IOException { - HttpUrl.Builder urlBuilder = RuneLiteAPI.getStaticBase().newBuilder() + HttpUrl.Builder urlBuilder = staticBase.newBuilder() .addPathSegment("npcs") .addPathSegment("npcs.min.json"); diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java b/runelite-client/src/main/java/net/runelite/client/game/WorldClient.java similarity index 94% rename from http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java rename to runelite-client/src/main/java/net/runelite/client/game/WorldClient.java index d6e0865f14..9c0c442a0f 100644 --- a/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java +++ b/runelite-client/src/main/java/net/runelite/client/game/WorldClient.java @@ -23,7 +23,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.api.worlds; +package net.runelite.client.game; import com.google.gson.JsonParseException; import java.io.IOException; @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.worlds.WorldResult; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -43,10 +44,11 @@ import okhttp3.Response; public class WorldClient { private final OkHttpClient client; + private final HttpUrl apiBase; public WorldResult lookupWorlds() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("worlds.js") .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/game/WorldService.java b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java index 4cc102016d..77864bca17 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/WorldService.java +++ b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java @@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.annotation.Nullable; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -41,8 +42,8 @@ import net.runelite.client.eventbus.EventBus; import net.runelite.client.events.WorldsFetch; import net.runelite.client.util.RunnableExceptionLogger; import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldClient; import net.runelite.http.api.worlds.WorldResult; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @Singleton @@ -61,11 +62,11 @@ public class WorldService @Inject private WorldService(Client client, ScheduledExecutorService scheduledExecutorService, OkHttpClient okHttpClient, - EventBus eventBus) + @Named("runelite.api.base") HttpUrl apiBase, EventBus eventBus) { this.client = client; this.scheduledExecutorService = scheduledExecutorService; - this.worldClient = new WorldClient(okHttpClient); + this.worldClient = new WorldClient(okHttpClient, apiBase); this.eventBus = eventBus; scheduledExecutorService.scheduleWithFixedDelay(RunnableExceptionLogger.wrap(this::tick), 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java index 4105a926a5..4973401812 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java @@ -73,6 +73,7 @@ import static net.runelite.api.widgets.WidgetID.DIARY_QUEST_GROUP_ID; import static net.runelite.api.widgets.WidgetID.KILL_LOGS_GROUP_ID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; @@ -93,7 +94,6 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.QuantityFormatter; import net.runelite.client.util.Text; -import net.runelite.http.api.chat.ChatClient; import net.runelite.http.api.chat.Duels; import net.runelite.http.api.item.ItemPrice; import okhttp3.OkHttpClient; diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedClient.java b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedClient.java similarity index 86% rename from http-api/src/main/java/net/runelite/http/api/feed/FeedClient.java rename to runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedClient.java index a0b628df33..f1b2506393 100644 --- a/http-api/src/main/java/net/runelite/http/api/feed/FeedClient.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedClient.java @@ -22,30 +22,39 @@ * (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.api.feed; +package net.runelite.client.plugins.feed; import com.google.gson.JsonParseException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import lombok.RequiredArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.feed.FeedResult; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @Slf4j -@RequiredArgsConstructor public class FeedClient { private final OkHttpClient client; + private final HttpUrl apiBase; + + @Inject + private FeedClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } public FeedResult lookupFeed() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("feed.js") .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java index ebe607d986..f315f59374 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/feed/FeedPlugin.java @@ -45,9 +45,7 @@ import net.runelite.client.task.Schedule; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ImageUtil; -import net.runelite.http.api.feed.FeedClient; import net.runelite.http.api.feed.FeedResult; -import okhttp3.OkHttpClient; @PluginDescriptor( name = "News Feed", @@ -145,10 +143,4 @@ public class FeedPlugin extends Plugin { return configManager.getConfig(FeedConfig.class); } - - @Provides - FeedClient provideFeedClient(OkHttpClient okHttpClient) - { - return new FeedClient(okHttpClient); - } } diff --git a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeClient.java similarity index 87% rename from http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java rename to runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeClient.java index 1d898ccf27..c50043ea80 100644 --- a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeClient.java @@ -22,16 +22,18 @@ * (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.api.ge; +package net.runelite.client.plugins.grandexchange; import com.google.gson.Gson; import java.io.IOException; import java.util.UUID; -import lombok.RequiredArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import static net.runelite.http.api.RuneLiteAPI.JSON; +import net.runelite.http.api.ge.GrandExchangeTrade; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -41,21 +43,28 @@ import okhttp3.RequestBody; import okhttp3.Response; @Slf4j -@RequiredArgsConstructor public class GrandExchangeClient { private static final Gson GSON = RuneLiteAPI.GSON; private final OkHttpClient client; + private final HttpUrl apiBase; @Setter private UUID uuid; @Setter private String machineId; + @Inject + private GrandExchangeClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } + public void submit(GrandExchangeTrade grandExchangeTrade) { - final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + final HttpUrl url = apiBase.newBuilder() .addPathSegment("ge") .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index 3728bad6dd..63f2c84669 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -100,11 +100,9 @@ import net.runelite.client.util.LinkBrowser; import net.runelite.client.util.OSType; import net.runelite.client.util.QuantityFormatter; import net.runelite.client.util.Text; -import net.runelite.http.api.ge.GrandExchangeClient; import net.runelite.http.api.ge.GrandExchangeTrade; import net.runelite.http.api.item.ItemStats; import net.runelite.http.api.worlds.WorldType; -import okhttp3.OkHttpClient; import org.apache.commons.lang3.time.DurationFormatUtils; import org.apache.commons.text.similarity.FuzzyScore; @@ -259,12 +257,6 @@ public class GrandExchangePlugin extends Plugin return configManager.getConfig(GrandExchangeConfig.class); } - @Provides - GrandExchangeClient provideGrandExchangeClient(OkHttpClient okHttpClient) - { - return new GrandExchangeClient(okHttpClient); - } - @Override protected void startUp() { diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerClient.java similarity index 89% rename from http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java rename to runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerClient.java index 4fc68a6ba5..1f4d99c549 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootTrackerClient.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerClient.java @@ -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.api.loottracker; +package net.runelite.client.plugins.loottracker; import com.google.gson.Gson; import com.google.gson.JsonParseException; @@ -35,12 +35,15 @@ import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import javax.inject.Inject; +import javax.inject.Named; import lombok.Getter; -import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import static net.runelite.http.api.RuneLiteAPI.JSON; +import net.runelite.http.api.loottracker.LootAggregate; +import net.runelite.http.api.loottracker.LootRecord; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -50,21 +53,29 @@ import okhttp3.RequestBody; import okhttp3.Response; @Slf4j -@RequiredArgsConstructor public class LootTrackerClient { private static final Gson GSON = RuneLiteAPI.GSON; private final OkHttpClient client; + private final HttpUrl apiBase; + @Getter @Setter private UUID uuid; + @Inject + private LootTrackerClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } + public CompletableFuture submit(Collection lootRecords) { CompletableFuture future = new CompletableFuture<>(); - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("loottracker") .build(); @@ -107,7 +118,7 @@ public class LootTrackerClient public Collection get() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("loottracker") .build(); @@ -137,7 +148,7 @@ public class LootTrackerClient public void delete(String eventId) { - HttpUrl.Builder builder = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl.Builder builder = apiBase.newBuilder() .addPathSegment("loottracker"); if (eventId != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java index a3d500dc49..654d7db9b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java @@ -65,7 +65,6 @@ import net.runelite.client.util.ImageUtil; import net.runelite.client.util.QuantityFormatter; import net.runelite.client.util.SwingUtil; import net.runelite.http.api.loottracker.LootRecordType; -import net.runelite.http.api.loottracker.LootTrackerClient; class LootTrackerPanel extends PluginPanel { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index b29c67be58..056022045c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -114,8 +114,6 @@ import net.runelite.http.api.loottracker.GameItem; import net.runelite.http.api.loottracker.LootAggregate; import net.runelite.http.api.loottracker.LootRecord; import net.runelite.http.api.loottracker.LootRecordType; -import net.runelite.http.api.loottracker.LootTrackerClient; -import okhttp3.OkHttpClient; import org.apache.commons.text.WordUtils; @PluginDescriptor( @@ -340,12 +338,6 @@ public class LootTrackerPlugin extends Plugin return list; } - @Provides - LootTrackerClient provideLootTrackerClient(OkHttpClient okHttpClient) - { - return new LootTrackerClient(okHttpClient); - } - @Provides LootTrackerConfig provideConfig(ConfigManager configManager) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 3cc468a39d..4722d85d85 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -67,6 +67,7 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.VarbitChanged; import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; @@ -96,7 +97,6 @@ import static net.runelite.client.util.Text.sanitize; import net.runelite.client.ws.PartyMember; import net.runelite.client.ws.PartyService; import net.runelite.client.ws.WSClient; -import net.runelite.http.api.chat.ChatClient; import net.runelite.http.api.chat.LayoutRoom; import net.runelite.http.api.ws.messages.party.PartyChatMessage; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java index 41598f00c4..3b35670873 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java @@ -74,6 +74,7 @@ import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.Notifier; import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; @@ -91,7 +92,6 @@ import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.ColorUtil; import net.runelite.client.util.Text; -import net.runelite.http.api.chat.ChatClient; import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( diff --git a/http-api/src/main/java/net/runelite/http/api/xp/XpClient.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpClient.java similarity index 88% rename from http-api/src/main/java/net/runelite/http/api/xp/XpClient.java rename to runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpClient.java index 76acf6ad63..d07cec417f 100644 --- a/http-api/src/main/java/net/runelite/http/api/xp/XpClient.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpClient.java @@ -22,11 +22,12 @@ * (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.api.xp; +package net.runelite.client.plugins.xptracker; import java.io.IOException; +import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -38,15 +39,18 @@ import okhttp3.Response; public class XpClient { private final OkHttpClient client; + private final HttpUrl apiBase; - public XpClient(OkHttpClient client) + @Inject + private XpClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) { this.client = client; + this.apiBase = apiBase; } public void update(String username) { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("xp") .addPathSegment("update") .addQueryParameter("username", username) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java index 5407226a99..69ff78aa17 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java @@ -69,8 +69,6 @@ import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; -import net.runelite.http.api.xp.XpClient; -import okhttp3.OkHttpClient; @PluginDescriptor( name = "XP Tracker", @@ -139,12 +137,6 @@ public class XpTrackerPlugin extends Plugin return configManager.getConfig(XpTrackerConfig.class); } - @Provides - XpClient provideXpClient(OkHttpClient okHttpClient) - { - return new XpClient(okHttpClient); - } - @Override public void configure(Binder binder) { diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java b/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java similarity index 86% rename from http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java rename to runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java index 1fdf364047..1f494a05f0 100644 --- a/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java @@ -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.api.xtea; +package net.runelite.client.plugins.xtea; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; @@ -31,10 +31,13 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.List; -import lombok.AllArgsConstructor; +import javax.inject.Inject; +import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import static net.runelite.http.api.RuneLiteAPI.JSON; +import net.runelite.http.api.xtea.XteaKey; +import net.runelite.http.api.xtea.XteaRequest; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -44,23 +47,28 @@ import okhttp3.RequestBody; import okhttp3.Response; @Slf4j -@AllArgsConstructor public class XteaClient { private final OkHttpClient client; + private final HttpUrl apiBase; + + @Inject + private XteaClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + { + this.client = client; + this.apiBase = apiBase; + } public void submit(XteaRequest xteaRequest) { - String json = RuneLiteAPI.GSON.toJson(xteaRequest); - - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("xtea") .build(); log.debug("Built URI: {}", url); Request request = new Request.Builder() - .post(RequestBody.create(JSON, json)) + .post(RequestBody.create(JSON, RuneLiteAPI.GSON.toJson(xteaRequest))) .url(url) .build(); @@ -75,7 +83,7 @@ public class XteaClient @Override public void onResponse(Call call, Response response) { - try + try // NOPMD: UseTryWithResources { if (!response.isSuccessful()) { @@ -92,7 +100,7 @@ public class XteaClient public List get() throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("xtea") .build(); @@ -115,7 +123,7 @@ public class XteaClient public XteaKey get(int region) throws IOException { - HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + HttpUrl url = apiBase.newBuilder() .addPathSegment("xtea") .addPathSegment(Integer.toString(region)) .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaPlugin.java index 4eae636114..9fd2df609a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaPlugin.java @@ -24,7 +24,6 @@ */ package net.runelite.client.plugins.xtea; -import com.google.inject.Provides; import java.util.HashSet; import java.util.Set; import javax.inject.Inject; @@ -35,10 +34,8 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.http.api.xtea.XteaClient; import net.runelite.http.api.xtea.XteaKey; import net.runelite.http.api.xtea.XteaRequest; -import okhttp3.OkHttpClient; @PluginDescriptor( name = "Xtea", @@ -55,12 +52,6 @@ public class XteaPlugin extends Plugin @Inject private XteaClient xteaClient; - @Provides - XteaClient provideXteaClient(OkHttpClient okHttpClient) - { - return new XteaClient(okHttpClient); - } - @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { diff --git a/runelite-client/src/main/java/net/runelite/client/rs/WorldSupplier.java b/runelite-client/src/main/java/net/runelite/client/rs/WorldSupplier.java index 16cf8141ad..26b3139a64 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/WorldSupplier.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/WorldSupplier.java @@ -35,9 +35,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import net.runelite.client.RuneLiteProperties; import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldClient; +import net.runelite.client.game.WorldClient; import net.runelite.http.api.worlds.WorldType; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @Slf4j @@ -46,7 +48,7 @@ class WorldSupplier implements Supplier { private final OkHttpClient okHttpClient; private final Random random = new Random(System.nanoTime()); - private Queue worlds = new ArrayDeque<>(); + private final Queue worlds = new ArrayDeque<>(); @Override public World get() @@ -58,7 +60,7 @@ class WorldSupplier implements Supplier try { - List newWorlds = new WorldClient(okHttpClient) + List newWorlds = new WorldClient(okHttpClient, HttpUrl.get(RuneLiteProperties.getApiBase())) .lookupWorlds() .getWorlds() .stream() diff --git a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java index 88fc16abed..41ac088c7d 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Objects; import java.util.UUID; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -40,6 +41,7 @@ import net.runelite.http.api.ws.WebsocketGsonFactory; import net.runelite.http.api.ws.WebsocketMessage; import net.runelite.http.api.ws.messages.Handshake; import net.runelite.http.api.ws.messages.party.PartyMessage; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -52,6 +54,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable { private final EventBus eventBus; private final OkHttpClient okHttpClient; + private final HttpUrl runeliteWs; private final Collection> messages = new HashSet<>(); private volatile Gson gson; @@ -60,10 +63,11 @@ public class WSClient extends WebSocketListener implements AutoCloseable private WebSocket webSocket; @Inject - private WSClient(EventBus eventBus, OkHttpClient okHttpClient) + private WSClient(EventBus eventBus, OkHttpClient okHttpClient, @Named("runelite.ws") HttpUrl runeliteWs) { this.eventBus = eventBus; this.okHttpClient = okHttpClient; + this.runeliteWs = runeliteWs; this.gson = WebsocketGsonFactory.build(WebsocketGsonFactory.factory(messages)); } @@ -101,7 +105,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable } Request request = new Request.Builder() - .url(RuneLiteAPI.getWsEndpoint()) + .url(runeliteWs) .header("User-Agent", RuneLiteAPI.userAgent) .build(); diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index e5f37e2fe7..50b70b6e83 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -12,4 +12,8 @@ runelite.jav_config=https://oldschool.runescape.com/jav_config.ws runelite.jav_config_backup=https://static.runelite.net/jav_config.ws runelite.pluginhub.url=https://repo.runelite.net/plugins runelite.pluginhub.version=${project.version} -runelite.imgur.client.id=30d71e5f6860809 \ No newline at end of file +runelite.imgur.client.id=30d71e5f6860809 +runelite.api.base=https://api.runelite.net/runelite-${project.version} +runelite.session=https://api.runelite.net/session +runelite.static.base=https://static.runelite.net +runelite.ws=https://api.runelite.net/ws \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java index 4f384e83ec..4b46a8844f 100644 --- a/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java @@ -73,6 +73,10 @@ public class ConfigManagerTest @Bind Client client; + @Mock + @Bind + ConfigClient configClient; + @Inject ConfigManager manager; diff --git a/runelite-client/src/test/java/net/runelite/client/hiscore/HiscoreClientTest.java b/runelite-client/src/test/java/net/runelite/client/hiscore/HiscoreClientTest.java index fbc2e7b48f..e0b079e6b8 100644 --- a/runelite-client/src/test/java/net/runelite/client/hiscore/HiscoreClientTest.java +++ b/runelite-client/src/test/java/net/runelite/client/hiscore/HiscoreClientTest.java @@ -25,7 +25,7 @@ package net.runelite.client.hiscore; import java.io.IOException; -import net.runelite.http.api.RuneLiteAPI; +import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import static org.junit.Assert.assertEquals; @@ -132,7 +132,7 @@ public class HiscoreClientTest @Test public void testNormalLookup() throws Exception { - HiscoreClient hiscoreClient = new HiscoreClient(RuneLiteAPI.CLIENT); + HiscoreClient hiscoreClient = new HiscoreClient(new OkHttpClient()); HiscoreResult result = hiscoreClient.lookup("zezima", server.url("/")); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java index 8ac44d3a6a..918732d049 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java @@ -49,17 +49,18 @@ import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetID.ADVENTURE_LOG_ID; import static net.runelite.api.widgets.WidgetID.DIARY_QUEST_GROUP_ID; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ChatColorConfig; import net.runelite.client.config.ConfigManager; import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.game.ItemManager; import net.runelite.client.hiscore.HiscoreClient; import net.runelite.client.hiscore.HiscoreEndpoint; import net.runelite.client.hiscore.HiscoreResult; import net.runelite.client.hiscore.Skill; import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.chat.ChatClient; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; @@ -116,6 +117,10 @@ public class ChatCommandsPluginTest @Bind RuneLiteConfig runeLiteConfig; + @Mock + @Bind + ItemManager itemManager; + @Mock @Bind ChatCommandsConfig chatCommandsConfig; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java index b6139cc265..dd46f28550 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java @@ -51,7 +51,6 @@ import net.runelite.client.input.KeyManager; import net.runelite.client.input.MouseManager; import static net.runelite.client.plugins.grandexchange.GrandExchangePlugin.findFuzzyIndices; import static net.runelite.http.api.RuneLiteAPI.GSON; -import net.runelite.http.api.ge.GrandExchangeClient; import net.runelite.http.api.ge.GrandExchangeTrade; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java index cff8a46591..4f2288a136 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java @@ -61,7 +61,6 @@ import net.runelite.client.game.SpriteManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.http.api.item.ItemPrice; import net.runelite.http.api.loottracker.LootRecordType; -import net.runelite.http.api.loottracker.LootTrackerClient; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.junit.Before; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java index ca13ae0c88..ff8ecbc5a6 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java @@ -31,13 +31,14 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule; import java.util.concurrent.ScheduledExecutorService; import net.runelite.api.Client; import net.runelite.client.Notifier; +import net.runelite.client.chat.ChatClient; import net.runelite.client.config.ChatColorConfig; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.ImageCapture; import net.runelite.client.ws.PartyService; -import net.runelite.http.api.chat.ChatClient; +import net.runelite.client.ws.WSClient; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Before; @@ -79,25 +80,33 @@ public class RaidsPluginTest @Bind ChatClient chatClient; + @Mock + @Bind + InfoBoxManager infoBoxManager; + + @Mock + @Bind + PartyService partyService; + + @Mock + @Bind + OverlayManager overlayManager; + + @Mock + @Bind + WSClient wsClient; + @Mock @Bind RaidsConfig raidsConfig; + @Mock + @Bind + RaidsOverlay raidsOverlay; + @Inject RaidsPlugin raidsPlugin; - @Mock - @Bind - private InfoBoxManager infoBoxManager; - - @Mock - @Bind - private PartyService partyService; - - @Mock - @Bind - private OverlayManager overlayManager; - @Before public void before() { diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java index c9ebfba6f5..fcdc75db13 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java @@ -52,6 +52,7 @@ import net.runelite.api.events.StatChanged; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.Notifier; +import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; @@ -59,7 +60,6 @@ import net.runelite.client.game.ItemManager; import net.runelite.client.game.npcoverlay.NpcOverlayService; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; -import net.runelite.http.api.chat.ChatClient; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; @@ -142,6 +142,10 @@ public class SlayerPluginTest @Bind SlayerOverlay overlay; + @Mock + @Bind + TargetWeaknessOverlay targetWeaknessOverlay; + @Mock @Bind InfoBoxManager infoBoxManager; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java index a8dce5b513..977e379a9a 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java @@ -46,6 +46,7 @@ import net.runelite.client.Notifier; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.ws.PartyService; +import net.runelite.client.ws.WSClient; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,6 +82,10 @@ public class SpecialCounterPluginTest @Bind private Notifier notifier; + @Mock + @Bind + private WSClient wsClient; + @Mock @Bind private SpecialCounterConfig specialCounterConfig; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/xptracker/XpTrackerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/xptracker/XpTrackerPluginTest.java index 64a1cec8e6..9311385e49 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/xptracker/XpTrackerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/xptracker/XpTrackerPluginTest.java @@ -39,7 +39,6 @@ import net.runelite.client.game.NPCManager; import net.runelite.client.game.SkillIconManager; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.http.api.xp.XpClient; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; From 0a501429e6cb72e9873eba94c6060fac26bbe484 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Dec 2021 12:36:05 -0500 Subject: [PATCH 02/34] Move okhttp client from http-api The client has been recreated with a new builder off of the http-api client for awhile anyway since runelite-client has multiple other requirements (caching, tls, etc). This fully moves creation of the okhttp client into both http-service and runelite-client separately. I've kept the CLIENT field in http-api for now since a few external plugins depend on it currently. --- http-api/pom.xml | 40 ------------- .../net/runelite/http/api/RuneLiteAPI.java | 57 +----------------- .../src/main/resources/runelite.properties | 3 - .../runelite/http/api/RuneLiteAPITest.java | 58 ------------------- http-service/pom.xml | 49 ++++++++++++++++ .../service/SpringBootWebApplication.java | 22 ++++++- .../http/service/account/AccountService.java | 5 +- .../src/main/resources/application.yaml | 3 + runelite-client/pom.xml | 26 +++++++++ .../java/net/runelite/client/RuneLite.java | 37 ++++++++---- .../runelite/client/RuneLiteProperties.java | 12 ++++ .../java/net/runelite/client/ws/WSClient.java | 4 +- .../net/runelite/client/runelite.properties | 2 + ...tpCacheSanityTest.java => OkHttpTest.java} | 23 ++++++-- 14 files changed, 162 insertions(+), 179 deletions(-) delete mode 100644 http-api/src/main/resources/runelite.properties delete mode 100644 http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java rename runelite-client/src/test/java/net/runelite/client/{OkHttpCacheSanityTest.java => OkHttpTest.java} (89%) diff --git a/http-api/pom.xml b/http-api/pom.xml index 49bb4a43f0..6f4e9a635e 100644 --- a/http-api/pom.xml +++ b/http-api/pom.xml @@ -34,11 +34,6 @@ Web API http-api - - nogit - false - - com.squareup.okhttp3 @@ -77,39 +72,4 @@ test - - - - - src/main/resources - true - - - - - pl.project13.maven - git-commit-id-plugin - 2.2.6 - - - query-git-info - - revision - - - false - false - - true - - - git.commit.id.abbrev - git.dirty - - - - - - - diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 99c699da51..2cec04c008 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -27,78 +27,25 @@ package net.runelite.http.api; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.awt.Color; -import java.io.IOException; -import java.io.InputStream; import java.time.Instant; -import java.util.Properties; -import java.util.concurrent.TimeUnit; -import lombok.Getter; import net.runelite.http.api.gson.ColorTypeAdapter; import net.runelite.http.api.gson.IllegalReflectionExclusion; import net.runelite.http.api.gson.InstantTypeAdapter; -import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class RuneLiteAPI { - private static final Logger logger = LoggerFactory.getLogger(RuneLiteAPI.class); - public static final String RUNELITE_AUTH = "RUNELITE-AUTH"; public static final String RUNELITE_MACHINEID = "RUNELITE-MACHINEID"; - public static final OkHttpClient CLIENT; + @Deprecated + public static OkHttpClient CLIENT; public static final Gson GSON; public static final MediaType JSON = MediaType.parse("application/json"); - public static String userAgent; - - private static final Properties properties = new Properties(); - @Getter - private static String version; static { - try - { - InputStream in = RuneLiteAPI.class.getResourceAsStream("/runelite.properties"); - properties.load(in); - - version = properties.getProperty("runelite.version"); - String commit = properties.getProperty("runelite.commit"); - boolean dirty = Boolean.parseBoolean(properties.getProperty("runelite.dirty")); - - userAgent = "RuneLite/" + version + "-" + commit + (dirty ? "+" : ""); - } - catch (NumberFormatException e) - { - throw new RuntimeException("Version string has not been substituted; Re-run maven"); - } - catch (IOException ex) - { - logger.error(null, ex); - } - - CLIENT = new OkHttpClient.Builder() - .pingInterval(30, TimeUnit.SECONDS) - .addNetworkInterceptor(new Interceptor() - { - - @Override - public Response intercept(Chain chain) throws IOException - { - Request userAgentRequest = chain.request() - .newBuilder() - .header("User-Agent", userAgent) - .build(); - return chain.proceed(userAgentRequest); - } - }) - .build(); - GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder diff --git a/http-api/src/main/resources/runelite.properties b/http-api/src/main/resources/runelite.properties deleted file mode 100644 index b912fac6ce..0000000000 --- a/http-api/src/main/resources/runelite.properties +++ /dev/null @@ -1,3 +0,0 @@ -runelite.version=${project.version} -runelite.commit=${git.commit.id.abbrev} -runelite.dirty=${git.dirty} \ No newline at end of file diff --git a/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java b/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java deleted file mode 100644 index d1fd3562bd..0000000000 --- a/http-api/src/test/java/net/runelite/http/api/RuneLiteAPITest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.api; - -import java.io.IOException; -import okhttp3.Request; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import static org.junit.Assert.assertTrue; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -public class RuneLiteAPITest -{ - @Rule - public final MockWebServer server = new MockWebServer(); - - @Before - public void before() throws IOException - { - server.enqueue(new MockResponse().setBody("OK")); - } - - @Test - public void testUserAgent() throws IOException, InterruptedException - { - Request request = new Request.Builder() - .url(server.url("/").url()) - .build(); - RuneLiteAPI.CLIENT.newCall(request).execute().close(); - - // rest of UA depends on if git is found - assertTrue(server.takeRequest().getHeader("User-Agent").startsWith("RuneLite/" + RuneLiteAPI.getVersion())); - } -} \ No newline at end of file diff --git a/http-service/pom.xml b/http-service/pom.xml index 15f6992c83..d983f9e9da 100644 --- a/http-service/pom.xml +++ b/http-service/pom.xml @@ -39,6 +39,8 @@ 1.5.6.RELEASE + nogit + false @@ -154,6 +156,13 @@ runelite-${project.version} + + + src/main/resources + true + + + org.apache.maven.plugins @@ -164,6 +173,10 @@ org.springframework.boot spring-boot-maven-plugin ${spring.boot.version} + + + false + com.github.kongchen @@ -215,6 +228,42 @@ + + pl.project13.maven + git-commit-id-plugin + 2.2.6 + + + query-git-info + + revision + + + false + false + + true + + + git.commit.id.abbrev + git.dirty + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + + @ + + false + + diff --git a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java index 6d045b8231..4c425cb0cf 100644 --- a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java +++ b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.time.Instant; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; import javax.naming.NamingException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -39,10 +40,10 @@ import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.service.util.InstantConverter; import okhttp3.Cache; import okhttp3.OkHttpClient; +import okhttp3.Request; import org.slf4j.ILoggerFactory; import org.slf4j.impl.StaticLoggerBinder; import org.springframework.beans.factory.annotation.Qualifier; @@ -200,9 +201,24 @@ public class SpringBootWebApplication extends SpringBootServletInitializer } @Bean - public OkHttpClient okHttpClient() + public OkHttpClient okHttpClient( + @Value("${runelite.version}") String version, + @Value("${runelite.commit}") String commit, + @Value("${runelite.dirty}") boolean dirty + ) { - return RuneLiteAPI.CLIENT; + final String userAgent = "RuneLite/" + version + "-" + commit + (dirty ? "+" : ""); + return new OkHttpClient.Builder() + .pingInterval(30, TimeUnit.SECONDS) + .addNetworkInterceptor(chain -> + { + Request userAgentRequest = chain.request() + .newBuilder() + .header("User-Agent", userAgent) + .build(); + return chain.proceed(userAgentRequest); + }) + .build(); } public static void main(String[] args) diff --git a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java index 4f39ed00e1..10a289b927 100644 --- a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java +++ b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java @@ -98,6 +98,7 @@ public class AccountService private final String oauthClientId; private final String oauthClientSecret; private final String oauthCallback; + private final String runeliteVersion; private final AuthFilter auth; private final RedisPool jedisPool; @@ -107,6 +108,7 @@ public class AccountService @Value("${oauth.client-id}") String oauthClientId, @Value("${oauth.client-secret}") String oauthClientSecret, @Value("${oauth.callback}") String oauthCallback, + @Value("${runelite.version}") String runeliteVersion, AuthFilter auth, RedisPool jedisPool ) @@ -115,6 +117,7 @@ public class AccountService this.oauthClientId = oauthClientId; this.oauthClientSecret = oauthClientSecret; this.oauthCallback = oauthCallback; + this.runeliteVersion = runeliteVersion; this.auth = auth; this.jedisPool = jedisPool; @@ -143,7 +146,7 @@ public class AccountService { State state = new State(); state.setUuid(uuid); - state.setApiVersion(RuneLiteAPI.getVersion()); + state.setApiVersion(runeliteVersion); OAuth20Service service = new ServiceBuilder() .apiKey(oauthClientId) diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml index f77e17ae19..7431545cbb 100644 --- a/http-service/src/main/resources/application.yaml +++ b/http-service/src/main/resources/application.yaml @@ -33,6 +33,9 @@ mongo: database: runelite runelite: + version: @project.version@ + commit: @git.commit.id.abbrev@ + dirty: @git.dirty@ # Twitter client for feed twitter: consumerkey: diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index e2ee15124e..49b8425eeb 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -38,6 +38,8 @@ true true + nogit + false @@ -474,6 +476,30 @@ + + pl.project13.maven + git-commit-id-plugin + 2.2.6 + + + query-git-info + + revision + + + false + false + + true + + + git.commit.id.abbrev + git.dirty + + + + + diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 1d314f44ab..fad5c22eb3 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -44,6 +44,7 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.Locale; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; import javax.annotation.Nullable; import javax.inject.Provider; @@ -80,6 +81,7 @@ import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Cache; import okhttp3.OkHttpClient; +import okhttp3.Request; import okhttp3.Response; import org.slf4j.LoggerFactory; @@ -97,6 +99,7 @@ public class RuneLite public static final File DEFAULT_CONFIG_FILE = new File(RUNELITE_DIR, "settings.properties"); private static final int MAX_OKHTTP_CACHE_SIZE = 20 * 1024 * 1024; // 20mb + public static String USER_AGENT = "RuneLite/" + RuneLiteProperties.getVersion() + "-" + RuneLiteProperties.getCommit() + (RuneLiteProperties.isDirty() ? "+" : ""); @Getter private static Injector injector; @@ -203,16 +206,8 @@ public class RuneLite } }); - OkHttpClient.Builder okHttpClientBuilder = RuneLiteAPI.CLIENT.newBuilder(); - setupCache(okHttpClientBuilder, new File(CACHE_DIR, "okhttp")); - - final boolean insecureSkipTlsVerification = options.has("insecure-skip-tls-verification"); - if (insecureSkipTlsVerification || RuneLiteProperties.isInsecureSkipTlsVerification()) - { - setupInsecureTrustManager(okHttpClientBuilder); - } - - final OkHttpClient okHttpClient = okHttpClientBuilder.build(); + final OkHttpClient okHttpClient = buildHttpClient(options.has("insecure-skip-tls-verification")); + RuneLiteAPI.CLIENT = okHttpClient; SplashScreen.init(); SplashScreen.stage(0, "Retrieving client", ""); @@ -416,9 +411,20 @@ public class RuneLite } @VisibleForTesting - static void setupCache(OkHttpClient.Builder builder, File cacheDir) + static OkHttpClient buildHttpClient(boolean insecureSkipTlsVerification) { - builder.cache(new Cache(cacheDir, MAX_OKHTTP_CACHE_SIZE)) + OkHttpClient.Builder builder = new OkHttpClient.Builder() + .pingInterval(30, TimeUnit.SECONDS) + .addNetworkInterceptor(chain -> + { + Request userAgentRequest = chain.request() + .newBuilder() + .header("User-Agent", USER_AGENT) + .build(); + return chain.proceed(userAgentRequest); + }) + // Setup cache + .cache(new Cache(new File(CACHE_DIR, "okhttp"), MAX_OKHTTP_CACHE_SIZE)) .addNetworkInterceptor(chain -> { // This has to be a network interceptor so it gets hit before the cache tries to store stuff @@ -432,6 +438,13 @@ public class RuneLite } return res; }); + + if (insecureSkipTlsVerification || RuneLiteProperties.isInsecureSkipTlsVerification()) + { + setupInsecureTrustManager(builder); + } + + return builder.build(); } private static void setupInsecureTrustManager(OkHttpClient.Builder okHttpClientBuilder) diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index 1f878b26cc..e598439c2d 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -35,6 +35,8 @@ import okhttp3.HttpUrl; public class RuneLiteProperties { private static final String RUNELITE_VERSION = "runelite.version"; + private static final String RUNELITE_COMMIT = "runelite.commit"; + private static final String RUNELITE_DIRTY = "runelite.dirty"; private static final String DISCORD_INVITE = "runelite.discord.invite"; private static final String LAUNCHER_VERSION_PROPERTY = "runelite.launcher.version"; private static final String INSECURE_SKIP_TLS_VERIFICATION_PROPERTY = "runelite.insecure-skip-tls-verification"; @@ -67,6 +69,16 @@ public class RuneLiteProperties return properties.getProperty(RUNELITE_VERSION); } + public static String getCommit() + { + return properties.getProperty(RUNELITE_COMMIT); + } + + public static boolean isDirty() + { + return Boolean.parseBoolean(properties.getProperty(RUNELITE_DIRTY)); + } + public static String getDiscordInvite() { return properties.getProperty(DISCORD_INVITE); diff --git a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java index 41ac088c7d..ea42605075 100644 --- a/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java +++ b/runelite-client/src/main/java/net/runelite/client/ws/WSClient.java @@ -35,8 +35,8 @@ import javax.inject.Named; import javax.inject.Singleton; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import net.runelite.client.RuneLite; import net.runelite.client.eventbus.EventBus; -import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.ws.WebsocketGsonFactory; import net.runelite.http.api.ws.WebsocketMessage; import net.runelite.http.api.ws.messages.Handshake; @@ -106,7 +106,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable Request request = new Request.Builder() .url(runeliteWs) - .header("User-Agent", RuneLiteAPI.userAgent) + .header("User-Agent", RuneLite.USER_AGENT) .build(); webSocket = okHttpClient.newWebSocket(request, this); diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index 50b70b6e83..8952e01593 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -1,5 +1,7 @@ runelite.title=RuneLite runelite.version=${project.version} +runelite.commit=${git.commit.id.abbrev} +runelite.dirty=${git.dirty} runelite.discord.appid=409416265891971072 runelite.discord.invite=https://discord.gg/ArdAhnN runelite.github.link=https://github.com/runelite diff --git a/runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java b/runelite-client/src/test/java/net/runelite/client/OkHttpTest.java similarity index 89% rename from runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java rename to runelite-client/src/test/java/net/runelite/client/OkHttpTest.java index 2478042ed2..83032c4e5c 100644 --- a/runelite-client/src/test/java/net/runelite/client/OkHttpCacheSanityTest.java +++ b/runelite-client/src/test/java/net/runelite/client/OkHttpTest.java @@ -30,7 +30,6 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Locale; import java.util.concurrent.TimeUnit; -import net.runelite.http.api.RuneLiteAPI; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -38,11 +37,12 @@ import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import org.junit.Assert; +import static org.junit.Assert.assertTrue; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -public class OkHttpCacheSanityTest +public class OkHttpTest { @Rule public TemporaryFolder cacheFolder = new TemporaryFolder(); @@ -71,9 +71,7 @@ public class OkHttpCacheSanityTest @Test public void testCacheSanity() throws IOException, InterruptedException { - OkHttpClient.Builder builder = RuneLiteAPI.CLIENT.newBuilder(); - RuneLite.setupCache(builder, cacheFolder.getRoot()); - OkHttpClient client = builder.build(); + OkHttpClient client = RuneLite.buildHttpClient(false); Instant lastModified = Instant.now().minusSeconds(20); @@ -122,4 +120,19 @@ public class OkHttpCacheSanityTest Assert.assertNotNull("cache did not make a conditional request", req); Assert.assertNotNull(req.getHeader("If-Modified-Since")); } + + @Test + public void testUserAgent() throws IOException, InterruptedException + { + server.enqueue(new MockResponse().setBody("OK")); + + Request request = new Request.Builder() + .url(server.url("/")) + .build(); + RuneLite.buildHttpClient(false) + .newCall(request).execute().close(); + + // rest of UA depends on if git is found + assertTrue(server.takeRequest().getHeader("User-Agent").startsWith("RuneLite/" + RuneLiteProperties.getVersion())); + } } From 055f5c2d2b37e63532f35dc470818723ab0477c3 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 24 Dec 2021 13:19:45 -0500 Subject: [PATCH 03/34] Remove http-api and http-service These are being split into a separate repository at https://github.com/runelite/api.runelite.net --- README.md | 2 - http-api/pom.xml | 75 ---- .../net/runelite/http/api/RuneLiteAPI.java | 66 ---- .../http/api/account/OAuthResponse.java | 35 -- .../net/runelite/http/api/chat/Duels.java | 36 -- .../runelite/http/api/chat/LayoutRoom.java | 50 --- .../java/net/runelite/http/api/chat/Task.java | 36 -- .../runelite/http/api/config/ConfigEntry.java | 38 -- .../http/api/config/Configuration.java | 37 -- .../net/runelite/http/api/feed/FeedItem.java | 42 -- .../runelite/http/api/feed/FeedItemType.java | 32 -- .../runelite/http/api/feed/FeedResult.java | 36 -- .../http/api/ge/GrandExchangeTrade.java | 48 --- .../http/api/gson/ColorTypeAdapter.java | 89 ----- .../api/gson/IllegalReflectionExclusion.java | 71 ---- .../http/api/gson/InstantTypeAdapter.java | 83 ---- .../http/api/item/ItemEquipmentStats.java | 57 --- .../net/runelite/http/api/item/ItemPrice.java | 36 -- .../net/runelite/http/api/item/ItemStats.java | 84 ---- .../net/runelite/http/api/item/ItemType.java | 48 --- .../http/api/loottracker/GameItem.java | 38 -- .../http/api/loottracker/LootAggregate.java | 44 --- .../http/api/loottracker/LootRecord.java | 44 --- .../http/api/loottracker/LootRecordType.java | 34 -- .../net/runelite/http/api/worlds/World.java | 46 --- .../runelite/http/api/worlds/WorldRegion.java | 74 ---- .../runelite/http/api/worlds/WorldResult.java | 54 --- .../runelite/http/api/worlds/WorldType.java | 39 -- .../api/ws/RuntimeTypeAdapterFactory.java | 240 ------------ .../http/api/ws/WebsocketGsonFactory.java | 88 ----- .../http/api/ws/WebsocketMessage.java | 35 -- .../http/api/ws/messages/Handshake.java | 35 -- .../http/api/ws/messages/LoginResponse.java | 37 -- .../http/api/ws/messages/party/Join.java | 38 -- .../http/api/ws/messages/party/Part.java | 31 -- .../ws/messages/party/PartyChatMessage.java | 33 -- .../ws/messages/party/PartyMemberMessage.java | 12 - .../api/ws/messages/party/PartyMessage.java | 35 -- .../http/api/ws/messages/party/UserJoin.java | 39 -- .../http/api/ws/messages/party/UserPart.java | 37 -- .../http/api/ws/messages/party/UserSync.java | 34 -- .../net/runelite/http/api/xtea/XteaKey.java | 34 -- .../runelite/http/api/xtea/XteaRequest.java | 41 -- .../http/api/gson/ColorTypeAdapterTest.java | 58 --- .../http/api/gson/InstantTypeAdapterTest.java | 54 --- http-service/pom.xml | 269 ------------- .../service/SpringBootWebApplication.java | 228 ----------- .../service/SpringSchedulingConfigurer.java | 52 --- .../http/service/SpringWebMvcConfigurer.java | 65 ---- .../http/service/account/AccountService.java | 284 -------------- .../http/service/account/AuthFilter.java | 116 ------ .../runelite/http/service/account/State.java | 35 -- .../http/service/account/UserInfo.java | 46 --- .../service/account/beans/SessionEntry.java | 76 ---- .../http/service/account/beans/UserEntry.java | 57 --- .../runelite/http/service/cache/CacheDAO.java | 123 ------ .../http/service/cache/CacheService.java | 254 ------------ .../service/cache/beans/ArchiveEntry.java | 38 -- .../http/service/cache/beans/CacheEntry.java | 36 -- .../http/service/cache/beans/FileEntry.java | 36 -- .../http/service/cache/beans/IndexEntry.java | 36 -- .../http/service/chat/ChatController.java | 274 ------------- .../http/service/chat/ChatService.java | 263 ------------- .../http/service/chat/KillCountKey.java | 34 -- .../http/service/config/ConfigController.java | 134 ------- .../http/service/config/ConfigService.java | 367 ------------------ .../http/service/feed/FeedController.java | 137 ------- .../http/service/feed/blog/BlogService.java | 143 ------- .../feed/osrsnews/OSRSNewsService.java | 143 ------- .../twitter/TwitterOAuth2TokenResponse.java | 38 -- .../service/feed/twitter/TwitterService.java | 183 --------- .../twitter/TwitterStatusesResponseItem.java | 35 -- .../TwitterStatusesResponseItemUser.java | 38 -- .../service/ge/GrandExchangeController.java | 158 -------- .../http/service/ge/GrandExchangeService.java | 119 ------ .../service/ge/GrandExchangeTradeHistory.java | 38 -- .../net/runelite/http/service/ge/Trade.java | 51 --- .../runelite/http/service/ge/TradeAction.java | 31 -- .../runelite/http/service/ge/TradeEntry.java | 40 -- .../http/service/item/ItemController.java | 113 ------ .../runelite/http/service/item/ItemEntry.java | 39 -- .../http/service/item/ItemService.java | 287 -------------- .../http/service/item/PriceEntry.java | 40 -- .../runelite/http/service/item/RSItem.java | 36 -- .../http/service/item/RSItemResponse.java | 33 -- .../runelite/http/service/item/RSPrices.java | 37 -- .../http/service/loottracker/LootResult.java | 42 -- .../loottracker/LootTrackerController.java | 118 ------ .../loottracker/LootTrackerService.java | 259 ------------ .../pluginhub/PluginHubController.java | 144 ------- .../http/service/util/InstantConverter.java | 48 --- .../InternalServerErrorException.java | 38 -- .../util/exception/NotFoundException.java | 35 -- .../http/service/util/redis/RedisPool.java | 102 ----- .../http/service/wiki/PriceResult.java | 44 --- .../http/service/wiki/WikiPriceService.java | 140 ------- .../http/service/worlds/ServiceWorldType.java | 60 --- .../http/service/worlds/WorldController.java | 68 ---- .../http/service/worlds/WorldsService.java | 132 ------- .../runelite/http/service/xtea/XteaCache.java | 39 -- .../http/service/xtea/XteaController.java | 86 ---- .../runelite/http/service/xtea/XteaEntry.java | 40 -- .../http/service/xtea/XteaService.java | 250 ------------ .../src/main/resources/application-dev.yaml | 29 -- .../src/main/resources/application.yaml | 61 --- http-service/src/main/templates/markdown.hbs | 110 ------ http-service/src/main/templates/operation.hbs | 71 ---- http-service/src/main/templates/security.hbs | 88 ----- .../src/main/templates/template.html.hbs | 49 --- http-service/src/main/webapp/WEB-INF/web.xml | 32 -- .../service/config/ConfigControllerTest.java | 85 ---- .../service/config/ConfigServiceTest.java | 72 ---- .../LootTrackerControllerTest.java | 104 ----- .../service/worlds/WorldsServiceTest.java | 79 ---- .../src/test/resources/application-test.yaml | 21 - .../runelite/http/service/worlds/worldlist | Bin 5000 -> 0 bytes pom.xml | 2 - runelite-client/pom.xml | 4 +- 118 files changed, 2 insertions(+), 9267 deletions(-) delete mode 100644 http-api/pom.xml delete mode 100644 http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/chat/Duels.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/chat/Task.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/config/Configuration.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemStats.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemType.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/World.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java delete mode 100644 http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java delete mode 100644 http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java delete mode 100644 http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java delete mode 100644 http-service/pom.xml delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/AccountService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/State.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/UserInfo.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/FeedController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/Trade.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItem.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSPrices.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java delete mode 100644 http-service/src/main/resources/application-dev.yaml delete mode 100644 http-service/src/main/resources/application.yaml delete mode 100644 http-service/src/main/templates/markdown.hbs delete mode 100644 http-service/src/main/templates/operation.hbs delete mode 100644 http-service/src/main/templates/security.hbs delete mode 100644 http-service/src/main/templates/template.html.hbs delete mode 100644 http-service/src/main/webapp/WEB-INF/web.xml delete mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java delete mode 100644 http-service/src/test/resources/application-test.yaml delete mode 100644 http-service/src/test/resources/net/runelite/http/service/worlds/worldlist diff --git a/README.md b/README.md index 04a036953b..26abeb39f5 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,6 @@ If you have any questions, please join our IRC channel on [irc.rizon.net #runeli ## Project Layout - [cache](cache/src/main/java/net/runelite/cache) - Libraries used for reading/writing cache files, as well as the data in it -- [http-api](http-api/src/main/java/net/runelite/http/api) - API for api.runelite.net -- [http-service](http-service/src/main/java/net/runelite/http/service) - Service for api.runelite.net - [runelite-api](runelite-api/src/main/java/net/runelite/api) - RuneLite API, interfaces for accessing the client - [runelite-client](runelite-client/src/main/java/net/runelite/client) - Game client with plugins diff --git a/http-api/pom.xml b/http-api/pom.xml deleted file mode 100644 index 6f4e9a635e..0000000000 --- a/http-api/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - 4.0.0 - - net.runelite - runelite-parent - 1.8.8-SNAPSHOT - - - Web API - http-api - - - - com.squareup.okhttp3 - okhttp - 3.14.9 - - - com.google.code.gson - gson - - - org.slf4j - slf4j-api - - - org.projectlombok - lombok - provided - - - - junit - junit - 4.12 - test - - - org.slf4j - slf4j-simple - test - - - com.squareup.okhttp3 - mockwebserver - 3.14.9 - test - - - diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java deleted file mode 100644 index 2cec04c008..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import java.awt.Color; -import java.time.Instant; -import net.runelite.http.api.gson.ColorTypeAdapter; -import net.runelite.http.api.gson.IllegalReflectionExclusion; -import net.runelite.http.api.gson.InstantTypeAdapter; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; - -public class RuneLiteAPI -{ - public static final String RUNELITE_AUTH = "RUNELITE-AUTH"; - public static final String RUNELITE_MACHINEID = "RUNELITE-MACHINEID"; - - @Deprecated - public static OkHttpClient CLIENT; - public static final Gson GSON; - public static final MediaType JSON = MediaType.parse("application/json"); - - static - { - GsonBuilder gsonBuilder = new GsonBuilder(); - - gsonBuilder - .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) - .registerTypeAdapter(Color.class, new ColorTypeAdapter()); - - boolean assertionsEnabled = false; - assert assertionsEnabled = true; - if (assertionsEnabled) - { - IllegalReflectionExclusion jbe = new IllegalReflectionExclusion(); - gsonBuilder.addSerializationExclusionStrategy(jbe); - gsonBuilder.addDeserializationExclusionStrategy(jbe); - } - - GSON = gsonBuilder.create(); - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java b/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java deleted file mode 100644 index 930540b6eb..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.account; - -import java.util.UUID; -import lombok.Data; - -@Data -public class OAuthResponse -{ - private String oauthUrl; - private UUID uid; -} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/Duels.java b/http-api/src/main/java/net/runelite/http/api/chat/Duels.java deleted file mode 100644 index ba117a526a..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/chat/Duels.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.api.chat; - -import lombok.Data; - -@Data -public class Duels -{ - private int wins; - private int losses; - private int winningStreak; - private int losingStreak; -} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java b/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java deleted file mode 100644 index 3498f83eed..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.api.chat; - -public enum LayoutRoom -{ - START, - END, - SCAVENGERS, - FARMING, - EMPTY, - - TEKTON, - MUTTADILES, - GUARDIANS, - VESPULA, - SHAMANS, - VASA, - VANGUARDS, - MYSTICS, - UNKNOWN_COMBAT, - - CRABS, - ICE_DEMON, - TIGHTROPE, - THIEVING, - UNKNOWN_PUZZLE; -} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/Task.java b/http-api/src/main/java/net/runelite/http/api/chat/Task.java deleted file mode 100644 index db38c90109..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/chat/Task.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.api.chat; - -import lombok.Data; - -@Data -public class Task -{ - private String task; - private int amount; - private int initialAmount; - private String location; -} diff --git a/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java b/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java deleted file mode 100644 index d8b69dae72..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.config; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ConfigEntry -{ - private String key; - private String value; -} diff --git a/http-api/src/main/java/net/runelite/http/api/config/Configuration.java b/http-api/src/main/java/net/runelite/http/api/config/Configuration.java deleted file mode 100644 index 44269b735a..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/config/Configuration.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.config; - -import java.util.ArrayList; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class Configuration -{ - private List config = new ArrayList<>(); -} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java deleted file mode 100644 index 620f639d15..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.api.feed; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.RequiredArgsConstructor; - -@Data -@RequiredArgsConstructor -@AllArgsConstructor -public class FeedItem -{ - private final FeedItemType type; - private String avatar; - private final String title; - private final String content; - private final String url; - private final long timestamp; -} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java deleted file mode 100644 index e3cc9443cd..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.api.feed; - -public enum FeedItemType -{ - BLOG_POST, - TWEET, - OSRS_NEWS -} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java deleted file mode 100644 index cf862b5be0..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.api.feed; - -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class FeedResult -{ - private List items; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java deleted file mode 100644 index fd6f6635d3..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.api.ge; - -import java.time.Instant; -import lombok.Data; -import net.runelite.http.api.worlds.WorldType; - -@Data -public class GrandExchangeTrade -{ - private boolean buy; - private boolean cancel; - private boolean login; - private int itemId; - private int qty; - private int dqty; - private int total; - private int spent; - private int dspent; - private int offer; - private int slot; - private WorldType worldType; - private int seq; - private Instant resetTime; -} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java deleted file mode 100644 index feec0f6d66..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2020 Abex - * 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.api.gson; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.awt.Color; -import java.io.IOException; - -public class ColorTypeAdapter extends TypeAdapter -{ - @Override - public void write(JsonWriter out, Color value) throws IOException - { - if (value == null) - { - out.nullValue(); - return; - } - - int rgba = value.getRGB(); - out.value(String.format("#%08X", rgba)); - } - - @Override - public Color read(JsonReader in) throws IOException - { - switch (in.peek()) - { - case NULL: - in.nextNull(); - return null; - case STRING: - { - String value = in.nextString(); - if (value.charAt(0) == '#') - { - value = value.substring(1); - } - int intValue = Integer.parseUnsignedInt(value, 16); - return new Color(intValue, true); - } - case BEGIN_OBJECT: - { - in.beginObject(); - double value = 0; - while (in.peek() != JsonToken.END_OBJECT) - { - switch (in.nextName()) - { - case "value": - value = in.nextDouble(); - break; - default: - in.skipValue(); - break; - } - } - in.endObject(); - return new Color((int) value, true); - } - } - return null; // throws - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java b/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java deleted file mode 100644 index a25ffb79f7..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2020 Abex - * 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.api.gson; - -import com.google.gson.ExclusionStrategy; -import com.google.gson.FieldAttributes; -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.Set; - -public class IllegalReflectionExclusion implements ExclusionStrategy -{ - private static final Set PRIVATE_CLASSLOADERS = new HashSet<>(); - - static - { - for (ClassLoader cl = ClassLoader.getSystemClassLoader(); cl != null; ) - { - cl = cl.getParent(); - PRIVATE_CLASSLOADERS.add(cl); - } - } - - @Override - public boolean shouldSkipField(FieldAttributes f) - { - if (!PRIVATE_CLASSLOADERS.contains(f.getDeclaringClass().getClassLoader())) - { - return false; - } - - assert !Modifier.isPrivate(f.getDeclaringClass().getModifiers()) : "gsoning private class " + f.getDeclaringClass().getName(); - try - { - f.getDeclaringClass().getField(f.getName()); - } - catch (NoSuchFieldException e) - { - throw new AssertionError("gsoning private field " + f.getDeclaringClass() + "." + f.getName()); - } - return false; - } - - @Override - public boolean shouldSkipClass(Class clazz) - { - return false; - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java deleted file mode 100644 index d5162c0e01..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020 Abex - * 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.api.gson; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; -import java.time.Instant; - -// Just add water! -public class InstantTypeAdapter extends TypeAdapter -{ - @Override - public void write(JsonWriter out, Instant value) throws IOException - { - if (value == null) - { - out.nullValue(); - return; - } - - out.value(value.toEpochMilli()); - } - - @Override - public Instant read(JsonReader in) throws IOException - { - if (in.peek() == JsonToken.NULL) - { - in.nextNull(); - return null; - } - - if (in.peek() == JsonToken.NUMBER) - { - long jsTime = in.nextLong(); - return Instant.ofEpochMilli(jsTime); - } - - long seconds = 0; - int nanos = 0; - in.beginObject(); - while (in.peek() != JsonToken.END_OBJECT) - { - switch (in.nextName()) - { - case "nanos": - nanos = in.nextInt(); - break; - case "seconds": - seconds = in.nextLong(); - break; - } - } - in.endObject(); - - return Instant.ofEpochSecond(seconds, nanos); - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java b/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java deleted file mode 100644 index 5848513c00..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.item; - -import com.google.gson.annotations.SerializedName; -import lombok.Builder; -import lombok.Value; - -@Value -@Builder -public class ItemEquipmentStats -{ - private int slot; - - @SerializedName("is2h") - private boolean isTwoHanded; - - private int astab; - private int aslash; - private int acrush; - private int amagic; - private int arange; - - private int dstab; - private int dslash; - private int dcrush; - private int dmagic; - private int drange; - - private int str; - private int rstr; - private int mdmg; - private int prayer; - private int aspeed; -} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java b/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java deleted file mode 100644 index faf5bfc3fb..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.item; - -import lombok.Data; - -@Data -public class ItemPrice -{ - private int id; - private String name; - private int price; - private int wikiPrice; -} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java b/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java deleted file mode 100644 index 5b86dd336d..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.item; - -import com.google.gson.annotations.SerializedName; -import lombok.Value; - -@Value -public class ItemStats -{ - private boolean equipable; - private double weight; - @SerializedName("ge_limit") - private int geLimit; - - private ItemEquipmentStats equipment; - - public ItemStats subtract(ItemStats other) - { - if (other == null) - { - return this; - } - - final double newWeight = weight - other.weight; - final ItemEquipmentStats newEquipment; - - - if (other.equipment != null) - { - final ItemEquipmentStats equipment = this.equipment != null - ? this.equipment - : new ItemEquipmentStats.ItemEquipmentStatsBuilder().build(); - - newEquipment = new ItemEquipmentStats.ItemEquipmentStatsBuilder() - .slot(equipment.getSlot()) - .astab(equipment.getAstab() - other.equipment.getAstab()) - .aslash(equipment.getAslash() - other.equipment.getAslash()) - .acrush(equipment.getAcrush() - other.equipment.getAcrush()) - .amagic(equipment.getAmagic() - other.equipment.getAmagic()) - .arange(equipment.getArange() - other.equipment.getArange()) - .dstab(equipment.getDstab() - other.equipment.getDstab()) - .dslash(equipment.getDslash() - other.equipment.getDslash()) - .dcrush(equipment.getDcrush() - other.equipment.getDcrush()) - .dmagic(equipment.getDmagic() - other.equipment.getDmagic()) - .drange(equipment.getDrange() - other.equipment.getDrange()) - .str(equipment.getStr() - other.equipment.getStr()) - .rstr(equipment.getRstr() - other.equipment.getRstr()) - .mdmg(equipment.getMdmg() - other.equipment.getMdmg()) - .prayer(equipment.getPrayer() - other.equipment.getPrayer()) - .aspeed(equipment.getAspeed() - other.equipment.getAspeed()) - .build(); - } - else - { - newEquipment = equipment; - } - - return new ItemStats(equipable, newWeight, 0, newEquipment); - } -} - diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemType.java b/http-api/src/main/java/net/runelite/http/api/item/ItemType.java deleted file mode 100644 index 9221f096b2..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemType.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.item; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public enum ItemType -{ - DEFAULT; - - private static final Logger logger = LoggerFactory.getLogger(ItemType.class); - - public static ItemType of(String type) - { - try - { - return ItemType.valueOf(type.toUpperCase()); - } - catch (IllegalArgumentException ex) - { - logger.warn("unable to convert type", ex); - return DEFAULT; - } - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java b/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java deleted file mode 100644 index 7e9b06c21b..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * 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.api.loottracker; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class GameItem -{ - private int id; - private int qty; -} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java deleted file mode 100644 index a5437226cc..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.api.loottracker; - -import java.time.Instant; -import java.util.Collection; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class LootAggregate -{ - private String eventId; - private LootRecordType type; - private Collection drops; - private Instant first_time; - private Instant last_time; - private int amount; -} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java deleted file mode 100644 index a8e04aefd3..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * 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.api.loottracker; - -import java.time.Instant; -import java.util.Collection; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class LootRecord -{ - private String eventId; - private LootRecordType type; - private Object metadata; - private Collection drops; - private Instant time; - private Integer world; -} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java deleted file mode 100644 index 33e622de45..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * 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.api.loottracker; - -public enum LootRecordType -{ - NPC, - PLAYER, - EVENT, - PICKPOCKET, - UNKNOWN -} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/World.java b/http-api/src/main/java/net/runelite/http/api/worlds/World.java deleted file mode 100644 index 70bc2c8237..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/worlds/World.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.worlds; - -import java.util.EnumSet; -import lombok.Builder; -import lombok.Value; - -@Value -@Builder -public class World -{ - private int id; - private EnumSet types; - private String address; - private String activity; - private int location; - private int players; - - public WorldRegion getRegion() - { - return WorldRegion.valueOf(location); - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java deleted file mode 100644 index 2c391e91f4..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2020, melky - * 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.api.worlds; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * Holds the data for each world's region (location) - */ -@AllArgsConstructor -@Getter -public enum WorldRegion -{ - UNITED_STATES_OF_AMERICA("US", "USA"), - UNITED_KINGDOM("GB", "GBR"), - AUSTRALIA("AU", "AUS"), - GERMANY("DE", "DEU"); - - /** - * ISO-3166-1 alpha-2 country code - */ - private final String alpha2; - /** - * ISO-3166-1 alpha-3 country code - */ - private final String alpha3; - - /** - * Gets the region using the location id - * {@link WorldRegion} value. - * - * @param locationId the location id of world - * @return WorldRegion the region of the world - */ - public static WorldRegion valueOf(int locationId) - { - switch (locationId) - { - case 0: - return UNITED_STATES_OF_AMERICA; - case 1: - return UNITED_KINGDOM; - case 3: - return AUSTRALIA; - case 7: - return GERMANY; - default: - return null; - } - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java deleted file mode 100644 index a4afe23e85..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.worlds; - -import java.util.List; - -public class WorldResult -{ - private List worlds; - - public List getWorlds() - { - return worlds; - } - - public void setWorlds(List worlds) - { - this.worlds = worlds; - } - - public World findWorld(int worldNum) - { - for (World world : worlds) - { - if (world.getId() == worldNum) - { - return world; - } - } - return null; - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java deleted file mode 100644 index 20639b5f3c..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.api.worlds; - -public enum WorldType -{ - MEMBERS, - PVP, - BOUNTY, - SKILL_TOTAL, - HIGH_RISK, - LAST_MAN_STANDING, - NOSAVE_MODE, - DEADMAN, - TOURNAMENT, - SEASONAL; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java deleted file mode 100644 index 2819c92ceb..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.runelite.http.api.ws; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.internal.Streams; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -/** - * Adapts values whose runtime type may differ from their declaration type. This - * is necessary when a field's type is not the same type that GSON should create - * when deserializing that field. For example, consider these types: - *
   {@code
- *   abstract class Shape {
- *     int x;
- *     int y;
- *   }
- *   class Circle extends Shape {
- *     int radius;
- *   }
- *   class Rectangle extends Shape {
- *     int width;
- *     int height;
- *   }
- *   class Diamond extends Shape {
- *     int width;
- *     int height;
- *   }
- *   class Drawing {
- *     Shape bottomShape;
- *     Shape topShape;
- *   }
- * }
- *

Without additional type information, the serialized JSON is ambiguous. Is - * the bottom shape in this drawing a rectangle or a diamond?

   {@code
- *   {
- *     "bottomShape": {
- *       "width": 10,
- *       "height": 5,
- *       "x": 0,
- *       "y": 0
- *     },
- *     "topShape": {
- *       "radius": 2,
- *       "x": 4,
- *       "y": 1
- *     }
- *   }}
- * This class addresses this problem by adding type information to the - * serialized JSON and honoring that type information when the JSON is - * deserialized:
   {@code
- *   {
- *     "bottomShape": {
- *       "type": "Diamond",
- *       "width": 10,
- *       "height": 5,
- *       "x": 0,
- *       "y": 0
- *     },
- *     "topShape": {
- *       "type": "Circle",
- *       "radius": 2,
- *       "x": 4,
- *       "y": 1
- *     }
- *   }}
- * Both the type field name ({@code "type"}) and the type labels ({@code - * "Rectangle"}) are configurable. - * - *

Registering Types

- * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field - * name to the {@link #of} factory method. If you don't supply an explicit type - * field name, {@code "type"} will be used.
   {@code
- *   RuntimeTypeAdapterFactory shapeAdapterFactory
- *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
- * }
- * Next register all of your subtypes. Every subtype must be explicitly - * registered. This protects your application from injection attacks. If you - * don't supply an explicit type label, the type's simple name will be used. - *
   {@code
- *   shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
- *   shapeAdapter.registerSubtype(Circle.class, "Circle");
- *   shapeAdapter.registerSubtype(Diamond.class, "Diamond");
- * }
- * Finally, register the type adapter factory in your application's GSON builder: - *
   {@code
- *   Gson gson = new GsonBuilder()
- *       .registerTypeAdapterFactory(shapeAdapterFactory)
- *       .create();
- * }
- * Like {@code GsonBuilder}, this API supports chaining:
   {@code
- *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
- *       .registerSubtype(Rectangle.class)
- *       .registerSubtype(Circle.class)
- *       .registerSubtype(Diamond.class);
- * }
- */ -public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { - private final Class baseType; - private final String typeFieldName; - private final Map> labelToSubtype = new LinkedHashMap>(); - private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); - - private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { - if (typeFieldName == null || baseType == null) { - throw new NullPointerException(); - } - this.baseType = baseType; - this.typeFieldName = typeFieldName; - } - - /** - * Creates a new runtime type adapter using for {@code baseType} using {@code - * typeFieldName} as the type field name. Type field names are case sensitive. - */ - public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { - return new RuntimeTypeAdapterFactory(baseType, typeFieldName); - } - - /** - * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as - * the type field name. - */ - public static RuntimeTypeAdapterFactory of(Class baseType) { - return new RuntimeTypeAdapterFactory(baseType, "type"); - } - - /** - * Registers {@code type} identified by {@code label}. Labels are case - * sensitive. - * - * @throws IllegalArgumentException if either {@code type} or {@code label} - * have already been registered on this type adapter. - */ - public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { - if (type == null || label == null) { - throw new NullPointerException(); - } - if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { - throw new IllegalArgumentException("types and labels must be unique"); - } - labelToSubtype.put(label, type); - subtypeToLabel.put(type, label); - return this; - } - - /** - * Registers {@code type} identified by its {@link Class#getSimpleName simple - * name}. Labels are case sensitive. - * - * @throws IllegalArgumentException if either {@code type} or its simple name - * have already been registered on this type adapter. - */ - public RuntimeTypeAdapterFactory registerSubtype(Class type) { - return registerSubtype(type, type.getSimpleName()); - } - - public TypeAdapter create(Gson gson, TypeToken type) { - if (type.getRawType() != baseType) { - return null; - } - - final Map> labelToDelegate - = new LinkedHashMap>(); - final Map, TypeAdapter> subtypeToDelegate - = new LinkedHashMap, TypeAdapter>(); - for (Map.Entry> entry : labelToSubtype.entrySet()) { - TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); - labelToDelegate.put(entry.getKey(), delegate); - subtypeToDelegate.put(entry.getValue(), delegate); - } - - return new TypeAdapter() { - @Override public R read(JsonReader in) throws IOException { - JsonElement jsonElement = Streams.parse(in); - JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); - if (labelJsonElement == null) { - throw new JsonParseException("cannot deserialize " + baseType - + " because it does not define a field named " + typeFieldName); - } - String label = labelJsonElement.getAsString(); - @SuppressWarnings("unchecked") // registration requires that subtype extends T - TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); - if (delegate == null) { - throw new JsonParseException("cannot deserialize " + baseType + " subtype named " - + label + "; did you forget to register a subtype?"); - } - return delegate.fromJsonTree(jsonElement); - } - - @Override public void write(JsonWriter out, R value) throws IOException { - Class srcType = value.getClass(); - String label = subtypeToLabel.get(srcType); - @SuppressWarnings("unchecked") // registration requires that subtype extends T - TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); - if (delegate == null) { - throw new JsonParseException("cannot serialize " + srcType.getName() - + "; did you forget to register a subtype?"); - } - JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); - if (jsonObject.has(typeFieldName)) { - throw new JsonParseException("cannot serialize " + srcType.getName() - + " because it already defines a field named " + typeFieldName); - } - JsonObject clone = new JsonObject(); - clone.add(typeFieldName, new JsonPrimitive(label)); - for (Map.Entry e : jsonObject.entrySet()) { - clone.add(e.getKey(), e.getValue()); - } - Streams.write(clone, out); - } - }.nullSafe(); - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java deleted file mode 100644 index 328d0aa1a7..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.ws; - -import com.google.gson.Gson; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.ws.messages.Handshake; -import net.runelite.http.api.ws.messages.LoginResponse; -import net.runelite.http.api.ws.messages.party.Join; -import net.runelite.http.api.ws.messages.party.Part; -import net.runelite.http.api.ws.messages.party.PartyChatMessage; -import net.runelite.http.api.ws.messages.party.UserJoin; -import net.runelite.http.api.ws.messages.party.UserPart; -import net.runelite.http.api.ws.messages.party.UserSync; - -public class WebsocketGsonFactory -{ - private static final Collection> MESSAGES; - - static - { - final List> messages = new ArrayList<>(); - messages.add(Handshake.class); - messages.add(LoginResponse.class); - messages.add(Join.class); - messages.add(Part.class); - messages.add(UserJoin.class); - messages.add(UserPart.class); - messages.add(UserSync.class); - messages.add(PartyChatMessage.class); - MESSAGES = messages; - } - - public static RuntimeTypeAdapterFactory factory(final Collection> messages) - { - final RuntimeTypeAdapterFactory factory = RuntimeTypeAdapterFactory.of(WebsocketMessage.class); - - for (Class message : MESSAGES) - { - factory.registerSubtype(message); - } - - for (Class message : messages) - { - factory.registerSubtype(message); - } - - return factory; - } - - public static Gson build(final RuntimeTypeAdapterFactory factory) - { - return RuneLiteAPI.GSON.newBuilder() - .registerTypeAdapterFactory(factory) - .create(); - } - - public static Gson build() - { - return build(factory(Collections.emptyList())); - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java deleted file mode 100644 index d732c110cd..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.ws; - -public class WebsocketMessage -{ - protected boolean _party; - - public boolean isParty() - { - return _party; - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java deleted file mode 100644 index 5320c95ab5..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.ws.messages; - -import java.util.UUID; -import lombok.Data; -import net.runelite.http.api.ws.WebsocketMessage; - -@Data -public class Handshake extends WebsocketMessage -{ - private UUID session; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java deleted file mode 100644 index 8f22db8f80..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.ws.messages; - -import lombok.Data; -import net.runelite.http.api.ws.WebsocketMessage; - -/** - * Called after a successful login to the server - */ -@Data -public class LoginResponse extends WebsocketMessage -{ - private String username; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java deleted file mode 100644 index 21aed0f653..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import java.util.UUID; -import lombok.EqualsAndHashCode; -import lombok.Value; -import net.runelite.http.api.ws.WebsocketMessage; - -@Value -@EqualsAndHashCode(callSuper = true) -public class Join extends WebsocketMessage -{ - private final UUID partyId; - private final String name; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java deleted file mode 100644 index e284ff0cf8..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import net.runelite.http.api.ws.WebsocketMessage; - -public class Part extends WebsocketMessage -{ -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java deleted file mode 100644 index 480e2660c1..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2019, Tomas Slusny - * 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.api.ws.messages.party; - -import lombok.Value; - -@Value -public class PartyChatMessage extends PartyMemberMessage -{ - private final String value; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java deleted file mode 100644 index 9d5cab8545..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.runelite.http.api.ws.messages.party; - -import java.util.UUID; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public abstract class PartyMemberMessage extends PartyMessage -{ - private UUID memberId; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java deleted file mode 100644 index 709457ed8c..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import net.runelite.http.api.ws.WebsocketMessage; - -public abstract class PartyMessage extends WebsocketMessage -{ - public PartyMessage() - { - _party = true; - } -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java deleted file mode 100644 index 7f940e8060..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import java.util.UUID; -import lombok.EqualsAndHashCode; -import lombok.Value; -import net.runelite.http.api.ws.WebsocketMessage; - -@Value -@EqualsAndHashCode(callSuper = true) -public class UserJoin extends WebsocketMessage -{ - private final UUID memberId; - private final UUID partyId; - private final String name; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java deleted file mode 100644 index e80c6002bd..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import java.util.UUID; -import lombok.EqualsAndHashCode; -import lombok.Value; -import net.runelite.http.api.ws.WebsocketMessage; - -@Value -@EqualsAndHashCode(callSuper = true) -public class UserPart extends WebsocketMessage -{ - private final UUID memberId; -} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java deleted file mode 100644 index c95038c9fa..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.api.ws.messages.party; - -import lombok.EqualsAndHashCode; -import lombok.Value; - -@Value -@EqualsAndHashCode(callSuper = true) -public class UserSync extends PartyMemberMessage -{ -} diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java deleted file mode 100644 index bed2a017f1..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.xtea; - -import lombok.Data; - -@Data -public class XteaKey -{ - private int region; - private int keys[]; -} diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java deleted file mode 100644 index fdce607f59..0000000000 --- a/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.api.xtea; - -import java.util.ArrayList; -import java.util.List; -import lombok.Data; - -@Data -public class XteaRequest -{ - private int revision; - private List keys = new ArrayList<>(); - - public void addKey(XteaKey key) - { - keys.add(key); - } -} diff --git a/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java deleted file mode 100644 index 0fe0b2226a..0000000000 --- a/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021 Abex - * 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.api.gson; - -import java.awt.Color; -import net.runelite.http.api.RuneLiteAPI; -import org.junit.Assert; -import org.junit.Test; - -public class ColorTypeAdapterTest -{ - @Test - public void test() - { - test("null", null, true); - test("{\"value\":-13347208,\"falpha\":0.0}", new Color(0x12345678, false), false); - test("{\"value\":305419896,\"falpha\":0.0}", new Color(0x12345678, true), false); - test("{\"value\":-1.4221317E7,\"falpha\":0.0}", new Color(0xFF26FFFB, true), false); - test("\"#FF345678\"", new Color(0x12345678, false), true); - test("\"#12345678\"", new Color(0x12345678, true), true); - test("\"#FF26FFFB\"", new Color(0xFF26FFFB, true), true); - } - - private void test(String json, Color object, boolean exactEncoding) - { - Color parsed = RuneLiteAPI.GSON.fromJson(json, Color.class); - Assert.assertEquals(object, parsed); - String serialized = RuneLiteAPI.GSON.toJson(object); - if (exactEncoding) - { - Assert.assertEquals(json, serialized); - } - Color roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Color.class); - Assert.assertEquals(object, roundTripped); - } -} \ No newline at end of file diff --git a/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java deleted file mode 100644 index f9ed850843..0000000000 --- a/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021 Abex - * 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.api.gson; - -import java.time.Instant; -import net.runelite.http.api.RuneLiteAPI; -import org.junit.Assert; -import org.junit.Test; - -public class InstantTypeAdapterTest -{ - @Test - public void test() - { - test("null", null, true); - test("{\"seconds\":1609538310,\"nanos\":291000000}", Instant.ofEpochSecond(1609538310, 291_000_000), false); - test("1609538310291", Instant.ofEpochSecond(1609538310, 291_000_000), true); - } - - private void test(String json, Instant object, boolean exactEncoding) - { - Instant parsed = RuneLiteAPI.GSON.fromJson(json, Instant.class); - Assert.assertEquals(object, parsed); - String serialized = RuneLiteAPI.GSON.toJson(object); - if (exactEncoding) - { - Assert.assertEquals(json, serialized); - } - Instant roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Instant.class); - Assert.assertEquals(object, roundTripped); - } -} \ No newline at end of file diff --git a/http-service/pom.xml b/http-service/pom.xml deleted file mode 100644 index d983f9e9da..0000000000 --- a/http-service/pom.xml +++ /dev/null @@ -1,269 +0,0 @@ - - - - 4.0.0 - - - net.runelite - runelite-parent - 1.8.8-SNAPSHOT - - - Web Service - http-service - war - - - 1.5.6.RELEASE - nogit - false - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-devtools - true - - - org.springframework - spring-jdbc - - - - org.projectlombok - lombok - provided - - - - net.runelite - http-api - ${project.version} - - - net.runelite - cache - ${project.version} - - - - org.mariadb.jdbc - mariadb-java-client - 2.2.3 - provided - - - org.sql2o - sql2o - 1.5.4 - - - com.google.guava - guava - - - com.github.scribejava - scribejava-apis - 4.1.0 - - - io.minio - minio - 3.0.6 - - - redis.clients - jedis - 2.10.0 - - - org.apache.commons - commons-pool2 - - - - - org.mongodb - mongodb-driver-sync - 3.10.2 - provided - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.squareup.okhttp3 - mockwebserver - 3.14.9 - test - - - com.h2database - h2 - test - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - runelite-${project.version} - - - - src/main/resources - true - - - - - - org.apache.maven.plugins - maven-war-plugin - 3.3.1 - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - false - - - - com.github.kongchen - swagger-maven-plugin - 3.1.8 - - - - javax.xml.bind - jaxb-api - 2.3.1 - - - - - - true - - net.runelite - - - https - - api.runelite.net - /runelite-${project.version} - - ${project.parent.name} HTTP API - ${project.version} - ${project.description} - - https://tldrlegal.com/license/bsd-2-clause-license-(freebsd) - BSD 2-Clause "Simplified" - - - ${basedir}/src/main/templates/template.html.hbs - ${project.build.directory}/swagger-ui - ${project.build.directory}/site/api.html - true - json - - - - - - compile - - generate - - - - - - pl.project13.maven - git-commit-id-plugin - 2.2.6 - - - query-git-info - - revision - - - false - false - - true - - - git.commit.id.abbrev - git.dirty - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - 2.7 - - - @ - - false - - - - - diff --git a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java deleted file mode 100644 index 4c425cb0cf..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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 ch.qos.logback.classic.LoggerContext; -import com.google.common.base.Strings; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoClients; -import java.io.IOException; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.naming.NamingException; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletException; -import javax.sql.DataSource; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.service.util.InstantConverter; -import okhttp3.Cache; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import org.slf4j.ILoggerFactory; -import org.slf4j.impl.StaticLoggerBinder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.web.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; -import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; -import org.springframework.jndi.JndiTemplate; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.sql2o.Sql2o; -import org.sql2o.converters.Converter; -import org.sql2o.quirks.NoQuirks; - -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) -@EnableScheduling -@Slf4j -public class SpringBootWebApplication extends SpringBootServletInitializer -{ - @Bean - protected ServletContextListener listener(OkHttpClient client) - { - return new ServletContextListener() - { - @Override - public void contextInitialized(ServletContextEvent sce) - { - log.info("RuneLite API started"); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) - { - // Destroy okhttp client - client.dispatcher().executorService().shutdown(); - client.connectionPool().evictAll(); - try - { - Cache cache = client.cache(); - if (cache != null) - { - cache.close(); - } - } - catch (IOException ex) - { - log.warn(null, ex); - } - - log.info("RuneLite API stopped"); - } - - }; - } - - @ConfigurationProperties(prefix = "datasource.runelite") - @Bean("dataSourceRuneLite") - public DataSourceProperties dataSourceProperties() - { - return new DataSourceProperties(); - } - - @ConfigurationProperties(prefix = "datasource.runelite-cache") - @Bean("dataSourceRuneLiteCache") - public DataSourceProperties dataSourcePropertiesCache() - { - return new DataSourceProperties(); - } - - @Bean(value = "runelite", destroyMethod = "") - public DataSource runeliteDataSource(@Qualifier("dataSourceRuneLite") DataSourceProperties dataSourceProperties) - { - return getDataSource(dataSourceProperties); - } - - @Bean(value = "runelite-cache", destroyMethod = "") - public DataSource runeliteCache2DataSource(@Qualifier("dataSourceRuneLiteCache") DataSourceProperties dataSourceProperties) - { - return getDataSource(dataSourceProperties); - } - - @Bean("Runelite SQL2O") - public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource) - { - return createSql2oFromDataSource(dataSource); - } - - @Bean("Runelite Cache SQL2O") - public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource) - { - return createSql2oFromDataSource(dataSource); - } - - @Bean(destroyMethod = "") - public MongoClient mongoClient(@Value("${mongo.host:}") String host, @Value("${mongo.jndiName:}") String jndiName) throws NamingException - { - if (!Strings.isNullOrEmpty(jndiName)) - { - JndiTemplate jndiTemplate = new JndiTemplate(); - return jndiTemplate.lookup(jndiName, MongoClient.class); - } - else if (!Strings.isNullOrEmpty(host)) - { - return MongoClients.create(host); - } - else - { - throw new RuntimeException("Either mongo.host or mongo.jndiName must be set"); - } - } - - private static DataSource getDataSource(DataSourceProperties dataSourceProperties) - { - if (!Strings.isNullOrEmpty(dataSourceProperties.getJndiName())) - { - // Use JNDI provided datasource, which is already configured with pooling - JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); - return dataSourceLookup.getDataSource(dataSourceProperties.getJndiName()); - } - else - { - return dataSourceProperties.initializeDataSourceBuilder().build(); - } - } - - private static Sql2o createSql2oFromDataSource(final DataSource dataSource) - { - final Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o(dataSource, new NoQuirks(converters)); - } - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) - { - return application.sources(SpringBootWebApplication.class); - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException - { - super.onStartup(servletContext); - ILoggerFactory loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory(); - if (loggerFactory instanceof LoggerContext) - { - LoggerContext loggerContext = (LoggerContext) loggerFactory; - loggerContext.setPackagingDataEnabled(false); - log.debug("Disabling logback packaging data"); - } - } - - @Bean - public OkHttpClient okHttpClient( - @Value("${runelite.version}") String version, - @Value("${runelite.commit}") String commit, - @Value("${runelite.dirty}") boolean dirty - ) - { - final String userAgent = "RuneLite/" + version + "-" + commit + (dirty ? "+" : ""); - return new OkHttpClient.Builder() - .pingInterval(30, TimeUnit.SECONDS) - .addNetworkInterceptor(chain -> - { - Request userAgentRequest = chain.request() - .newBuilder() - .header("User-Agent", userAgent) - .build(); - return chain.proceed(userAgentRequest); - }) - .build(); - } - - public static void main(String[] args) - { - SpringApplication.run(SpringBootWebApplication.class, args); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java deleted file mode 100644 index 6af0895619..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * 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.common.util.concurrent.ThreadFactoryBuilder; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.annotation.SchedulingConfigurer; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.scheduling.config.ScheduledTaskRegistrar; - -@Configuration -public class SpringSchedulingConfigurer implements SchedulingConfigurer -{ - @Override - public void configureTasks(ScheduledTaskRegistrar taskRegistrar) - { - // this is from ScheduledTaskRegistrar.scheduleTasks() but modified to give the scheduler thread a - // recognizable name - ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder() - .setNameFormat("scheduler-%d") - .build() - ); - TaskScheduler scheduler = new ConcurrentTaskScheduler(scheduledExecutorService); - taskRegistrar.setTaskScheduler(scheduler); - } -} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java deleted file mode 100644 index 704e4f9cb2..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.util.List; -import net.runelite.http.api.RuneLiteAPI; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.GsonHttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -@Configuration -@EnableWebMvc -public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter -{ - /** - * Configure .js as application/json to trick Cloudflare into caching json responses - */ - @Override - public void configureContentNegotiation(ContentNegotiationConfigurer configurer) - { - configurer.mediaType("js", MediaType.APPLICATION_JSON); - } - - /** - * Use GSON instead of Jackson for JSON serialization - * @param converters - */ - @Override - public void extendMessageConverters(List> converters) - { - // Could not figure out a better way to force GSON - converters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance); - - GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); - gsonHttpMessageConverter.setGson(RuneLiteAPI.GSON); - converters.add(gsonHttpMessageConverter); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java deleted file mode 100644 index 10a289b927..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import com.github.scribejava.apis.GoogleApi20; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.model.OAuth2AccessToken; -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.oauth.OAuth20Service; -import com.google.gson.Gson; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -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.account.OAuthResponse; -import net.runelite.http.api.ws.WebsocketGsonFactory; -import net.runelite.http.api.ws.WebsocketMessage; -import net.runelite.http.api.ws.messages.LoginResponse; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.account.beans.UserEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.GetMapping; -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.Sql2o; -import org.sql2o.Sql2oException; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/account") -public class AccountService -{ - private static final Logger logger = LoggerFactory.getLogger(AccountService.class); - - private static final String CREATE_SESSIONS = "CREATE TABLE IF NOT EXISTS `sessions` (\n" - + " `user` int(11) NOT NULL PRIMARY KEY,\n" - + " `uuid` varchar(36) NOT NULL,\n" - + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " UNIQUE KEY `uuid` (`uuid`),\n" - + " KEY `user` (`user`)\n" - + ") ENGINE=InnoDB"; - - private static final String CREATE_USERS = "CREATE TABLE IF NOT EXISTS `users` (\n" - + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" - + " `username` tinytext NOT NULL,\n" - + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " PRIMARY KEY (`id`),\n" - + " UNIQUE KEY `username` (`username`(64))\n" - + ") ENGINE=InnoDB"; - - private static final String SESSIONS_FK = "ALTER TABLE `sessions`\n" - + " ADD CONSTRAINT `id` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;"; - - private static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email"; - private static final String USERINFO = "https://www.googleapis.com/oauth2/v2/userinfo"; - private static final String RL_REDIR = "https://runelite.net/logged-in"; - - private final Gson gson = RuneLiteAPI.GSON; - private final Gson websocketGson = WebsocketGsonFactory.build(); - - private final Sql2o sql2o; - private final String oauthClientId; - private final String oauthClientSecret; - private final String oauthCallback; - private final String runeliteVersion; - private final AuthFilter auth; - private final RedisPool jedisPool; - - @Autowired - public AccountService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${oauth.client-id}") String oauthClientId, - @Value("${oauth.client-secret}") String oauthClientSecret, - @Value("${oauth.callback}") String oauthCallback, - @Value("${runelite.version}") String runeliteVersion, - AuthFilter auth, - RedisPool jedisPool - ) - { - this.sql2o = sql2o; - this.oauthClientId = oauthClientId; - this.oauthClientSecret = oauthClientSecret; - this.oauthCallback = oauthCallback; - this.runeliteVersion = runeliteVersion; - this.auth = auth; - this.jedisPool = jedisPool; - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_SESSIONS) - .executeUpdate(); - - con.createQuery(CREATE_USERS) - .executeUpdate(); - - try - { - con.createQuery(SESSIONS_FK) - .executeUpdate(); - } - catch (Sql2oException ex) - { - // Ignore, happens when index already exists - } - } - } - - @GetMapping("/login") - public OAuthResponse login(@RequestParam UUID uuid) - { - State state = new State(); - state.setUuid(uuid); - state.setApiVersion(runeliteVersion); - - OAuth20Service service = new ServiceBuilder() - .apiKey(oauthClientId) - .apiSecret(oauthClientSecret) - .scope(SCOPE) - .callback(oauthCallback) - .state(gson.toJson(state)) - .build(GoogleApi20.instance()); - - final Map additionalParams = new HashMap<>(); - additionalParams.put("prompt", "select_account"); - - String authorizationUrl = service.getAuthorizationUrl(additionalParams); - - OAuthResponse lr = new OAuthResponse(); - lr.setOauthUrl(authorizationUrl); - lr.setUid(uuid); - - return lr; - } - - @GetMapping("/callback") - public Object callback( - HttpServletRequest request, - HttpServletResponse response, - @RequestParam(required = false) String error, - @RequestParam String code, - @RequestParam("state") String stateStr - ) throws InterruptedException, ExecutionException, IOException - { - if (error != null) - { - logger.info("Error in oauth callback: {}", error); - return null; - } - - State state = gson.fromJson(stateStr, State.class); - - logger.info("Got authorization code {} for uuid {}", code, state.getUuid()); - - OAuth20Service service = new ServiceBuilder() - .apiKey(oauthClientId) - .apiSecret(oauthClientSecret) - .scope(SCOPE) - .callback(oauthCallback) - .state(gson.toJson(state)) - .build(GoogleApi20.instance()); - - OAuth2AccessToken accessToken = service.getAccessToken(code); - - // Access user info - OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO); - service.signRequest(accessToken, orequest); - - Response oresponse = service.execute(orequest); - - if (oresponse.getCode() / 100 != 2) - { - // Could be a forged result - return null; - } - - UserInfo userInfo = gson.fromJson(oresponse.getBody(), UserInfo.class); - - logger.info("Got user info: {}", userInfo); - - try (Connection con = sql2o.open()) - { - con.createQuery("insert ignore into users (username) values (:username)") - .addParameter("username", userInfo.getEmail()) - .executeUpdate(); - - UserEntry user = con.createQuery("select id from users where username = :username") - .addParameter("username", userInfo.getEmail()) - .executeAndFetchFirst(UserEntry.class); - - if (user == null) - { - logger.warn("Unable to find newly created user session"); - return null; // that's weird - } - - // insert session - con.createQuery("insert ignore into sessions (user, uuid) values (:user, :uuid)") - .addParameter("user", user.getId()) - .addParameter("uuid", state.getUuid().toString()) - .executeUpdate(); - - logger.info("Created session for user {}", userInfo.getEmail()); - } - - response.sendRedirect(RL_REDIR); - - notifySession(state.getUuid(), userInfo.getEmail()); - - return ""; - } - - private void notifySession(UUID uuid, String username) - { - LoginResponse response = new LoginResponse(); - response.setUsername(username); - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class)); - } - } - - @GetMapping("/logout") - public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = auth.handle(request, response); - - if (session == null) - { - return; - } - - auth.invalidate(session.getUuid()); - - try (Connection con = sql2o.open()) - { - con.createQuery("delete from sessions where uuid = :uuid") - .addParameter("uuid", session.getUuid().toString()) - .executeUpdate(); - } - } - - @GetMapping("/session-check") - public void sessionCheck(HttpServletRequest request, HttpServletResponse response) throws IOException - { - auth.handle(request, response); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java deleted file mode 100644 index d283e71c5c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; -import java.io.IOException; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -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.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Sql2o; - -@Service -public class AuthFilter -{ - private final Sql2o sql2o; - - private final Cache sessionCache = CacheBuilder.newBuilder() - .maximumSize(10000L) - .expireAfterAccess(30, TimeUnit.MINUTES) - .removalListener(this::removalListener) - .build(); - - @Autowired - public AuthFilter(@Qualifier("Runelite SQL2O") Sql2o sql2o) - { - this.sql2o = sql2o; - } - - public SessionEntry handle(HttpServletRequest request, HttpServletResponse response) throws IOException - { - String runeliteAuth = request.getHeader(RuneLiteAPI.RUNELITE_AUTH); - if (runeliteAuth == null) - { - response.sendError(401, "Access denied"); - return null; - } - - UUID uuid = UUID.fromString(runeliteAuth); - SessionEntry sessionEntry = sessionCache.getIfPresent(uuid); - if (sessionEntry != null) - { - return sessionEntry; - } - - try (Connection con = sql2o.open()) - { - sessionEntry = con.createQuery("select user, uuid, created, last_used as lastUsed from sessions where uuid = :uuid") - .addParameter("uuid", uuid.toString()) - .executeAndFetchFirst(SessionEntry.class); - } - - if (sessionEntry == null) - { - response.sendError(401, "Access denied"); - return null; - } - - sessionCache.put(uuid, sessionEntry); - - return sessionEntry; - } - - private void removalListener(RemovalNotification notification) - { - UUID uuid = notification.getKey(); - Instant now = Instant.now(); - - try (Connection con = sql2o.open()) - { - con.createQuery("update sessions set last_used = :last_used where uuid = :uuid") - .addParameter("last_used", Timestamp.from(now)) - .addParameter("uuid", uuid.toString()) - .executeUpdate(); - } - } - - public void invalidate(UUID uuid) - { - // If we ever run multiple services, may need to publish something here to invalidate... - sessionCache.invalidate(uuid); - } - -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/State.java b/http-service/src/main/java/net/runelite/http/service/account/State.java deleted file mode 100644 index 1412efa11a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/State.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import java.util.UUID; -import lombok.Data; - -@Data -public class State -{ - private UUID uuid; - private String apiVersion; -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java b/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java deleted file mode 100644 index a1cde03f79..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -public class UserInfo -{ - private String email; - - @Override - public String toString() - { - return "UserInfo{" + "email=" + email + '}'; - } - - public String getEmail() - { - return email; - } - - public void setEmail(String email) - { - this.email = email; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java deleted file mode 100644 index ded67c7a45..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account.beans; - -import java.time.Instant; -import java.util.UUID; - -public class SessionEntry -{ - private int user; - private UUID uuid; - private Instant created; - private Instant lastUsed; - - public int getUser() - { - return user; - } - - public void setUser(int user) - { - this.user = user; - } - - public UUID getUuid() - { - return uuid; - } - - public void setUuid(UUID uuid) - { - this.uuid = uuid; - } - - public Instant getCreated() - { - return created; - } - - public void setCreated(Instant created) - { - this.created = created; - } - - public Instant getLastUsed() - { - return lastUsed; - } - - public void setLastUsed(Instant lastUsed) - { - this.lastUsed = lastUsed; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java deleted file mode 100644 index 83dd4152ac..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account.beans; - -public class UserEntry -{ - private int id; - private String username; - - @Override - public String toString() - { - return "UserEntry{" + "id=" + id + ", username=" + username + '}'; - } - - public int getId() - { - return id; - } - - public void setId(int id) - { - this.id = id; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java deleted file mode 100644 index 08282ca38e..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache; - -import java.util.List; -import net.runelite.cache.IndexType; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.cache.beans.FileEntry; -import net.runelite.http.service.cache.beans.IndexEntry; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.ResultSetIterable; - -class CacheDAO -{ - public List listCaches(Connection con) - { - return con.createQuery("select id, revision, date from cache") - .executeAndFetch(CacheEntry.class); - } - - public CacheEntry findMostRecent(Connection con) - { - return con.createQuery("select id, revision, date from cache order by revision desc, date desc limit 1") - .executeAndFetchFirst(CacheEntry.class); - } - - public List findIndexesForCache(Connection con, CacheEntry cache) - { - return con.createQuery("select id, indexId, crc, revision from `index` where cache = :cache") - .addParameter("cache", cache.getId()) - .executeAndFetch(IndexEntry.class); - } - - public IndexEntry findIndexForCache(Connection con, CacheEntry cache, int indexId) - { - return con.createQuery("select id, indexId, crc, revision from `index` " - + "where cache = :id " - + "and indexId = :indexId") - .addParameter("id", cache.getId()) - .addParameter("indexId", indexId) - .executeAndFetchFirst(IndexEntry.class); - } - - public ResultSetIterable findArchivesForIndex(Connection con, IndexEntry indexEntry) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from index_archive " - + "join archive on index_archive.archive = archive.id " - + "where index_archive.index = :id") - .addParameter("id", indexEntry.getId()) - .executeAndFetchLazy(ArchiveEntry.class); - } - - public ArchiveEntry findArchiveForIndex(Connection con, IndexEntry indexEntry, int archiveId) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from index_archive " - + "join archive on index_archive.archive = archive.id " - + "where index_archive.index = :id " - + "and archive.archiveId = :archiveId") - .addParameter("id", indexEntry.getId()) - .addParameter("archiveId", archiveId) - .executeAndFetchFirst(ArchiveEntry.class); - } - - public ArchiveEntry findArchiveByName(Connection con, CacheEntry cache, IndexType index, int nameHash) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from archive " - + "join index_archive on index_archive.archive = archive.id " - + "join `index` on index.id = index_archive.index " - + "where index.cache = :cacheId " - + "and index.indexId = :indexId " - + "and archive.nameHash = :nameHash " - + "limit 1") - .addParameter("cacheId", cache.getId()) - .addParameter("indexId", index.getNumber()) - .addParameter("nameHash", nameHash) - .executeAndFetchFirst(ArchiveEntry.class); - } - - public ResultSetIterable findFilesForArchive(Connection con, ArchiveEntry archiveEntry) - { - Query findFilesForArchive = con.createQuery("select id, fileId, nameHash from file " - + "where archive = :archive"); - - return findFilesForArchive - .addParameter("archive", archiveEntry.getId()) - .executeAndFetchLazy(FileEntry.class); - } - - public CacheEntry findCache(Connection con, int cacheId) - { - return con.createQuery("select id, revision, date from cache " - + "where id = :cacheId") - .addParameter("cacheId", cacheId) - .executeAndFetchFirst(CacheEntry.class); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java deleted file mode 100644 index c0b767a68c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.cache; - -import com.google.common.collect.Iterables; -import com.google.common.io.BaseEncoding; -import com.google.common.io.ByteStreams; -import io.minio.MinioClient; -import io.minio.errors.ErrorResponseException; -import io.minio.errors.InsufficientDataException; -import io.minio.errors.InternalException; -import io.minio.errors.InvalidArgumentException; -import io.minio.errors.InvalidBucketNameException; -import io.minio.errors.InvalidEndpointException; -import io.minio.errors.InvalidPortException; -import io.minio.errors.NoResponseException; -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.ConfigType; -import net.runelite.cache.IndexType; -import net.runelite.cache.definitions.ItemDefinition; -import net.runelite.cache.definitions.loaders.ItemLoader; -import net.runelite.cache.fs.ArchiveFiles; -import net.runelite.cache.fs.Container; -import net.runelite.cache.fs.FSFile; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.cache.beans.FileEntry; -import net.runelite.http.service.cache.beans.IndexEntry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.ResultSetIterable; -import org.sql2o.Sql2o; -import org.xmlpull.v1.XmlPullParserException; - -@Service -@Slf4j -public class CacheService -{ - @Autowired - @Qualifier("Runelite Cache SQL2O") - private Sql2o sql2o; - - @Value("${minio.bucket}") - private String minioBucket; - - private final MinioClient minioClient; - - @Autowired - public CacheService( - @Value("${minio.endpoint}") String minioEndpoint, - @Value("${minio.accesskey}") String accessKey, - @Value("${minio.secretkey}") String secretKey - ) throws InvalidEndpointException, InvalidPortException - { - this.minioClient = new MinioClient(minioEndpoint, accessKey, secretKey); - } - - @Bean - public MinioClient minioClient() - { - return minioClient; - } - - /** - * retrieve archive from storage - * - * @param archiveEntry - * @return - */ - public byte[] getArchive(ArchiveEntry archiveEntry) - { - String hashStr = BaseEncoding.base16().encode(archiveEntry.getHash()); - String path = new StringBuilder() - .append(hashStr, 0, 2) - .append('/') - .append(hashStr.substring(2)) - .toString(); - - try (InputStream in = minioClient.getObject(minioBucket, path)) - { - return ByteStreams.toByteArray(in); - } - catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException - | IOException | InvalidKeyException | NoResponseException | XmlPullParserException - | ErrorResponseException | InternalException | InvalidArgumentException ex) - { - log.warn(null, ex); - return null; - } - } - - public ArchiveFiles getArchiveFiles(ArchiveEntry archiveEntry) throws IOException - { - CacheDAO cacheDao = new CacheDAO(); - - try (Connection con = sql2o.open(); - ResultSetIterable files = cacheDao.findFilesForArchive(con, archiveEntry)) - { - byte[] archiveData = getArchive(archiveEntry); - - if (archiveData == null) - { - return null; - } - - Container result = Container.decompress(archiveData, null); - if (result == null) - { - return null; - } - - byte[] decompressedData = result.data; - - ArchiveFiles archiveFiles = new ArchiveFiles(); - for (FileEntry fileEntry : files) - { - FSFile file = new FSFile(fileEntry.getFileId()); - archiveFiles.addFile(file); - file.setNameHash(fileEntry.getNameHash()); - } - archiveFiles.loadContents(decompressedData); - return archiveFiles; - } - } - - public List listCaches() - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.listCaches(con); - } - } - - public CacheEntry findCache(int cacheId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findCache(con, cacheId); - } - } - - public CacheEntry findMostRecent() - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findMostRecent(con); - } - } - - public List findIndexesForCache(CacheEntry cacheEntry) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findIndexesForCache(con, cacheEntry); - } - } - - public IndexEntry findIndexForCache(CacheEntry cahceEntry, int indexId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findIndexForCache(con, cahceEntry, indexId); - } - } - - public List findArchivesForIndex(IndexEntry indexEntry) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - ResultSetIterable archiveEntries = cacheDao.findArchivesForIndex(con, indexEntry); - List archives = new ArrayList<>(); - Iterables.addAll(archives, archiveEntries); - return archives; - } - } - - public ArchiveEntry findArchiveForIndex(IndexEntry indexEntry, int archiveId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findArchiveForIndex(con, indexEntry, archiveId); - } - } - - public ArchiveEntry findArchiveForTypeAndName(CacheEntry cache, IndexType index, int nameHash) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findArchiveByName(con, cache, index, nameHash); - } - } - - public List getItems() throws IOException - { - CacheEntry cache = findMostRecent(); - if (cache == null) - { - return Collections.emptyList(); - } - - IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber()); - ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId()); - ArchiveFiles archiveFiles = getArchiveFiles(archiveEntry); - final ItemLoader itemLoader = new ItemLoader(); - final List result = new ArrayList<>(archiveFiles.getFiles().size()); - for (FSFile file : archiveFiles.getFiles()) - { - ItemDefinition itemDef = itemLoader.load(file.getFileId(), file.getContents()); - result.add(itemDef); - } - return result; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java deleted file mode 100644 index acda96e77f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class ArchiveEntry -{ - private int id; - private int archiveId; - private int nameHash; - private int crc; - private int revision; - private byte[] hash; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java deleted file mode 100644 index 231ad7c655..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import java.time.Instant; -import lombok.Data; - -@Data -public class CacheEntry -{ - private int id; - private int revision; - private Instant date; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java deleted file mode 100644 index c5f35a4cc3..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class FileEntry -{ - private int id; - private int archiveId; - private int fileId; - private int nameHash; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java deleted file mode 100644 index 8d60927c71..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class IndexEntry -{ - private int id; - private int indexId; - private int crc; - private int revision; -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java deleted file mode 100644 index 954c90e94b..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import net.runelite.http.api.chat.Duels; -import net.runelite.http.api.chat.LayoutRoom; -import net.runelite.http.api.chat.Task; -import net.runelite.http.service.util.exception.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/chat") -public class ChatController -{ - private static final Pattern STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]"); - private static final int STRING_MAX_LENGTH = 50; - private static final int MAX_LAYOUT_ROOMS = 16; - private static final int MAX_PETS = 256; - - private final Cache killCountCache = CacheBuilder.newBuilder() - .expireAfterWrite(2, TimeUnit.MINUTES) - .maximumSize(128L) - .build(); - - @Autowired - private ChatService chatService; - - @PostMapping("/kc") - public void submitKc(@RequestParam String name, @RequestParam String boss, @RequestParam int kc) - { - if (kc <= 0) - { - return; - } - - chatService.setKc(name, boss, kc); - killCountCache.put(new KillCountKey(name, boss), kc); - } - - @GetMapping("/kc") - public int getKc(@RequestParam String name, @RequestParam String boss) - { - Integer kc = killCountCache.getIfPresent(new KillCountKey(name, boss)); - if (kc == null) - { - kc = chatService.getKc(name, boss); - if (kc != null) - { - killCountCache.put(new KillCountKey(name, boss), kc); - } - } - - if (kc == null) - { - throw new NotFoundException(); - } - return kc; - } - - @PostMapping("/qp") - public void submitQp(@RequestParam String name, @RequestParam int qp) - { - if (qp < 0) - { - return; - } - - chatService.setQp(name, qp); - } - - @GetMapping("/qp") - public int getQp(@RequestParam String name) - { - Integer kc = chatService.getQp(name); - if (kc == null) - { - throw new NotFoundException(); - } - return kc; - } - - @PostMapping("/gc") - public void submitGc(@RequestParam String name, @RequestParam int gc) - { - if (gc < 0) - { - return; - } - - chatService.setGc(name, gc); - } - - @GetMapping("/gc") - public int getKc(@RequestParam String name) - { - Integer gc = chatService.getGc(name); - if (gc == null) - { - throw new NotFoundException(); - } - return gc; - } - - @PostMapping("/task") - public void submitTask(@RequestParam String name, @RequestParam("task") String taskName, @RequestParam int amount, - @RequestParam int initialAmount, @RequestParam String location) - { - Matcher mTask = STRING_VALIDATION.matcher(taskName); - Matcher mLocation = STRING_VALIDATION.matcher(location); - if (mTask.find() || taskName.length() > STRING_MAX_LENGTH || - mLocation.find() || location.length() > STRING_MAX_LENGTH) - { - return; - } - - Task task = new Task(); - task.setTask(taskName); - task.setAmount(amount); - task.setInitialAmount(initialAmount); - task.setLocation(location); - - chatService.setTask(name, task); - } - - @GetMapping("/task") - public ResponseEntity getTask(@RequestParam String name) - { - Task task = chatService.getTask(name); - if (task == null) - { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(2, TimeUnit.MINUTES).cachePublic()) - .body(task); - } - - @PostMapping("/pb") - public void submitPb(@RequestParam String name, @RequestParam String boss, @RequestParam double pb) - { - if (pb < 0) - { - return; - } - - chatService.setPb(name, boss, pb); - } - - @GetMapping("/pb") - public double getPb(@RequestParam String name, @RequestParam String boss) - { - Double pb = chatService.getPb(name, boss); - if (pb == null) - { - throw new NotFoundException(); - } - return pb; - } - - @PostMapping("/duels") - public void submitDuels(@RequestParam String name, @RequestParam int wins, - @RequestParam int losses, - @RequestParam int winningStreak, @RequestParam int losingStreak) - { - if (wins < 0 || losses < 0 || winningStreak < 0 || losingStreak < 0) - { - return; - } - - Duels duels = new Duels(); - duels.setWins(wins); - duels.setLosses(losses); - duels.setWinningStreak(winningStreak); - duels.setLosingStreak(losingStreak); - - chatService.setDuels(name, duels); - } - - @GetMapping("/duels") - public Duels getDuels(@RequestParam String name) - { - Duels duels = chatService.getDuels(name); - if (duels == null) - { - throw new NotFoundException(); - } - return duels; - } - - @PostMapping("/layout") - public void submitLayout(@RequestParam String name, @RequestBody LayoutRoom[] rooms) - { - if (rooms.length > MAX_LAYOUT_ROOMS) - { - return; - } - - chatService.setLayout(name, rooms); - } - - @GetMapping("/layout") - public LayoutRoom[] getLayout(@RequestParam String name) - { - LayoutRoom[] layout = chatService.getLayout(name); - - if (layout == null) - { - throw new NotFoundException(); - } - - return layout; - } - - @PostMapping("/pets") - public void submitPetList(@RequestParam String name, @RequestBody int[] petList) - { - if (petList.length == 0 || petList.length > MAX_PETS) - { - return; - } - - chatService.setPetList(name, petList); - } - - @GetMapping("/pets") - public int[] getPetList(@RequestParam String name) - { - int[] petList = chatService.getPetList(name); - if (petList == null) - { - throw new NotFoundException(); - } - - return petList; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java deleted file mode 100644 index 7748728aab..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import net.runelite.http.api.chat.Duels; -import net.runelite.http.api.chat.LayoutRoom; -import net.runelite.http.api.chat.Task; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import redis.clients.jedis.Jedis; - -@Service -public class ChatService -{ - private static final Duration EXPIRE = Duration.ofMinutes(2); - - private final RedisPool jedisPool; - - @Autowired - public ChatService(RedisPool jedisPool) - { - this.jedisPool = jedisPool; - } - - public Integer getKc(String name, String boss) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("kc." + name + "." + boss); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setKc(String name, String boss, int kc) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("kc." + name + "." + boss, (int) EXPIRE.getSeconds(), Integer.toString(kc)); - } - } - - public Integer getQp(String name) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("qp." + name); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setQp(String name, int qp) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("qp." + name, (int) EXPIRE.getSeconds(), Integer.toString(qp)); - } - } - - public Task getTask(String name) - { - Map map; - - try (Jedis jedis = jedisPool.getResource()) - { - map = jedis.hgetAll("task." + name); - } - - if (map.isEmpty()) - { - return null; - } - - Task task = new Task(); - task.setTask(map.get("task")); - task.setAmount(Integer.parseInt(map.get("amount"))); - task.setInitialAmount(Integer.parseInt(map.get("initialAmount"))); - task.setLocation(map.get("location")); - return task; - } - - public void setTask(String name, Task task) - { - Map taskMap = ImmutableMap.builderWithExpectedSize(4) - .put("task", task.getTask()) - .put("amount", Integer.toString(task.getAmount())) - .put("initialAmount", Integer.toString(task.getInitialAmount())) - .put("location", task.getLocation()) - .build(); - - String key = "task." + name; - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.hmset(key, taskMap); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } - - public Double getPb(String name, String boss) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("pb." + boss + "." + name); - } - return value == null ? null : Double.parseDouble(value); - } - - public void setPb(String name, String boss, double pb) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("pb." + boss + "." + name, (int) EXPIRE.getSeconds(), Double.toString(pb)); - } - } - - public Integer getGc(String name) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("gc." + name); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setGc(String name, int gc) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("gc." + name, (int) EXPIRE.getSeconds(), Integer.toString(gc)); - } - } - - public Duels getDuels(String name) - { - Map map; - - try (Jedis jedis = jedisPool.getResource()) - { - map = jedis.hgetAll("duels." + name); - } - - if (map.isEmpty()) - { - return null; - } - - Duels duels = new Duels(); - duels.setWins(Integer.parseInt(map.get("wins"))); - duels.setLosses(Integer.parseInt(map.get("losses"))); - duels.setWinningStreak(Integer.parseInt(map.get("winningStreak"))); - duels.setLosingStreak(Integer.parseInt(map.get("losingStreak"))); - return duels; - } - - public void setDuels(String name, Duels duels) - { - Map duelsMap = ImmutableMap.builderWithExpectedSize(4) - .put("wins", Integer.toString(duels.getWins())) - .put("losses", Integer.toString(duels.getLosses())) - .put("winningStreak", Integer.toString(duels.getWinningStreak())) - .put("losingStreak", Integer.toString(duels.getLosingStreak())) - .build(); - - String key = "duels." + name; - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.hmset(key, duelsMap); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } - - public LayoutRoom[] getLayout(String name) - { - String layout; - try (Jedis jedis = jedisPool.getResource()) - { - layout = jedis.get("layout." + name); - } - - if (layout == null) - { - return null; - } - - List roomList = Splitter.on(' ').splitToList(layout); - return roomList.stream() - .map(LayoutRoom::valueOf) - .toArray(LayoutRoom[]::new); - } - - public void setLayout(String name, LayoutRoom[] rooms) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("layout." + name, (int) EXPIRE.getSeconds(), Joiner.on(' ').join(rooms)); - } - } - - public int[] getPetList(String name) - { - Set pets; - try (Jedis jedis = jedisPool.getResource()) - { - pets = jedis.smembers("pets." + name); - } - - if (pets.isEmpty()) - { - return null; - } - - return pets.stream() - .mapToInt(Integer::parseInt) - .toArray(); - } - - public void setPetList(String name, int[] petList) - { - String[] pets = Arrays.stream(petList).mapToObj(Integer::toString).toArray(String[]::new); - String key = "pets." + name; - try (Jedis jedis = jedisPool.getResource()) - { - jedis.sadd(key, pets); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java b/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java deleted file mode 100644 index 07ca775dad..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import lombok.Value; - -@Value -class KillCountKey -{ - private String username; - private String boss; -} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java deleted file mode 100644 index c247ecc0bc..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import java.io.IOException; -import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.config.Configuration; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -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; - -@RestController -@RequestMapping("/config") -public class ConfigController -{ - private final ConfigService configService; - private final AuthFilter authFilter; - - @Autowired - public ConfigController(ConfigService configService, AuthFilter authFilter) - { - this.configService = configService; - this.authFilter = authFilter; - } - - @GetMapping - public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return null; - } - - return configService.get(session.getUser()); - } - - @PatchMapping - public List patch( - HttpServletRequest request, - HttpServletResponse response, - @RequestBody Configuration changes - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - if (session == null) - { - return null; - } - - List failures = configService.patch(session.getUser(), changes); - if (failures.size() != 0) - { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return failures; - } - - return null; - } - - @RequestMapping(path = "/{key:.+}", method = PUT) - public void setKey( - HttpServletRequest request, - HttpServletResponse response, - @PathVariable String key, - @RequestBody(required = false) String value - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - if (!configService.setKey(session.getUser(), key, value)) - { - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } - - @RequestMapping(path = "/{key:.+}", method = DELETE) - public void unsetKey( - HttpServletRequest request, - HttpServletResponse response, - @PathVariable String key - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - if (!configService.unsetKey(session.getUser(), key)) - { - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java deleted file mode 100644 index bb6050ad4b..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (c) 2017-2019, Adam - * 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.config; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSyntaxException; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import static com.mongodb.client.model.Filters.eq; -import com.mongodb.client.model.IndexOptions; -import com.mongodb.client.model.Indexes; -import com.mongodb.client.model.UpdateOptions; -import static com.mongodb.client.model.Updates.combine; -import static com.mongodb.client.model.Updates.set; -import static com.mongodb.client.model.Updates.unset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.config.ConfigEntry; -import net.runelite.http.api.config.Configuration; -import org.bson.Document; -import org.bson.conversions.Bson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -public class ConfigService -{ - private static final Pattern MAYBE_JSON = Pattern.compile("^[\\-0-9{\\[\"]|true|false"); - private static final int MAX_DEPTH = 8; - private static final int MAX_VALUE_LENGTH = 262144; - - private final Gson GSON = RuneLiteAPI.GSON; - private final UpdateOptions upsertUpdateOptions = new UpdateOptions().upsert(true); - - private final MongoCollection mongoCollection; - - @Autowired - public ConfigService( - MongoClient mongoClient, - @Value("${mongo.database}") String databaseName - ) - { - - MongoDatabase database = mongoClient.getDatabase(databaseName); - MongoCollection collection = database.getCollection("config"); - this.mongoCollection = collection; - - // Create unique index on _userId - IndexOptions indexOptions = new IndexOptions().unique(true); - collection.createIndex(Indexes.ascending("_userId"), indexOptions); - } - - private Document getConfig(int userId) - { - return mongoCollection.find(eq("_userId", userId)).first(); - } - - public Configuration get(int userId) - { - Map configMap = getConfig(userId); - - if (configMap == null || configMap.isEmpty()) - { - return new Configuration(Collections.emptyList()); - } - - List config = new ArrayList<>(); - - for (String group : configMap.keySet()) - { - // Reserved keys - if (group.startsWith("_") || group.startsWith("$")) - { - continue; - } - - Map groupMap = (Map) configMap.get(group); - - for (Map.Entry entry : groupMap.entrySet()) - { - String key = entry.getKey(); - Object value = entry.getValue(); - - if (value instanceof Map || value instanceof Collection) - { - value = GSON.toJson(entry.getValue()); - } - else if (value == null) - { - continue; - } - - ConfigEntry configEntry = new ConfigEntry(); - configEntry.setKey(group + "." + key.replace(':', '.')); - configEntry.setValue(value.toString()); - config.add(configEntry); - } - } - - return new Configuration(config); - } - - public List patch(int userID, Configuration config) - { - List failures = new ArrayList<>(); - List sets = new ArrayList<>(config.getConfig().size()); - for (ConfigEntry entry : config.getConfig()) - { - Bson s = setForKV(entry.getKey(), entry.getValue()); - if (s == null) - { - failures.add(entry.getKey()); - } - else - { - sets.add(s); - } - } - - if (sets.size() > 0) - { - mongoCollection.updateOne( - eq("_userId", userID), - combine(sets), - upsertUpdateOptions - ); - } - - return failures; - } - - @Nullable - private Bson setForKV(String key, @Nullable String value) - { - if (key.startsWith("$") || key.startsWith("_")) - { - return null; - } - - String[] split = key.split("\\.", 2); - if (split.length != 2) - { - return null; - } - - String dbKey = split[0] + "." + split[1].replace('.', ':'); - - if (Strings.isNullOrEmpty(value)) - { - return unset(dbKey); - } - - Object jsonValue; - if (!isMaybeJson(value)) - { - if (!validateStr(value)) - { - return null; - } - - jsonValue = value; - } - else - { - if (!validateJson(value)) - { - return null; - } - - jsonValue = parseJsonString(value); - } - return set(dbKey, jsonValue); - } - - public boolean setKey( - int userId, - String key, - @Nullable String value - ) - { - Bson set = setForKV(key, value); - if (set == null) - { - return false; - } - - mongoCollection.updateOne(eq("_userId", userId), - set, - upsertUpdateOptions); - return true; - } - - public boolean unsetKey( - int userId, - String key - ) - { - Bson set = setForKV(key, null); - if (set == null) - { - return false; - } - - mongoCollection.updateOne(eq("_userId", userId), set); - return true; - } - - @VisibleForTesting - static Object parseJsonString(String value) - { - Object jsonValue; - try - { - jsonValue = RuneLiteAPI.GSON.fromJson(value, Object.class); - if (jsonValue == null) - { - return value; - } - else if (jsonValue instanceof Double || jsonValue instanceof Float) - { - Number number = (Number) jsonValue; - if (Math.floor(number.doubleValue()) == number.doubleValue() && !Double.isInfinite(number.doubleValue())) - { - // value is an int or long. 'number' might be truncated so parse it from 'value' - try - { - jsonValue = Integer.parseInt(value); - } - catch (NumberFormatException ex) - { - try - { - jsonValue = Long.parseLong(value); - } - catch (NumberFormatException ex2) - { - - } - } - } - } - } - catch (JsonSyntaxException ex) - { - jsonValue = value; - } - return jsonValue; - } - - @VisibleForTesting - static boolean isMaybeJson(String value) - { - return MAYBE_JSON.matcher(value).find(); - } - - private static boolean validateStr(String value) - { - return value.length() < MAX_VALUE_LENGTH; - } - - @VisibleForTesting - static boolean validateJson(String value) - { - try - { - // I couldn't figure out a better way to do this than a second json parse - JsonElement jsonElement = RuneLiteAPI.GSON.fromJson(value, JsonElement.class); - if (jsonElement == null) - { - return value.length() < MAX_VALUE_LENGTH; - } - return validateObject(jsonElement, 1); - } - catch (JsonSyntaxException ex) - { - // the client submits the string representation of objects which is not always valid json, - // eg. a value with a ':' in it. We just ignore it now. We can't json encode the values client - // side due to them already being strings, which prevents gson from being able to convert them - // to ints/floats/maps etc. - return value.length() < MAX_VALUE_LENGTH; - } - } - - private static boolean validateObject(JsonElement jsonElement, int depth) - { - if (depth >= MAX_DEPTH) - { - return false; - } - - if (jsonElement.isJsonObject()) - { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - - for (Map.Entry entry : jsonObject.entrySet()) - { - JsonElement element = entry.getValue(); - - if (!validateObject(element, depth + 1)) - { - return false; - } - } - } - else if (jsonElement.isJsonArray()) - { - JsonArray jsonArray = jsonElement.getAsJsonArray(); - - for (int i = 0; i < jsonArray.size(); ++i) - { - JsonElement element = jsonArray.get(i); - - if (!validateObject(element, depth + 1)) - { - return false; - } - } - } - else if (jsonElement.isJsonPrimitive()) - { - JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive(); - String value = jsonPrimitive.getAsString(); - if (value.length() >= MAX_VALUE_LENGTH) - { - return false; - } - } - - return true; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java b/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java deleted file mode 100644 index 9c799d9873..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed; - -import com.google.common.hash.HashCode; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedResult; -import net.runelite.http.service.feed.blog.BlogService; -import net.runelite.http.service.feed.osrsnews.OSRSNewsService; -import net.runelite.http.service.feed.twitter.TwitterService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/feed") -@Slf4j -public class FeedController -{ - private final BlogService blogService; - private final TwitterService twitterService; - private final OSRSNewsService osrsNewsService; - - private static class MemoizedFeed - { - final FeedResult feedResult; - final String hash; - - MemoizedFeed(FeedResult feedResult) - { - this.feedResult = feedResult; - - Hasher hasher = Hashing.sha256().newHasher(); - for (FeedItem itemPrice : feedResult.getItems()) - { - hasher.putBytes(itemPrice.getTitle().getBytes(StandardCharsets.UTF_8)).putBytes(itemPrice.getContent().getBytes(StandardCharsets.UTF_8)); - } - HashCode code = hasher.hash(); - hash = code.toString(); - } - } - - private MemoizedFeed memoizedFeed; - - @Autowired - public FeedController(BlogService blogService, TwitterService twitterService, OSRSNewsService osrsNewsService) - { - this.blogService = blogService; - this.twitterService = twitterService; - this.osrsNewsService = osrsNewsService; - } - - @Scheduled(fixedDelay = 10 * 60 * 1000) - public void updateFeed() - { - List items = new ArrayList<>(); - - try - { - items.addAll(blogService.getBlogPosts()); - } - catch (Exception e) - { - log.warn("unable to fetch blogs", e); - } - - try - { - items.addAll(twitterService.getTweets()); - } - catch (Exception e) - { - log.warn("unable to fetch tweets", e); - } - - try - { - items.addAll(osrsNewsService.getNews()); - } - catch (Exception e) - { - log.warn("unable to fetch news", e); - } - - memoizedFeed = new MemoizedFeed(new FeedResult(items)); - } - - @GetMapping - public ResponseEntity getFeed() - { - if (memoizedFeed == null) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .eTag(memoizedFeed.hash) - .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) - .body(memoizedFeed.feedResult); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java b/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java deleted file mode 100644 index 72f7938910..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.blog; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -@Service -public class BlogService -{ - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - - private final OkHttpClient okHttpClient; - private final HttpUrl rssUrl; - - @Autowired - public BlogService( - OkHttpClient okHttpClient, - @Value("${runelite.feed.rssUrl}") String rssUrl - ) - { - this.okHttpClient = okHttpClient; - this.rssUrl = HttpUrl.get(rssUrl); - } - - public List getBlogPosts() throws IOException - { - Request request = new Request.Builder() - .url(rssUrl) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error getting blog posts: " + response); - } - - try - { - InputStream in = response.body().byteStream(); - Document document = DocumentBuilderFactory.newInstance() - .newDocumentBuilder() - .parse(in); - - Element documentElement = document.getDocumentElement(); - NodeList documentItems = documentElement.getElementsByTagName("entry"); - - List items = new ArrayList<>(); - - for (int i = 0; i < Math.min(documentItems.getLength(), 3); i++) - { - Node item = documentItems.item(i); - NodeList children = item.getChildNodes(); - - String title = null; - String summary = null; - String link = null; - long timestamp = -1; - - for (int j = 0; j < children.getLength(); j++) - { - Node childItem = children.item(j); - String nodeName = childItem.getNodeName(); - - switch (nodeName) - { - case "title": - title = childItem.getTextContent(); - break; - case "summary": - summary = childItem.getTextContent().replace("\n", "").trim(); - break; - case "link": - link = childItem.getAttributes().getNamedItem("href").getTextContent(); - break; - case "updated": - timestamp = DATE_FORMAT.parse(childItem.getTextContent()).getTime(); - break; - } - } - - if (title == null || summary == null || link == null || timestamp == -1) - { - throw new InternalServerErrorException("Failed to find title, summary, link and/or timestamp in the blog post feed"); - } - - items.add(new FeedItem(FeedItemType.BLOG_POST, title, summary, link, timestamp)); - } - - return items; - } - catch (ParserConfigurationException | SAXException | ParseException e) - { - throw new InternalServerErrorException("Failed to parse blog posts: " + e.getMessage()); - } - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java b/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java deleted file mode 100644 index e53b2d8044..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.osrsnews; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -@Service -public class OSRSNewsService -{ - private static final SimpleDateFormat PUB_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy '00:00:00 GMT'", Locale.US); - - private final OkHttpClient okHttpClient; - private final HttpUrl rssUrl; - - @Autowired - public OSRSNewsService( - OkHttpClient okHttpClient, - @Value("${runelite.osrsnews.rssUrl}") String rssUrl - ) - { - this.okHttpClient = okHttpClient; - this.rssUrl = HttpUrl.get(rssUrl); - } - - public List getNews() throws IOException - { - Request request = new Request.Builder() - .url(rssUrl) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error getting OSRS news: " + response); - } - - try - { - InputStream in = response.body().byteStream(); - Document document = DocumentBuilderFactory.newInstance() - .newDocumentBuilder() - .parse(in); - - Element documentElement = document.getDocumentElement(); - NodeList documentItems = documentElement.getElementsByTagName("item"); - - List items = new ArrayList<>(); - - for (int i = 0; i < documentItems.getLength(); i++) - { - Node item = documentItems.item(i); - NodeList children = item.getChildNodes(); - - String title = null; - String description = null; - String link = null; - long timestamp = -1; - - for (int j = 0; j < children.getLength(); j++) - { - Node childItem = children.item(j); - String nodeName = childItem.getNodeName(); - - switch (nodeName) - { - case "title": - title = childItem.getTextContent(); - break; - case "description": - description = childItem.getTextContent().replace("\n", "").trim(); - break; - case "link": - link = childItem.getTextContent(); - break; - case "pubDate": - timestamp = PUB_DATE_FORMAT.parse(childItem.getTextContent()).getTime(); - break; - } - } - - if (title == null || description == null || link == null || timestamp == -1) - { - throw new InternalServerErrorException("Failed to find title, description, link and/or timestamp in the OSRS RSS feed"); - } - - items.add(new FeedItem(FeedItemType.OSRS_NEWS, title, description, link, timestamp)); - } - - return items; - } - catch (ParserConfigurationException | SAXException | ParseException e) - { - throw new InternalServerErrorException("Failed to parse OSRS news: " + e.getMessage()); - } - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java deleted file mode 100644 index 24df0b6cf6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.annotations.SerializedName; -import lombok.Data; - -@Data -class TwitterOAuth2TokenResponse -{ - @SerializedName("token_type") - private String tokenType; - - @SerializedName("access_token") - private String token; -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java deleted file mode 100644 index 4b7b026646..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.reflect.TypeToken; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.FormBody; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; - -@Service -public class TwitterService -{ - private static final HttpUrl AUTH_URL = HttpUrl.parse("https://api.twitter.com/oauth2/token"); - private static final HttpUrl LIST_STATUSES_URL = HttpUrl.parse("https://api.twitter.com/1.1/lists/statuses.json"); - - private final String credentials; - private final String listId; - private final OkHttpClient okHttpClient; - - private String token; - - @Autowired - public TwitterService( - @Value("${runelite.twitter.consumerkey}") String consumerKey, - @Value("${runelite.twitter.secretkey}") String consumerSecret, - @Value("${runelite.twitter.listid}") String listId, - OkHttpClient okHttpClient - ) - { - this.credentials = consumerKey + ":" + consumerSecret; - this.listId = listId; - this.okHttpClient = okHttpClient; - } - - public List getTweets() throws IOException - { - return getTweets(false); - } - - private List getTweets(boolean hasRetried) throws IOException - { - if (token == null) - { - updateToken(); - } - - HttpUrl url = LIST_STATUSES_URL.newBuilder() - .addQueryParameter("list_id", listId) - .addQueryParameter("count", "15") - .addQueryParameter("include_entities", "false") - .build(); - - Request request = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + token) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - switch (HttpStatus.valueOf(response.code())) - { - case BAD_REQUEST: - case UNAUTHORIZED: - updateToken(); - if (!hasRetried) - { - return getTweets(true); - } - throw new InternalServerErrorException("Could not auth to Twitter after trying once: " + response); - default: - throw new IOException("Error getting Twitter list: " + response); - } - } - - InputStream in = response.body().byteStream(); - Type listType = new TypeToken>() - { - }.getType(); - List statusesResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), listType); - - List items = new ArrayList<>(); - - for (TwitterStatusesResponseItem i : statusesResponse) - { - items.add(new FeedItem(FeedItemType.TWEET, - i.getUser().getProfileImageUrl(), - i.getUser().getScreenName(), - i.getText().replace("\n\n", " ").replaceAll("\n", " "), - "https://twitter.com/" + i.getUser().getScreenName() + "/status/" + i.getId(), - getTimestampFromSnowflake(i.getId()))); - } - - return items; - } - } - - private void updateToken() throws IOException - { - String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); - - Request request = new Request.Builder() - .url(AUTH_URL) - .header("Authorization", "Basic " + encodedCredentials) - .post(new FormBody.Builder().add("grant_type", "client_credentials").build()) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error authing to Twitter: " + response); - } - - InputStream in = response.body().byteStream(); - TwitterOAuth2TokenResponse tokenResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), TwitterOAuth2TokenResponse.class); - - if (!tokenResponse.getTokenType().equals("bearer")) - { - throw new InternalServerErrorException("Returned token was not a bearer token"); - } - - if (tokenResponse.getToken() == null) - { - throw new InternalServerErrorException("Returned token was null"); - } - - token = tokenResponse.getToken(); - } - } - - /** - * Extracts the UTC timestamp from a Twitter snowflake as per - * https://github.com/client9/snowflake2time/blob/master/python/snowflake.py#L24 - */ - private long getTimestampFromSnowflake(long snowflake) - { - return (snowflake >> 22) + 1288834974657L; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java deleted file mode 100644 index 90b37c5021..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import lombok.Data; - -@Data -class TwitterStatusesResponseItem -{ - private long id; - private String text; - private TwitterStatusesResponseItemUser user; -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java deleted file mode 100644 index 94fe9360f9..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.annotations.SerializedName; -import lombok.Data; - -@Data -class TwitterStatusesResponseItemUser -{ - @SerializedName("screen_name") - private String screenName; - - @SerializedName("profile_image_url_https") - private String profileImageUrl; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java deleted file mode 100644 index 509f2bdb70..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import com.google.gson.Gson; -import java.io.IOException; -import java.time.Instant; -import java.util.Collection; -import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.ge.GrandExchangeTrade; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/ge") -public class GrandExchangeController -{ - private static final Gson GSON = RuneLiteAPI.GSON; - - private final GrandExchangeService grandExchangeService; - private final AuthFilter authFilter; - private final RedisPool redisPool; - - @Autowired - public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter, RedisPool redisPool) - { - this.grandExchangeService = grandExchangeService; - this.authFilter = authFilter; - this.redisPool = redisPool; - } - - @PostMapping - public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException - { - SessionEntry session = null; - if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) - { - session = authFilter.handle(request, response); - if (session == null) - { - // error is set here on the response, so we shouldn't continue - return; - } - } - Integer userId = session == null ? null : session.getUser(); - - // We don't keep track of pending trades in the web UI, so only add cancelled or completed trades - if (userId != null && - grandExchangeTrade.getQty() > 0 && - (grandExchangeTrade.isCancel() || grandExchangeTrade.getQty() == grandExchangeTrade.getTotal())) - { - grandExchangeService.add(userId, grandExchangeTrade); - } - - Trade trade = new Trade(); - trade.setBuy(grandExchangeTrade.isBuy()); - trade.setCancel(grandExchangeTrade.isCancel()); - trade.setLogin(grandExchangeTrade.isLogin()); - trade.setItemId(grandExchangeTrade.getItemId()); - trade.setQty(grandExchangeTrade.getQty()); - trade.setDqty(grandExchangeTrade.getDqty()); - trade.setTotal(grandExchangeTrade.getTotal()); - trade.setSpent(grandExchangeTrade.getDspent()); - trade.setOffer(grandExchangeTrade.getOffer()); - trade.setSlot(grandExchangeTrade.getSlot()); - trade.setTime((int) (System.currentTimeMillis() / 1000L)); - trade.setMachineId(request.getHeader(RuneLiteAPI.RUNELITE_MACHINEID)); - trade.setUserId(userId); - trade.setIp(request.getHeader("X-Forwarded-For")); - trade.setUa(request.getHeader("User-Agent")); - trade.setWorldType(grandExchangeTrade.getWorldType()); - trade.setSeq(grandExchangeTrade.getSeq()); - Instant resetTime = grandExchangeTrade.getResetTime(); - trade.setResetTime(resetTime == null ? 0L : resetTime.getEpochSecond()); - - String json = GSON.toJson(trade); - try (Jedis jedis = redisPool.getResource()) - { - jedis.publish("ge", json); - } - } - - @GetMapping - public Collection get(HttpServletRequest request, HttpServletResponse response, - @RequestParam(required = false, defaultValue = "1024") int limit, - @RequestParam(required = false, defaultValue = "0") int offset) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return null; - } - - return grandExchangeService.get(session.getUser(), limit, offset).stream() - .map(GrandExchangeController::convert) - .collect(Collectors.toList()); - } - - private static GrandExchangeTradeHistory convert(TradeEntry tradeEntry) - { - GrandExchangeTradeHistory grandExchangeTrade = new GrandExchangeTradeHistory(); - grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY); - grandExchangeTrade.setItemId(tradeEntry.getItem()); - grandExchangeTrade.setQuantity(tradeEntry.getQuantity()); - grandExchangeTrade.setPrice(tradeEntry.getPrice()); - grandExchangeTrade.setTime(tradeEntry.getTime()); - return grandExchangeTrade; - } - - @DeleteMapping - public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - grandExchangeService.delete(session.getUser()); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java deleted file mode 100644 index 227d5e1159..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import java.util.Collection; -import net.runelite.http.api.ge.GrandExchangeTrade; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Sql2o; - -@Service -public class GrandExchangeService -{ - private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" + - " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + - " `user` int(11) NOT NULL,\n" + - " `action` enum('BUY','SELL') NOT NULL,\n" + - " `item` int(11) NOT NULL,\n" + - " `quantity` int(11) NOT NULL,\n" + - " `price` int(11) NOT NULL,\n" + - " `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + - " PRIMARY KEY (`id`),\n" + - " KEY `user_time` (`user`, `time`),\n" + - " KEY `time` (`time`),\n" + - " CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" + - ") ENGINE=InnoDB;"; - - private final Sql2o sql2o; - private final int historyDays; - - @Autowired - public GrandExchangeService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${runelite.ge.history}") int historyDays - ) - { - this.sql2o = sql2o; - this.historyDays = historyDays; - - // Ensure necessary tables exist - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_TABLE).executeUpdate(); - } - } - - public void add(int userId, GrandExchangeTrade grandExchangeTrade) - { - try (Connection con = sql2o.open()) - { - con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," + - " :action, :item, :quantity, :price)") - .addParameter("user", userId) - .addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL") - .addParameter("item", grandExchangeTrade.getItemId()) - .addParameter("quantity", grandExchangeTrade.getQty()) - .addParameter("price", grandExchangeTrade.getSpent() / grandExchangeTrade.getQty()) - .executeUpdate(); - } - } - - public Collection get(int userId, int limit, int offset) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset") - .addParameter("user", userId) - .addParameter("limit", limit) - .addParameter("offset", offset) - .executeAndFetch(TradeEntry.class); - } - } - - public void delete(int userId) - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from ge_trades where user = :user") - .addParameter("user", userId) - .executeUpdate(); - } - } - - @Scheduled(fixedDelay = 60 * 60 * 1000) - public void expire() - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from ge_trades where time < current_timestamp - interval " + historyDays + " day") - .executeUpdate(); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java deleted file mode 100644 index c45f5acf4f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.ge; - -import java.time.Instant; -import lombok.Data; - -@Data -class GrandExchangeTradeHistory -{ - private boolean buy; - private int itemId; - private int quantity; - private int price; - private Instant time; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/Trade.java b/http-service/src/main/java/net/runelite/http/service/ge/Trade.java deleted file mode 100644 index 7ad01f322a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/Trade.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.ge; - -import lombok.Data; -import net.runelite.http.api.worlds.WorldType; - -@Data -class Trade -{ - private boolean buy; - private boolean cancel; - private boolean login; - private int itemId; - private int qty; - private int dqty; - private int total; - private int spent; - private int offer; - private int slot; - private int time; - private String machineId; - private Integer userId; - private String ip; - private String ua; - private WorldType worldType; - private int seq; - private long resetTime; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java deleted file mode 100644 index fcc96d615f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -enum TradeAction -{ - BUY, - SELL; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java deleted file mode 100644 index bca3869811..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import java.time.Instant; -import lombok.Data; - -@Data -class TradeEntry -{ - private int id; - private int user; - private TradeAction action; - private int item; - private int quantity; - private int price; - private Instant time; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemController.java b/http-service/src/main/java/net/runelite/http/service/item/ItemController.java deleted file mode 100644 index e546344d4c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemController.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.item; - -import com.google.common.base.Suppliers; -import com.google.common.hash.HashCode; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import net.runelite.http.api.item.ItemPrice; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.CacheControl; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/item") -public class ItemController -{ - private static class MemoizedPrices - { - final ItemPrice[] prices; - final String hash; - - MemoizedPrices(ItemPrice[] prices) - { - this.prices = prices; - - Hasher hasher = Hashing.sha256().newHasher(); - for (ItemPrice itemPrice : prices) - { - hasher.putInt(itemPrice.getId()).putInt(itemPrice.getPrice()); - } - HashCode code = hasher.hash(); - hash = code.toString(); - } - } - - private final ItemService itemService; - private final int priceCache; - - private final Supplier memoizedPrices; - - @Autowired - public ItemController( - ItemService itemService, - @Value("${runelite.price.cache}") int priceCache - ) - { - this.itemService = itemService; - this.priceCache = priceCache; - - memoizedPrices = Suppliers.memoizeWithExpiration(() -> new MemoizedPrices(itemService.fetchPrices().stream() - .map(priceEntry -> - { - ItemPrice itemPrice = new ItemPrice(); - itemPrice.setId(priceEntry.getItem()); - itemPrice.setName(priceEntry.getName()); - itemPrice.setPrice(priceEntry.getPrice()); - itemPrice.setWikiPrice(computeWikiPrice(priceEntry)); - return itemPrice; - }) - .toArray(ItemPrice[]::new)), priceCache, TimeUnit.MINUTES); - } - - private static int computeWikiPrice(PriceEntry priceEntry) - { - if (priceEntry.getLow() > 0 && priceEntry.getHigh() > 0) - { - return (priceEntry.getLow() + priceEntry.getHigh()) / 2; - } - else - { - return Math.max(priceEntry.getLow(), priceEntry.getHigh()); - } - } - - @GetMapping("/prices") - public ResponseEntity prices() - { - MemoizedPrices memorizedPrices = this.memoizedPrices.get(); - return ResponseEntity.ok() - .eTag(memorizedPrices.hash) - .cacheControl(CacheControl.maxAge(priceCache, TimeUnit.MINUTES).cachePublic()) - .body(memorizedPrices.prices); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java b/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java deleted file mode 100644 index 41186b1608..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.time.Instant; -import lombok.Data; -import net.runelite.http.api.item.ItemType; - -@Data -public class ItemEntry -{ - private int id; - private String name; - private String description; - private ItemType type; - private Instant timestamp; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemService.java b/http-service/src/main/java/net/runelite/http/service/item/ItemService.java deleted file mode 100644 index bc3f03e70c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemService.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.item; - -import com.google.gson.JsonParseException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.Random; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.definitions.ItemDefinition; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.item.ItemType; -import net.runelite.http.service.cache.CacheService; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class ItemService -{ - private static final String CREATE_ITEMS = "CREATE TABLE IF NOT EXISTS `items` (\n" - + " `id` int(11) NOT NULL,\n" - + " `name` tinytext NOT NULL,\n" - + " `description` tinytext NOT NULL,\n" - + " `type` enum('DEFAULT') NOT NULL,\n" - + " `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " PRIMARY KEY (`id`)\n" - + ") ENGINE=InnoDB"; - - private static final String CREATE_PRICES = "CREATE TABLE IF NOT EXISTS `prices` (\n" - + " `item` int(11) NOT NULL,\n" - + " `price` int(11) NOT NULL,\n" - + " `time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" - + " `fetched_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" - + " UNIQUE KEY `item_time` (`item`,`time`),\n" - + " KEY `item_fetched_time` (`item`,`fetched_time`)\n" - + ") ENGINE=InnoDB"; - - private final Sql2o sql2o; - private final CacheService cacheService; - private final OkHttpClient okHttpClient; - private final HttpUrl itemUrl; - private final HttpUrl priceUrl; - - private int[] tradeableItems; - private final Random random = new Random(); - - @Autowired - public ItemService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - CacheService cacheService, - OkHttpClient okHttpClient, - @Value("${runelite.item.itemUrl}") String itemUrl, - @Value("${runelite.item.priceUrl}") String priceUrl - ) - { - this.sql2o = sql2o; - this.cacheService = cacheService; - this.okHttpClient = okHttpClient; - this.itemUrl = HttpUrl.get(itemUrl); - this.priceUrl = HttpUrl.get(priceUrl); - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_ITEMS) - .executeUpdate(); - - con.createQuery(CREATE_PRICES) - .executeUpdate(); - } - } - - public ItemEntry getItem(int itemId) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select id, name, description, type from items where id = :id") - .addParameter("id", itemId) - .executeAndFetchFirst(ItemEntry.class); - } - } - - public ItemEntry fetchItem(int itemId) - { - try - { - RSItem rsItem = fetchRSItem(itemId); - - try (Connection con = sql2o.open()) - { - con.createQuery("insert into items (id, name, description, type) values (:id," - + " :name, :description, :type) ON DUPLICATE KEY UPDATE name = :name," - + " description = :description, type = :type") - .addParameter("id", rsItem.getId()) - .addParameter("name", rsItem.getName()) - .addParameter("description", rsItem.getDescription()) - .addParameter("type", rsItem.getType()) - .executeUpdate(); - } - - ItemEntry item = new ItemEntry(); - item.setId(itemId); - item.setName(rsItem.getName()); - item.setDescription(rsItem.getDescription()); - item.setType(ItemType.of(rsItem.getType())); - return item; - } - catch (IOException ex) - { - log.warn("unable to fetch item {}", itemId, ex); - return null; - } - } - - private void fetchPrice(int itemId) - { - RSPrices rsprice; - try - { - rsprice = fetchRSPrices(itemId); - } - catch (IOException ex) - { - log.warn("unable to fetch price for item {}", itemId, ex); - return; - } - - try (Connection con = sql2o.beginTransaction()) - { - Instant now = Instant.now(); - - Query query = con.createQuery("insert into prices (item, price, time, fetched_time) values (:item, :price, :time, :fetched_time) " - + "ON DUPLICATE KEY UPDATE price = VALUES(price), fetched_time = VALUES(fetched_time)"); - - for (Map.Entry entry : rsprice.getDaily().entrySet()) - { - long ts = entry.getKey(); // ms since epoch - int price = entry.getValue(); // gp - - Instant time = Instant.ofEpochMilli(ts); - - query - .addParameter("item", itemId) - .addParameter("price", price) - .addParameter("time", time) - .addParameter("fetched_time", now) - .addToBatch(); - } - - query.executeBatch(); - con.commit(false); - } - } - - public List fetchPrices() - { - try (Connection con = sql2o.beginTransaction()) - { - Query query = con.createQuery("select t2.item, t3.name, t2.time, prices.price, prices.fetched_time, t4.high, t4.low" + - " from (select t1.item as item, max(t1.time) as time from prices t1 group by item) t2" + - " join prices on t2.item=prices.item and t2.time=prices.time" + - " join items t3 on t2.item=t3.id" + - " join wiki_prices t4 on t2.item=t4.item_id"); - return query.executeAndFetch(PriceEntry.class); - } - } - - private RSItem fetchRSItem(int itemId) throws IOException - { - HttpUrl itemUrl = this.itemUrl - .newBuilder() - .addQueryParameter("item", "" + itemId) - .build(); - - Request request = new Request.Builder() - .url(itemUrl) - .build(); - - RSItemResponse itemResponse = fetchJson(request, RSItemResponse.class); - return itemResponse.getItem(); - - } - - private RSPrices fetchRSPrices(int itemId) throws IOException - { - HttpUrl priceUrl = this.priceUrl - .newBuilder() - .addPathSegment(itemId + ".json") - .build(); - - Request request = new Request.Builder() - .url(priceUrl) - .build(); - - return fetchJson(request, RSPrices.class); - } - - private T fetchJson(Request request, Class clazz) throws IOException - { - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Unsuccessful http response: " + response); - } - - InputStream in = response.body().byteStream(); - return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), clazz); - } - catch (JsonParseException ex) - { - throw new IOException(ex); - } - } - - @Scheduled(fixedDelay = 20_000) - public void crawlPrices() - { - if (tradeableItems == null || tradeableItems.length == 0) - { - return; - } - - int idx = random.nextInt(tradeableItems.length); - int id = tradeableItems[idx]; - - log.debug("Fetching price for {}", id); - - // check if the item name or description has changed - fetchItem(id); - fetchPrice(id); - } - - @Scheduled(fixedDelay = 1_800_000) // 30 minutes - public void reloadItems() throws IOException - { - List items = cacheService.getItems(); - if (items.isEmpty()) - { - log.warn("Failed to load any items from cache, item price updating will be disabled"); - } - - tradeableItems = items.stream() - .filter(ItemDefinition::isTradeable) - .mapToInt(ItemDefinition::getId) - .toArray(); - - log.debug("Loaded {} tradeable items", tradeableItems.length); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java b/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java deleted file mode 100644 index 4d29d7e98d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.time.Instant; -import lombok.Data; - -@Data -class PriceEntry -{ - private int item; - private String name; - private int price; - private Instant time; - private Instant fetched_time; - private int high; - private int low; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItem.java b/http-service/src/main/java/net/runelite/http/service/item/RSItem.java deleted file mode 100644 index 17e3352f6d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSItem.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import lombok.Data; - -@Data -class RSItem -{ - private int id; - private String name; - private String description; - private String type; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java b/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java deleted file mode 100644 index c0305cd552..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import lombok.Data; - -@Data -class RSItemResponse -{ - private RSItem item; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java b/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java deleted file mode 100644 index 04331d753e..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.util.Map; -import lombok.Data; - -@Data -public class RSPrices -{ - /** - * unix time in ms to price in gp - */ - private Map daily; -} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java deleted file mode 100644 index 4cb3375154..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.loottracker; - -import java.time.Instant; -import lombok.Data; -import net.runelite.http.api.loottracker.LootRecordType; - -@Data -class LootResult -{ - private int killId; - private Instant first_time; - private Instant last_time; - private LootRecordType type; - private String eventId; - private int amount; - private int itemId; - private int itemQuantity; -} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java deleted file mode 100644 index ef39ac0d50..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * Copyright (c) 2018, Adam - * 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.loottracker; - -import com.google.api.client.http.HttpStatusCodes; -import com.google.gson.Gson; -import java.io.IOException; -import java.util.Collection; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.loottracker.LootAggregate; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/loottracker") -public class LootTrackerController -{ - private static final Gson GSON = RuneLiteAPI.GSON; - - @Autowired - private LootTrackerService service; - - @Autowired - private RedisPool redisPool; - - @Autowired - private AuthFilter auth; - - @RequestMapping(method = RequestMethod.POST) - public void storeLootRecord(HttpServletRequest request, HttpServletResponse response, @RequestBody Collection records) throws IOException - { - SessionEntry session = null; - if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) - { - session = auth.handle(request, response); - if (session == null) - { - // error is set here on the response, so we shouldn't continue - return; - } - } - Integer userId = session == null ? null : session.getUser(); - - if (userId != null) - { - service.store(records, userId); - } - response.setStatus(HttpStatusCodes.STATUS_CODE_OK); - - try (Jedis jedis = redisPool.getResource()) - { - jedis.publish("drops", GSON.toJson(records)); - } - } - - @GetMapping - public Collection getLootAggregate(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException - { - SessionEntry e = auth.handle(request, response); - if (e == null) - { - response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); - return null; - } - - return service.get(e.getUser(), count, start); - } - - @DeleteMapping - public void deleteLoot(HttpServletRequest request, HttpServletResponse response, - @RequestParam(required = false) String eventId) throws IOException - { - SessionEntry e = auth.handle(request, response); - if (e == null) - { - response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); - return; - } - - service.delete(e.getUser(), eventId); - } -} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java deleted file mode 100644 index 4836afd97d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * Copyright (c) 2018, Adam - * 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.loottracker; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.runelite.http.api.loottracker.GameItem; -import net.runelite.http.api.loottracker.LootAggregate; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.api.loottracker.LootRecordType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -public class LootTrackerService -{ - private static final String CREATE_KILLS = "CREATE TABLE IF NOT EXISTS `loottracker_kills` (\n" + - " `id` bigint NOT NULL AUTO_INCREMENT,\n" + - " `first_time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + - " `last_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n" + - " `accountId` int(11) NOT NULL,\n" + - " `type` enum('NPC','PLAYER','EVENT','PICKPOCKET','UNKNOWN') NOT NULL,\n" + - " `eventId` varchar(255) NOT NULL,\n" + - " `amount` int(11) NOT NULL,\n" + - " PRIMARY KEY (`id`),\n" + - " FOREIGN KEY (accountId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,\n" + - " INDEX idx_acc_lasttime (`accountId` ,`last_time`),\n" + - " UNIQUE INDEX idx_acc_type_event (`accountId`, `type`, `eventId`),\n" + - " INDEX idx_time (last_time)" + - ") ENGINE=InnoDB;"; - - private static final String CREATE_DROPS = "CREATE TABLE IF NOT EXISTS `loottracker_drops` (\n" + - " `killId` bigint NOT NULL,\n" + - " `itemId` int(11) NOT NULL,\n" + - " `itemQuantity` int(11) NOT NULL,\n" + - " UNIQUE INDEX idx_kill_item (`killId`, `itemId`),\n" + - " FOREIGN KEY (killId) REFERENCES loottracker_kills(id) ON DELETE CASCADE\n" + - ") ENGINE=InnoDB;\n"; - - // Queries for inserting kills - private static final String INSERT_KILL_QUERY = "INSERT INTO loottracker_kills (accountId, type, eventId, amount) VALUES (:accountId, :type, :eventId, :kills) ON DUPLICATE KEY UPDATE amount = amount + :kills"; - private static final String INSERT_DROP_QUERY = "INSERT INTO loottracker_drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity) ON DUPLICATE KEY UPDATE itemQuantity = itemQuantity + :itemQuantity"; - - private static final String SELECT_LOOT_QUERY = "SELECT killId,first_time,last_time,type,eventId,amount,itemId,itemQuantity FROM loottracker_kills JOIN loottracker_drops ON loottracker_drops.killId = loottracker_kills.id WHERE accountId = :accountId ORDER BY last_time DESC LIMIT :limit OFFSET :offset"; - - private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM loottracker_kills WHERE accountId = :accountId"; - private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM loottracker_kills WHERE accountId = :accountId AND eventId = :eventId"; - - private final Sql2o sql2o; - private final int historyDays; - - @Autowired - public LootTrackerService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${runelite.loottracker.history}") int historyDays - ) - { - this.sql2o = sql2o; - this.historyDays = historyDays; - - // Ensure necessary tables exist - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_KILLS).executeUpdate(); - con.createQuery(CREATE_DROPS).executeUpdate(); - } - } - - @RequiredArgsConstructor - @EqualsAndHashCode(exclude = {"kills", "drops"}) - @Getter - private static class AggregateLootRecord - { - final LootRecordType type; - final String eventId; - int kills = 0; - Map drops = new HashMap<>(); - } - - @RequiredArgsConstructor - @EqualsAndHashCode(exclude = "qty") - @Getter - private static class AggregateDrop - { - final int id; - int qty = 0; - } - - private static Collection aggregate(Collection records) - { - Map combinedRecords = new HashMap<>(); - for (LootRecord record : records) - { - AggregateLootRecord r = new AggregateLootRecord(record.getType(), record.getEventId()); - r = combinedRecords.computeIfAbsent(r, (k) -> k); - ++r.kills; - - // Combine drops - for (GameItem gameItem : record.getDrops()) - { - AggregateDrop cd = new AggregateDrop(gameItem.getId()); - cd = r.drops.computeIfAbsent(cd, (k) -> k); - cd.qty += gameItem.getQty(); - } - } - return combinedRecords.values(); - } - - /** - * Store LootRecord - * - * @param records LootRecords to store - * @param accountId runelite account id to tie data too - */ - public void store(Collection records, int accountId) - { - Collection combinedRecords = aggregate(records); - - try (Connection con = sql2o.beginTransaction()) - { - Query killQuery = con.createQuery(INSERT_KILL_QUERY, true); - Query insertDrop = con.createQuery(INSERT_DROP_QUERY); - - for (AggregateLootRecord record : combinedRecords) - { - killQuery - .addParameter("accountId", accountId) - .addParameter("type", record.getType()) - .addParameter("eventId", record.getEventId()) - .addParameter("kills", record.getKills()) - .executeUpdate(); - Object[] keys = con.getKeys(); - - for (AggregateDrop drop : record.getDrops().values()) - { - insertDrop - .addParameter("killId", keys[0]) - .addParameter("itemId", drop.getId()) - .addParameter("itemQuantity", drop.getQty()) - .addToBatch(); - } - - insertDrop.executeBatch(); - } - - con.commit(false); - } - } - - public Collection get(int accountId, int limit, int offset) - { - List lootResults; - - try (Connection con = sql2o.open()) - { - lootResults = con.createQuery(SELECT_LOOT_QUERY) - .addParameter("accountId", accountId) - .addParameter("limit", limit) - .addParameter("offset", offset) - .executeAndFetch(LootResult.class); - } - - LootResult current = null; - List lootRecords = new ArrayList<>(); - List gameItems = new ArrayList<>(); - - for (LootResult lootResult : lootResults) - { - if (current == null || current.getKillId() != lootResult.getKillId()) - { - if (!gameItems.isEmpty()) - { - LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); - lootRecords.add(lootRecord); - - gameItems = new ArrayList<>(); - } - - current = lootResult; - } - - GameItem gameItem = new GameItem(lootResult.getItemId(), lootResult.getItemQuantity()); - gameItems.add(gameItem); - } - - if (!gameItems.isEmpty()) - { - LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); - lootRecords.add(lootRecord); - } - - return lootRecords; - } - - public void delete(int accountId, String eventId) - { - try (Connection con = sql2o.open()) - { - if (eventId == null) - { - con.createQuery(DELETE_LOOT_ACCOUNT) - .addParameter("accountId", accountId) - .executeUpdate(); - } - else - { - con.createQuery(DELETE_LOOT_ACCOUNT_EVENTID) - .addParameter("accountId", accountId) - .addParameter("eventId", eventId) - .executeUpdate(); - } - } - } - - @Scheduled(fixedDelay = 60 * 60 * 1000) - public void expire() - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from loottracker_kills where last_time < current_timestamp() - interval " + historyDays + " day") - .executeUpdate(); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java b/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java deleted file mode 100644 index f9f424dca7..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.pluginhub; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; -import javax.servlet.http.HttpServletRequest; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/pluginhub") -public class PluginHubController -{ - @Value("${pluginhub.stats.days:7}") - private int days; - - @Value("${pluginhub.stats.expire:90}") - private int expireDays; - - @Autowired - private RedisPool redisPool; - - private final Cache pluginCache = CacheBuilder.newBuilder() - .maximumSize(512L) - .build(); - - private Map pluginCounts = Collections.emptyMap(); - - @GetMapping - public ResponseEntity> get() - { - if (pluginCounts.isEmpty()) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES).cachePublic()) - .body(pluginCounts); - } - - @PostMapping - public void submit(HttpServletRequest request, @RequestBody String[] plugins) - { - final String date = Instant.now().atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE); - final String ip = request.getHeader("X-Forwarded-For"); - try (Jedis jedis = redisPool.getResource()) - { - for (String plugin : plugins) - { - if (!plugin.matches("[a-z0-9-]+")) - { - continue; - } - - jedis.pfadd("pluginhub." + plugin + "." + date, ip); - - if (pluginCache.getIfPresent(plugin) == null) - { - jedis.sadd("pluginhub.plugins", plugin); - // additionally set the ttl on the hyperloglog since it might be a new key - jedis.expire("pluginhub." + plugin + "." + date, (int) (Duration.ofDays(expireDays).toMillis() / 1000L)); - - pluginCache.put(plugin, plugin); - } - } - } - } - - @Scheduled(fixedDelay = 1_800_000, initialDelay = 30_000) // 30 minutes with 30 second initial delay - public void rebuildCounts() - { - Map counts = new HashMap<>(); - try (Jedis jedis = redisPool.getResource()) - { - Set plugins = jedis.smembers("pluginhub.plugins"); - ZonedDateTime time = Instant.now().atZone(ZoneOffset.UTC); - - for (String plugin : plugins) - { - // When called with multiple keys, pfcount returns the approximated - // cardinality of the union of the HyperLogLogs. We use this to determine - // the number of users in the last N days. - String[] keys = IntStream.range(0, days - 1) - .mapToObj(time::minusDays) - .map(zdt -> "pluginhub." + plugin + "." + zdt.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .toArray(String[]::new); - long cnt = jedis.pfcount(keys); - if (cnt > 0) - { - counts.put(plugin, cnt); - } - } - } - pluginCounts = counts; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java b/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java deleted file mode 100644 index 785ad00266..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util; - -import java.sql.Timestamp; -import java.time.Instant; -import org.sql2o.converters.Converter; -import org.sql2o.converters.ConverterException; - -public class InstantConverter implements Converter -{ - @Override - public Instant convert(Object val) throws ConverterException - { - Timestamp ts = (Timestamp) val; - return ts.toInstant(); - } - - @Override - public Object toDatabaseParam(Instant val) - { - return Timestamp.from(val); - } - -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java deleted file mode 100644 index 62adc5b6fc..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) -public class InternalServerErrorException extends RuntimeException -{ - public InternalServerErrorException(String message) - { - super(message); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java deleted file mode 100644 index 83e04ceca6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not found") -public class NotFoundException extends RuntimeException -{ - -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java b/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java deleted file mode 100644 index c0d4a65a29..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.util.redis; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import redis.clients.jedis.Jedis; - -@Component -@Slf4j -public class RedisPool -{ - private final String redisHost; - private final BlockingQueue queue; - - RedisPool(@Value("${redis.pool.size:10}") int queueSize, @Value("${redis.host:localhost}") String redisHost) - { - this.redisHost = redisHost; - - queue = new ArrayBlockingQueue<>(queueSize); - for (int i = 0; i < queueSize; ++i) - { - Jedis jedis = new PooledJedis(redisHost); - queue.offer(jedis); - } - } - - public Jedis getResource() - { - Jedis jedis; - try - { - jedis = queue.poll(1, TimeUnit.SECONDS); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - if (jedis == null) - { - throw new RuntimeException("Unable to acquire connection from pool, timeout"); - } - return jedis; - } - - class PooledJedis extends Jedis - { - PooledJedis(String host) - { - super(host); - } - - @Override - public void close() - { - if (!getClient().isBroken()) - { - queue.offer(this); - return; - } - - log.warn("jedis client is broken, creating new client"); - - try - { - super.close(); - } - catch (Exception e) - { - log.warn("unable to close broken jedis", e); - } - - queue.offer(new PooledJedis(redisHost)); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java b/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java deleted file mode 100644 index 0723063b02..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.wiki; - -import java.util.Map; -import lombok.Data; - -@Data -class PriceResult -{ - @Data - static class Item - { - private int high; - private int highTime; - private int low; - private int lowTime; - } - - private Map data; -} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java b/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java deleted file mode 100644 index 2e32fc1808..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.wiki; - -import com.google.gson.JsonSyntaxException; -import java.io.IOException; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class WikiPriceService -{ - private static final String CREATE = "CREATE TABLE IF NOT EXISTS `wiki_prices` (\n" + - " `item_id` int(11) NOT NULL,\n" + - " `high` int(11) NOT NULL,\n" + - " `highTime` int(11) NOT NULL,\n" + - " `low` int(11) NOT NULL,\n" + - " `lowTime` int(11) NOT NULL,\n" + - " `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" + - " PRIMARY KEY (`item_id`)\n" + - ") ENGINE=InnoDB;"; - - private final Sql2o sql2o; - private final OkHttpClient okHttpClient; - private final HttpUrl wikiUrl; - - @Autowired - public WikiPriceService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - OkHttpClient okHttpClient, - @Value("${runelite.wiki.url}") String url - ) - { - this.sql2o = sql2o; - this.okHttpClient = okHttpClient; - this.wikiUrl = HttpUrl.get(url); - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE).executeUpdate(); - } - } - - @Scheduled(initialDelay = 1000 * 5, fixedDelayString = "${runelite.wiki.poll.ms}") - private void updateDatabase() - { - try - { - PriceResult summary = getPrices(); - - try (Connection con = sql2o.beginTransaction()) - { - Query query = con.createQuery("INSERT INTO wiki_prices (item_id, high, highTime, low, lowTime)" - + " VALUES (:itemId, :high, :highTime, :low, :lowTime)" - + " ON DUPLICATE KEY UPDATE high = VALUES(high), highTime = VALUES(highTime)," - + " low = VALUES(low), lowTime = VALUES(lowTime)"); - - for (Map.Entry entry : summary.getData().entrySet()) - { - Integer itemId = entry.getKey(); - PriceResult.Item item = entry.getValue(); - - query - .addParameter("itemId", itemId) - .addParameter("high", item.getHigh()) - .addParameter("highTime", item.getHighTime()) - .addParameter("low", item.getLow()) - .addParameter("lowTime", item.getLowTime()) - .addToBatch(); - } - - query.executeBatch(); - con.commit(false); - } - } - catch (IOException e) - { - log.warn("Error while updating wiki prices", e); - } - } - - private PriceResult getPrices() throws IOException - { - Request request = new Request.Builder() - .url(wikiUrl) - .header("User-Agent", "RuneLite") - .build(); - - try (Response responseOk = okHttpClient.newCall(request).execute()) - { - if (!responseOk.isSuccessful()) - { - throw new IOException("Error retrieving prices: " + responseOk.message()); - } - - return RuneLiteAPI.GSON.fromJson(responseOk.body().string(), PriceResult.class); - } - catch (JsonSyntaxException ex) - { - throw new IOException(ex); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java b/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java deleted file mode 100644 index 642cd0440a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.worlds; - -import net.runelite.http.api.worlds.WorldType; - -enum ServiceWorldType -{ - MEMBERS(WorldType.MEMBERS, 1), - PVP(WorldType.PVP, 1 << 2), - BOUNTY(WorldType.BOUNTY, 1 << 5), - SKILL_TOTAL(WorldType.SKILL_TOTAL, 1 << 7), - HIGH_RISK(WorldType.HIGH_RISK, 1 << 10), - LAST_MAN_STANDING(WorldType.LAST_MAN_STANDING, 1 << 14), - NOSAVE_MODE(WorldType.NOSAVE_MODE, 1 << 25), - TOURNAMENT(WorldType.TOURNAMENT, 1 << 26), - DEADMAN(WorldType.DEADMAN, 1 << 29), - SEASONAL(WorldType.SEASONAL, 1 << 30); - - private final WorldType apiType; - private final int mask; - - ServiceWorldType(WorldType apiType, int mask) - { - this.apiType = apiType; - this.mask = mask; - } - - public WorldType getApiType() - { - return apiType; - } - - public int getMask() - { - return mask; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java deleted file mode 100644 index a0c71af52c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.worlds; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import net.runelite.http.api.worlds.WorldResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/worlds") -public class WorldController -{ - @Autowired - private WorldsService worldsService; - - private WorldResult worldResult; - - @GetMapping - public ResponseEntity listWorlds() - { - if (worldResult == null) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) - .body(worldResult); - } - - @Scheduled(fixedDelay = 60_000L) - public void refreshWorlds() throws IOException - { - worldResult = worldsService.getWorlds(); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java deleted file mode 100644 index 1f8debe7eb..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.worlds; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldResult; -import net.runelite.http.api.worlds.WorldType; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -public class WorldsService -{ - private final OkHttpClient okHttpClient; - private final HttpUrl url; - - @Autowired - public WorldsService( - OkHttpClient okHttpClient, - @Value("${runelite.worlds.url}") String url - ) - { - this.okHttpClient = okHttpClient; - this.url = HttpUrl.get(url); - } - - public WorldResult getWorlds() throws IOException - { - Request okrequest = new Request.Builder() - .url(url) - .build(); - - byte[] b; - - try (Response okresponse = okHttpClient.newCall(okrequest).execute()) - { - b = okresponse.body().bytes(); - } - - List worlds = new ArrayList<>(); - ByteBuffer buf = ByteBuffer.wrap(b); - - int length = buf.getInt(); - buf.limit(length + 4); - - int num = buf.getShort() & 0xFFFF; - - for (int i = 0; i < num; ++i) - { - final World.WorldBuilder worldBuilder = World.builder() - .id(buf.getShort() & 0xFFFF) - .types(getTypes(buf.getInt())) - .address(readString(buf)) - .activity(readString(buf)) - .location(buf.get() & 0xFF) - .players(buf.getShort()); - - worlds.add(worldBuilder.build()); - } - - WorldResult result = new WorldResult(); - result.setWorlds(worlds); - return result; - } - - private static EnumSet getTypes(int mask) - { - EnumSet types = EnumSet.noneOf(WorldType.class); - - for (ServiceWorldType type : ServiceWorldType.values()) - { - if ((mask & type.getMask()) != 0) - { - types.add(type.getApiType()); - } - } - - return types; - } - - private static String readString(ByteBuffer buf) - { - byte b; - StringBuilder sb = new StringBuilder(); - - for (;;) - { - b = buf.get(); - - if (b == 0) - { - break; - } - - sb.append((char) b); - } - - return sb.toString(); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java deleted file mode 100644 index 7c5f2bb5b0..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.xtea; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -class XteaCache -{ - private int region; - private int key1; - private int key2; - private int key3; - private int key4; -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java deleted file mode 100644 index 3868acb8c6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.xtea; - -import java.util.List; -import java.util.stream.Collectors; -import net.runelite.http.api.xtea.XteaKey; -import net.runelite.http.api.xtea.XteaRequest; -import net.runelite.http.service.util.exception.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -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; - -@RestController -@RequestMapping("/xtea") -public class XteaController -{ - @Autowired - private XteaService xteaService; - - @RequestMapping(method = POST) - public void submit(@RequestBody XteaRequest xteaRequest) - { - xteaService.submit(xteaRequest); - } - - @GetMapping - public List get() - { - return xteaService.get().stream() - .map(XteaController::entryToKey) - .collect(Collectors.toList()); - } - - @GetMapping("/{region}") - public XteaKey getRegion(@PathVariable int region) - { - XteaEntry xteaRegion = xteaService.getRegion(region); - if (xteaRegion == null) - { - throw new NotFoundException(); - } - - return entryToKey(xteaRegion); - } - - private static XteaKey entryToKey(XteaEntry xe) - { - XteaKey xteaKey = new XteaKey(); - xteaKey.setRegion(xe.getRegion()); - xteaKey.setKeys(new int[] - { - xe.getKey1(), - xe.getKey2(), - xe.getKey3(), - xe.getKey4() - }); - return xteaKey; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java deleted file mode 100644 index c5e60b1119..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.xtea; - -import java.time.Instant; -import lombok.Data; - -@Data -class XteaEntry -{ - private int region; - private Instant time; - private int rev; - private int key1; - private int key2; - private int key3; - private int key4; -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java deleted file mode 100644 index 8a5d651b05..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.xtea; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.io.IOException; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.IndexType; -import net.runelite.cache.fs.Container; -import net.runelite.cache.util.Djb2; -import net.runelite.http.api.xtea.XteaKey; -import net.runelite.http.api.xtea.XteaRequest; -import net.runelite.http.service.cache.CacheService; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.util.exception.InternalServerErrorException; -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.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class XteaService -{ - private static final String CREATE_SQL = "CREATE TABLE IF NOT EXISTS `xtea` (\n" - + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" - + " `region` int(11) NOT NULL,\n" - + " `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" - + " `rev` int(11) NOT NULL,\n" - + " `key1` int(11) NOT NULL,\n" - + " `key2` int(11) NOT NULL,\n" - + " `key3` int(11) NOT NULL,\n" - + " `key4` int(11) NOT NULL,\n" - + " PRIMARY KEY (`id`),\n" - + " KEY `region` (`region`,`time`)\n" - + ") ENGINE=InnoDB"; - - private final Sql2o sql2o; - private final CacheService cacheService; - - private final Cache keyCache = CacheBuilder.newBuilder() - .maximumSize(1024) - .build(); - - @Autowired - public XteaService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - CacheService cacheService - ) - { - this.sql2o = sql2o; - this.cacheService = cacheService; - - try (Connection con = sql2o.beginTransaction()) - { - con.createQuery(CREATE_SQL) - .executeUpdate(); - } - } - - private XteaEntry findLatestXtea(Connection con, int region) - { - return con.createQuery("select region, time, key1, key2, key3, key4 from xtea " - + "where region = :region " - + "order by time desc " - + "limit 1") - .addParameter("region", region) - .executeAndFetchFirst(XteaEntry.class); - } - - public void submit(XteaRequest xteaRequest) - { - boolean cached = true; - for (XteaKey key : xteaRequest.getKeys()) - { - int region = key.getRegion(); - int[] keys = key.getKeys(); - - if (keys.length != 4) - { - throw new IllegalArgumentException("Key length must be 4"); - } - - XteaCache xteaCache = keyCache.getIfPresent(region); - if (xteaCache == null - || xteaCache.getKey1() != keys[0] - || xteaCache.getKey2() != keys[1] - || xteaCache.getKey3() != keys[2] - || xteaCache.getKey4() != keys[3]) - { - cached = false; - keyCache.put(region, new XteaCache(region, keys[0], keys[1], keys[2], keys[3])); - } - } - - if (cached) - { - return; - } - - try (Connection con = sql2o.beginTransaction()) - { - CacheEntry cache = cacheService.findMostRecent(); - - if (cache == null) - { - throw new InternalServerErrorException("No most recent cache"); - } - - Query query = null; - - for (XteaKey key : xteaRequest.getKeys()) - { - int region = key.getRegion(); - int[] keys = key.getKeys(); - - XteaEntry xteaEntry = findLatestXtea(con, region); - - // already have these? - if (xteaEntry != null - && xteaEntry.getKey1() == keys[0] - && xteaEntry.getKey2() == keys[1] - && xteaEntry.getKey3() == keys[2] - && xteaEntry.getKey4() == keys[3]) - { - continue; - } - - ArchiveEntry archiveEntry = archiveForRegion(cache, region); - if (archiveEntry == null) - { - // the client sends 0,0,0,0 for non-existent regions, just ignore them - continue; - } - - if (!checkKeys(archiveEntry, keys)) - { - continue; - } - - if (query == null) - { - query = con.createQuery("insert into xtea (region, rev, key1, key2, key3, key4) " - + "values (:region, :rev, :key1, :key2, :key3, :key4)"); - } - - query.addParameter("region", region) - .addParameter("rev", xteaRequest.getRevision()) - .addParameter("key1", keys[0]) - .addParameter("key2", keys[1]) - .addParameter("key3", keys[2]) - .addParameter("key4", keys[3]) - .addToBatch(); - - log.debug("Inserted keys for {}: {}, {}, {}, {}", region, keys[0], keys[1], keys[2], keys[3]); - } - - if (query != null) - { - query.executeBatch(); - con.commit(false); - } - } - } - - public List get() - { - try (Connection con = sql2o.open()) - { - return con.createQuery( - "select t1.region, t2.time, t2.rev, t2.key1, t2.key2, t2.key3, t2.key4 from " + - "(select region,max(id) as id from xtea group by region) t1 " + - "join xtea t2 on t1.id = t2.id") - .executeAndFetch(XteaEntry.class); - } - } - - public XteaEntry getRegion(int region) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select region, time, rev, key1, key2, key3, key4 from xtea " - + "where region = :region order by time desc limit 1") - .addParameter("region", region) - .executeAndFetchFirst(XteaEntry.class); - } - } - - private ArchiveEntry archiveForRegion(CacheEntry cache, int regionId) - { - int x = regionId >>> 8; - int y = regionId & 0xFF; - - String archiveName = new StringBuilder() - .append('l') - .append(x) - .append('_') - .append(y) - .toString(); - int archiveNameHash = Djb2.hash(archiveName); - - return cacheService.findArchiveForTypeAndName(cache, IndexType.MAPS, archiveNameHash); - } - - private boolean checkKeys(ArchiveEntry archiveEntry, int[] keys) - { - byte[] data = cacheService.getArchive(archiveEntry); - if (data == null) - { - throw new InternalServerErrorException("Unable to get archive data for archive " + archiveEntry.getArchiveId()); - } - - try - { - Container.decompress(data, keys); - return true; - } - catch (IOException ex) - { - return false; - } - } -} diff --git a/http-service/src/main/resources/application-dev.yaml b/http-service/src/main/resources/application-dev.yaml deleted file mode 100644 index 2b24790c51..0000000000 --- a/http-service/src/main/resources/application-dev.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Enable debug logging -debug: true -logging.level.net.runelite: DEBUG - -# Development data sources -datasource: - runelite: - jndiName: - driverClassName: org.mariadb.jdbc.Driver - type: org.mariadb.jdbc.MariaDbDataSource - url: jdbc:mariadb://localhost:3306/runelite - username: runelite - password: runelite - runelite-cache: - jndiName: - driverClassName: org.mariadb.jdbc.Driver - type: org.mariadb.jdbc.MariaDbDataSource - url: jdbc:mariadb://localhost:3306/cache - username: runelite - password: runelite - -# Development mongo -mongo: - jndiName: - host: mongodb://localhost:27017 - -# Development oauth callback (without proxy) -oauth: - callback: http://localhost:8080/account/callback diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml deleted file mode 100644 index 7431545cbb..0000000000 --- a/http-service/src/main/resources/application.yaml +++ /dev/null @@ -1,61 +0,0 @@ -datasource: - runelite: - jndiName: java:comp/env/jdbc/runelite - runelite-cache: - jndiName: java:comp/env/jdbc/runelite-cache2 - -# By default Spring tries to register the datasource as an MXBean, -# so if multiple apis are deployed on one web container with -# shared datasource it tries to register it multiples times and -# fails when starting the 2nd api -spring.jmx.enabled: false - -# Google OAuth client -oauth: - client-id: - client-secret: - callback: https://api.runelite.net/oauth/ - -# Minio client storage for cache -minio: - endpoint: http://localhost:9000 - accesskey: AM54M27O4WZK65N6F8IP - secretkey: /PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP - bucket: runelite - -# Redis client -redis: - pool.size: 10 - host: tcp://localhost:6379 - -mongo: - jndiName: java:comp/env/mongodb/runelite - database: runelite - -runelite: - version: @project.version@ - commit: @git.commit.id.abbrev@ - dirty: @git.dirty@ - # Twitter client for feed - twitter: - consumerkey: - secretkey: - listid: 1185897074786742273 - ge: - history: 90 # days - loottracker: - history: 90 # days - wiki: - poll.ms: 300000 # 5 minutes - url: https://prices.runescape.wiki/api/v1/osrs/latest - price: - cache: 30 # minutes - feed: - rssUrl: https://runelite.net/atom.xml - worlds: - url: http://www.runescape.com/g=oldscape/slr.ws?order=LPWM - osrsnews: - rssUrl: https://services.runescape.com/m=news/latest_news.rss?oldschool=true - item: - itemUrl: https://services.runescape.com/m=itemdb_oldschool/api/catalogue/detail.json - priceUrl: https://services.runescape.com/m=itemdb_oldschool/api/graph \ No newline at end of file diff --git a/http-service/src/main/templates/markdown.hbs b/http-service/src/main/templates/markdown.hbs deleted file mode 100644 index 1beacd052a..0000000000 --- a/http-service/src/main/templates/markdown.hbs +++ /dev/null @@ -1,110 +0,0 @@ -{{#info}} -# {{title}} -{{join schemes " | "}}://{{host}}{{basePath}} - -{{description}} - -{{#contact}} -[**Contact the developer**](mailto:{{email}}) -{{/contact}} - -**Version** {{version}} - -{{#if termsOfService}} -[**Terms of Service**]({{termsOfService}}) -{{/if}} - -{{/info}} - -{{#if consumes}}__Consumes:__ {{join consumes ", "}}{{/if}} - -{{#if produces}}__Produces:__ {{join produces ", "}}{{/if}} - -{{#if securityDefinitions}} -# Security Definitions -{{> security}} -{{/if}} - -
-Table Of Contents -[toc] -
- -# APIs - -{{#each paths}} -## {{@key}} -{{#this}} -{{#get}} -### GET -{{> operation}} -{{/get}} - -{{#put}} -### PUT -{{> operation}} -{{/put}} - -{{#post}} -### POST - -{{> operation}} - -{{/post}} - -{{#delete}} -### DELETE -{{> operation}} -{{/delete}} - -{{#option}} -### OPTION -{{> operation}} -{{/option}} - -{{#patch}} -### PATCH -{{> operation}} -{{/patch}} - -{{#head}} -### HEAD -{{> operation}} -{{/head}} - -{{/this}} -{{/each}} - -# Definitions -{{#each definitions}} -## {{@key}} - - - - - - - - - - {{#each this.properties}} - - - - - - - - {{/each}} -
nametyperequireddescriptionexample
{{@key}} - {{#ifeq type "array"}} - {{#items.$ref}} - {{type}}[{{basename items.$ref}}] - {{/items.$ref}} - {{^items.$ref}}{{type}}[{{items.type}}]{{/items.$ref}} - {{else}} - {{#$ref}}{{basename $ref}}{{/$ref}} - {{^$ref}}{{type}}{{#format}} ({{format}}){{/format}}{{/$ref}} - {{/ifeq}} - {{#required}}required{{/required}}{{^required}}optional{{/required}}{{#description}}{{{description}}}{{/description}}{{^description}}-{{/description}}{{example}}
-{{/each}} diff --git a/http-service/src/main/templates/operation.hbs b/http-service/src/main/templates/operation.hbs deleted file mode 100644 index f7015850b8..0000000000 --- a/http-service/src/main/templates/operation.hbs +++ /dev/null @@ -1,71 +0,0 @@ -{{#deprecated}}-deprecated-{{/deprecated}} -{{summary}} - -{{description}} - -{{#if externalDocs.url}}{{externalDocs.description}}. [See external documents for more details]({{externalDocs.url}}) -{{/if}} - -{{#if security}} -#### Security -{{/if}} - -{{#security}} -{{#each this}} -* {{@key}} -{{#this}} * {{this}} -{{/this}} -{{/each}} -{{/security}} - -#### Request - -{{#if consumes}}__Content-Type:__ {{join consumes ", "}}{{/if}} - -##### Parameters -{{#if parameters}} - - - - - - - - - -{{/if}} - -{{#parameters}} - - - - - - -{{#ifeq in "body"}} - -{{else}} - {{#ifeq type "array"}} - - {{else}} - - {{/ifeq}} -{{/ifeq}} - -{{/parameters}} -{{#if parameters}} -
NameLocated inRequiredDescriptionDefaultSchema
{{name}}{{in}}{{#if required}}yes{{else}}no{{/if}}{{description}}{{#if pattern}} (**Pattern**: `{{pattern}}`){{/if}} - - {{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}} - {{#schema.$ref}}{{basename schema.$ref}} {{/schema.$ref}} - Array[{{items.type}}] ({{collectionFormat}}){{type}} {{#format}}({{format}}){{/format}}
-{{/if}} - - -#### Response - -{{#if produces}}__Content-Type:__ {{join produces ", "}}{{/if}} - -| Status Code | Reason | Response Model | -|-------------|-------------|----------------| -{{#each responses}}| {{@key}} | {{description}} | {{#schema.$ref}}{{basename schema.$ref}}{{/schema.$ref}}{{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}}{{^schema}} - {{/schema}}| -{{/each}} diff --git a/http-service/src/main/templates/security.hbs b/http-service/src/main/templates/security.hbs deleted file mode 100644 index 04f86e8380..0000000000 --- a/http-service/src/main/templates/security.hbs +++ /dev/null @@ -1,88 +0,0 @@ -{{#each securityDefinitions}} -### {{@key}} -{{#this}} -{{#ifeq type "oauth2"}} - - - - - -{{#if description}} - - - - -{{/if}} -{{#if authorizationUrl}} - - - - -{{/if}} -{{#if flow}} - - - - -{{/if}} -{{#if tokenUrl}} - - - - -{{/if}} -{{#if scopes}} - - -{{#each scopes}} - - - - -{{/each}} - -{{/if}} -
type{{type}}
description{{description}}
authorizationUrl{{authorizationUrl}}
flow{{flow}}
tokenUrl{{tokenUrl}}
scopes{{@key}}{{this}}
-{{/ifeq}} -{{#ifeq type "apiKey"}} - - - - - -{{#if description}} - - - - -{{/if}} -{{#if name}} - - - - -{{/if}} -{{#if in}} - - - - -{{/if}} -
type{{type}}
description{{description}}
name{{name}}
in{{in}}
-{{/ifeq}} -{{#ifeq type "basic"}} - - - - - -{{#if description}} - - - - -{{/if}} -
type{{type}}
description{{description}}
-{{/ifeq}} -{{/this}} -{{/each}} \ No newline at end of file diff --git a/http-service/src/main/templates/template.html.hbs b/http-service/src/main/templates/template.html.hbs deleted file mode 100644 index da587c2cc4..0000000000 --- a/http-service/src/main/templates/template.html.hbs +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - {{info.title}} {{info.version}} - - - - - \ No newline at end of file diff --git a/http-service/src/main/webapp/WEB-INF/web.xml b/http-service/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 0b07dbb973..0000000000 --- a/http-service/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - RuneLite API - \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java deleted file mode 100644 index 27320f3f72..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@WebMvcTest(ConfigController.class) -@ActiveProfiles("test") -public class ConfigControllerTest -{ - @Autowired - private MockMvc mockMvc; - - @MockBean - private ConfigService configService; - - @MockBean - private AuthFilter authFilter; - - @Before - public void before() throws IOException - { - when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) - .thenReturn(mock(SessionEntry.class)); - - when(configService.setKey(anyInt(), anyString(), anyString())).thenReturn(true); - } - - @Test - public void testSetKey() throws Exception - { - mockMvc.perform(put("/config/key") - .content("value") - .contentType(MediaType.TEXT_PLAIN)) - .andExpect(status().isOk()); - - verify(configService).setKey(anyInt(), eq("key"), eq("value")); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java deleted file mode 100644 index a08a9a7160..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import com.google.common.collect.ImmutableMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import org.junit.Test; - -public class ConfigServiceTest -{ - @Test - public void testParseJsonString() - { - assertEquals(1, ConfigService.parseJsonString("1")); - assertEquals(3.14, ConfigService.parseJsonString("3.14")); - assertEquals(1L << 32, ConfigService.parseJsonString("4294967296")); - assertEquals("test", ConfigService.parseJsonString("test")); - assertEquals("test", ConfigService.parseJsonString("\"test\"")); - assertEquals(ImmutableMap.of("key", "value"), ConfigService.parseJsonString("{\"key\": \"value\"}")); - } - - @Test - public void testValidateJson() - { - assertTrue(ConfigService.validateJson("1")); - assertTrue(ConfigService.validateJson("3.14")); - assertTrue(ConfigService.validateJson("test")); - assertTrue(ConfigService.validateJson("\"test\"")); - assertTrue(ConfigService.validateJson("key:value")); - assertTrue(ConfigService.validateJson("{\"key\": \"value\"}")); - assertTrue(ConfigService.validateJson("\n")); - } - - @Test - public void testMaybeJson() - { - assertFalse(ConfigService.isMaybeJson("string")); - assertFalse(ConfigService.isMaybeJson("string with spaces")); - - assertTrue(ConfigService.isMaybeJson("true")); - assertTrue(ConfigService.isMaybeJson("false")); - assertTrue(ConfigService.isMaybeJson("1")); - assertTrue(ConfigService.isMaybeJson("1.2")); - assertTrue(ConfigService.isMaybeJson("\"quote\"")); - assertTrue(ConfigService.isMaybeJson("{\"key\": \"value\"}")); - assertTrue(ConfigService.isMaybeJson("[42]")); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java deleted file mode 100644 index 68e64270d6..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.loottracker; - -import java.io.IOException; -import java.time.Instant; -import java.time.temporal.ChronoField; -import java.util.Collections; -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.loottracker.GameItem; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.api.loottracker.LootRecordType; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import redis.clients.jedis.Jedis; - -@RunWith(SpringRunner.class) -@WebMvcTest(LootTrackerController.class) -@ActiveProfiles("test") -public class LootTrackerControllerTest -{ - @Autowired - private MockMvc mockMvc; - - @MockBean - private LootTrackerService lootTrackerService; - - @MockBean - private AuthFilter authFilter; - - @MockBean - private RedisPool redisPool; - - @Before - public void before() throws IOException - { - when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) - .thenReturn(mock(SessionEntry.class)); - - when(redisPool.getResource()).thenReturn(mock(Jedis.class)); - } - - @Test - public void storeLootRecord() throws Exception - { - LootRecord lootRecord = new LootRecord(); - lootRecord.setType(LootRecordType.NPC); - lootRecord.setTime(Instant.now().with(ChronoField.NANO_OF_SECOND, 0)); - lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1))); - - String data = RuneLiteAPI.GSON.toJson(Collections.singletonList(lootRecord)); - mockMvc.perform(post("/loottracker") - .header(RuneLiteAPI.RUNELITE_AUTH, UUID.nameUUIDFromBytes("test".getBytes())) - .content(data) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - - verify(lootTrackerService).store(eq(Collections.singletonList(lootRecord)), anyInt()); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java deleted file mode 100644 index b6275d7c48..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.worlds; - -import java.io.IOException; -import java.io.InputStream; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldResult; -import net.runelite.http.api.worlds.WorldType; -import okhttp3.OkHttpClient; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okio.Buffer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sql2o.tools.IOUtils; - -public class WorldsServiceTest -{ - @Rule - public final MockWebServer server = new MockWebServer(); - - @Before - public void before() throws IOException - { - InputStream in = WorldsServiceTest.class.getResourceAsStream("worldlist"); - byte[] worldData = IOUtils.toByteArray(in); - - Buffer buffer = new Buffer(); - buffer.write(worldData); - - server.enqueue(new MockResponse().setBody(buffer)); - } - - @Test - public void testListWorlds() throws Exception - { - WorldsService worlds = new WorldsService(new OkHttpClient(), server.url("/").toString()); - - WorldResult worldResult = worlds.getWorlds(); - assertEquals(82, worldResult.getWorlds().size()); - - World world = worldResult.findWorld(385); - assertNotNull(world); - assertTrue(world.getTypes().contains(WorldType.SKILL_TOTAL)); - - for (World testWorld : worldResult.getWorlds()) - { - assertNotNull("Missing a region in WorldRegion enum", testWorld.getRegion()); - } - } - -} diff --git a/http-service/src/test/resources/application-test.yaml b/http-service/src/test/resources/application-test.yaml deleted file mode 100644 index 3a8e416a54..0000000000 --- a/http-service/src/test/resources/application-test.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Use in-memory database for tests -datasource: - runelite: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:runelite - runelite-cache: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:cache - runelite-tracker: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:xptracker - -mongo: - jndiName: - host: mongodb://localhost:27017 \ No newline at end of file diff --git a/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist b/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist deleted file mode 100644 index 1d1360e5795d066b068e095cf2a033a504405ad6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5000 zcmeHKOK%%h6uu{Nt&HNnr;&XfUL@?A&0Xv2`>KbrNjykW>2xs2%({goUE2ojRl+UsP2YF3kRF>f)3pl!mq&wAvxSj*vi<` zL+jfJeGeWY1bdoC8M!GddJqr^AHcJOR^c?>rfy383=~o`EgbG-%g){BFW?y(jytE( z4^`J~%Z8WuXg~ztgnJ0Z;z}$8;g*g%lgkR9g4r$CbK^cTzJkXHugooe2$gZDT;KJ# z5d9785>A!3$~+oBz{>`Iajg@H&p1F21Jocycp5{fJHd`3fGmV+CeBADvbNG8Q=gAg+81nq!QO^DM%tc zH84YRq~rOT1m2nR1XRk~LWtMl z2?8qTYY^fMxR-z|?j4iUn{bAJO8M>y@ir_|5ZBq9v=3&$j#M`;+($4^Kz81CLVOIX z1XRx3&dih&0dYfNN^lGwCz$dW(8M2bzu9)u-NWLb!G;%fdpdSwciSv#@4%DfT!$yP zy1S%QDC@Z54Bq;|-nLCR)x1LhZ{@=TRN|n~^~Azc4`7oJ9Bu?UG(mg|W^`uNI=ou5 zV}1u~1XSjxXa=61?0Kqh-a8QA!y^>W{gDj_Pwfn+1K_|vg{*8_w7Fr@Z4pEK3@ao= zi5q7TSJ7xN?r_2eTlg3smkZiQ>aTDSse5UI%lt;=mP-)7LxqI1c!!s9`_+D14&VOS z7COW1Mrunelite-client runelite-jshell runelite-script-assembler-plugin - http-api - http-service diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 49b8425eeb..e6062cb4fd 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -242,9 +242,9 @@ runtime - net.runelite + net.runelite.arn http-api - ${project.version} + 1.0.0 net.runelite From faf5ce7a7dc99f2a6ca473d8974988426fbad32f Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 25 Dec 2021 14:12:38 -0500 Subject: [PATCH 04/34] checkstyle: remove suppressions These are not used anymore --- checkstyle.xml | 3 --- suppressions.xml | 32 -------------------------------- 2 files changed, 35 deletions(-) delete mode 100644 suppressions.xml diff --git a/checkstyle.xml b/checkstyle.xml index 5c8832b782..2e9c6131cb 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -56,7 +56,4 @@ - - - diff --git a/suppressions.xml b/suppressions.xml deleted file mode 100644 index 7a6d858208..0000000000 --- a/suppressions.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - From bb43d232bb594c6e062e3342fa7db1b53f594c11 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 27 Dec 2021 13:50:11 -0500 Subject: [PATCH 05/34] gpu: fix stretched mode scaling issues on macos This fixes the following issues: 1) resize events for the client not being propagated to the listener on the canvas 2) resizing the client in fixed mode not triggering a resetSize due to the underlying canvas size not changing 3) maximizing the client calling restSize too soon causing it to have no effect --- .../client/plugins/gpu/GpuPlugin.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index 062c810ffa..7b3c52f5be 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -44,9 +44,13 @@ import com.jogamp.opengl.GLFBODrawable; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.math.Matrix4; import java.awt.Canvas; +import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; @@ -293,6 +297,24 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private int uniSmoothBanding; private int uniTextureLightMode; + private int needsReset; + + private final ComponentListener resizeListener = new ComponentAdapter() + { + @Override + public void componentResized(ComponentEvent e) + { + // forward to the JAWTWindow component listener on the canvas. The JAWTWindow component + // listener listens for resizes or movement of the component in order to resize and move + // the associated offscreen layer (calayer on macos only) + canvas.dispatchEvent(e); + // resetSize needs to be run awhile after the resize is completed. + // I've tried waiting until all EDT events are completed and even that is too soon. + // Not sure why, so we just wait a few frames. + needsReset = 5; + } + }; + @Override protected void startUp() { @@ -447,6 +469,11 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { invokeOnMainThread(this::uploadScene); } + + if (OSType.getOSType() == OSType.MacOS) + { + SwingUtilities.invokeAndWait(() -> ((Component) client).addComponentListener(resizeListener)); + } } catch (Throwable e) { @@ -474,6 +501,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Override protected void shutDown() { + ((Component) client).removeComponentListener(resizeListener); clientThread.invoke(() -> { client.setGpu(false); @@ -1091,16 +1119,22 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture); gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, canvasWidth, canvasHeight, 0, gl.GL_BGRA, gl.GL_UNSIGNED_BYTE, null); gl.glBindTexture(gl.GL_TEXTURE_2D, 0); + } - if (OSType.getOSType() == OSType.MacOS && glDrawable instanceof GLFBODrawable) + if (needsReset > 0) + { + assert OSType.getOSType() == OSType.MacOS; + if (needsReset == 1 && glDrawable instanceof GLFBODrawable) { // GLDrawables created with createGLDrawable() do not have a resize listener // I don't know why this works with Windows/Linux, but on OSX // it prevents JOGL from resizing its FBOs and underlying GL textures. So, // we manually trigger a resize here. GLFBODrawable glfboDrawable = (GLFBODrawable) glDrawable; + log.debug("Resetting GLFBODrawable size"); glfboDrawable.resetSize(gl); } + needsReset--; } final BufferProvider bufferProvider = client.getBufferProvider(); From 153b475301c022a875a2ef4bfed664644cdcae0c Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 27 Dec 2021 16:21:37 -0500 Subject: [PATCH 06/34] clientui: disable ui scale transform for client bounds on macos This appears unnecessary on macos and breaks the remember client position feature --- .../src/main/java/net/runelite/client/ui/ClientUI.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index b99ebe437c..0cee8b636f 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -546,7 +546,11 @@ public class ClientUI // When Windows screen scaling is on, the position/bounds will be wrong when they are set. // The bounds saved in shutdown are the full, non-scaled co-ordinates. - if (scale != 1) + // On MacOS the scaling is already applied and the position/bounds are correct on at least + // - 2015 x64 MBP JDK11 Mohave + // - 2020 m1 MBP JDK17 Big Sur + // Adjusting the scaling further results in the client position being incorrect + if (scale != 1 && OSType.getOSType() != OSType.MacOS) { clientBounds.setRect( clientBounds.getX() / scale, From 637ee563d622fa187b2e4537ade86979bad1dbc9 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 27 Dec 2021 16:22:36 -0500 Subject: [PATCH 07/34] gpu: queue fbo reset on startup too Startup races with stretch mode plugin startup and clientui startup, so starting with stretched mode on doesn't reliably work. Just reset a few frames after startup to be sure. --- .../src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index 7b3c52f5be..869ac73eef 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -473,6 +473,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks if (OSType.getOSType() == OSType.MacOS) { SwingUtilities.invokeAndWait(() -> ((Component) client).addComponentListener(resizeListener)); + needsReset = 5; // plugin startup races with ClientUI positioning, so do a reset in a little bit } } catch (Throwable e) From 98279d4cfdf7f2b392e483ac50146a1343a448f2 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 28 Dec 2021 12:19:41 -0500 Subject: [PATCH 08/34] api: add arguments and mousey to scriptevent --- .../src/main/java/net/runelite/api/ScriptEvent.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptEvent.java b/runelite-api/src/main/java/net/runelite/api/ScriptEvent.java index 2436c9ac3b..cc62a9e9ef 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptEvent.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptEvent.java @@ -53,6 +53,12 @@ public interface ScriptEvent */ ScriptEvent setSource(Widget widget); + /** + * Arguments passed to the script. Index 0 is the script being run and is not an argument. + * @return + */ + Object[] getArguments(); + /** * Gets the menu index of the event * @@ -73,6 +79,11 @@ public interface ScriptEvent */ int getMouseX(); + /** + * Parent relative y coordinate for mouse related events + */ + int getMouseY(); + /** * Jagex typed keycode * From 6c15080bfbd58c781533a0ce3f54e4df9620c1ca Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 28 Dec 2021 20:16:16 -0700 Subject: [PATCH 09/34] grounditems/Lootbeam: handle loading models correctly models are streamed over js5 so loadModel can return null until it is downloaded --- .../main/java/net/runelite/api/Client.java | 4 +++ .../grounditems/GroundItemsPlugin.java | 2 +- .../client/plugins/grounditems/Lootbeam.java | 26 ++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 12ae583c74..de2e895a88 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1057,7 +1057,9 @@ public interface Client extends GameEngine * Loads a model from the cache * * @param id the ID of the model + * @return the model or null if it is loading or nonexistent */ + @Nullable Model loadModel(int id); /** @@ -1066,7 +1068,9 @@ public interface Client extends GameEngine * @param id the ID of the model * @param colorToFind array of hsl color values to find in the model to replace * @param colorToReplace array of hsl color values to replace in the model + * @return the model or null if it is loading or nonexistent */ + @Nullable Model loadModel(int id, short[] colorToFind, short[] colorToReplace); /** diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index 662316eb93..25338d4285 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -800,7 +800,7 @@ public class GroundItemsPlugin extends Plugin Lootbeam lootbeam = lootbeams.get(worldPoint); if (lootbeam == null) { - lootbeam = new Lootbeam(client, worldPoint, color); + lootbeam = new Lootbeam(client, clientThread, worldPoint, color); lootbeams.put(worldPoint, lootbeam); } else diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java index 1d95a39dc1..9e8761a93f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java @@ -27,10 +27,12 @@ package net.runelite.client.plugins.grounditems; import net.runelite.api.AnimationID; import net.runelite.api.Client; import net.runelite.api.JagexColor; +import net.runelite.api.Model; import net.runelite.api.RuneLiteObject; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import java.awt.Color; +import net.runelite.client.callback.ClientThread; class Lootbeam { @@ -39,11 +41,13 @@ class Lootbeam private final RuneLiteObject runeLiteObject; private final Client client; + private final ClientThread clientThread; private Color color; - public Lootbeam(Client client, WorldPoint worldPoint, Color color) + public Lootbeam(Client client, ClientThread clientThread, WorldPoint worldPoint, Color color) { this.client = client; + this.clientThread = clientThread; runeLiteObject = client.createRuneLiteObject(); setColor(color); @@ -64,11 +68,21 @@ class Lootbeam } this.color = color; - runeLiteObject.setModel(client.loadModel( - RAID_LIGHT_MODEL, - new short[]{RAID_LIGHT_FIND_COLOR}, - new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)} - )); + clientThread.invoke(() -> + { + Model m = client.loadModel( + RAID_LIGHT_MODEL, + new short[]{RAID_LIGHT_FIND_COLOR}, + new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)} + ); + if (m == null) + { + return false; + } + + runeLiteObject.setModel(m); + return true; + }); } public void remove() From 99d0a61cc4b85256c56aceb496045b0a23663733 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 30 Dec 2021 01:54:09 +0000 Subject: [PATCH 10/34] worldpoint: use passed plane when getting instance chunk for localpoint Without this, fromLocalInstance can only find the template chunk for the player's current plane. --- .../src/main/java/net/runelite/api/coords/WorldPoint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java index cafb9e9115..8b31f7c499 100644 --- a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java +++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java @@ -198,7 +198,7 @@ public class WorldPoint // get the template chunk for the chunk int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks(); - int templateChunk = instanceTemplateChunks[client.getPlane()][chunkX][chunkY]; + int templateChunk = instanceTemplateChunks[plane][chunkX][chunkY]; int rotation = templateChunk >> 1 & 0x3; int templateChunkY = (templateChunk >> 3 & 0x7FF) * CHUNK_SIZE; From c23e499c92cd4e82e47dd9bbff05e027d53e43bf Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 30 Dec 2021 01:59:48 +0000 Subject: [PATCH 11/34] roof removal: use worldpoint's plane instead of current plane This allows for overrides on template chunks to be defined based on the chunk's position, not where the chunk ends up in the scene. I think this only really matters for the POH, which stores each style across all 4 planes of 3 (or 7) regions. --- .../client/plugins/roofremoval/RoofRemovalPlugin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java index 9f86d9a47e..d9d711ab41 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java @@ -250,15 +250,15 @@ public class RoofRemovalPlugin extends Plugin // Properly account for instances shifting worldpoints around final WorldPoint wp = WorldPoint.fromLocalInstance(client, tile.getLocalLocation(), tile.getPlane()); - int regionID = wp.getRegionID() << 2 | z; - if (!overrides.containsKey(regionID)) + int regionAndPlane = wp.getRegionID() << 2 | wp.getPlane(); + if (!overrides.containsKey(regionAndPlane)) { continue; } int rx = wp.getRegionX(); int ry = wp.getRegionY(); - long[] region = overrides.get(regionID); + long[] region = overrides.get(regionAndPlane); if ((region[ry] & (1L << rx)) != 0) { settings[z][x][y] |= Constants.TILE_FLAG_UNDER_ROOF; From 7bacb13ac52fc381eba9fa36a4f905bc164b25d9 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 30 Dec 2021 02:00:53 +0000 Subject: [PATCH 12/34] roof removal: add overrides for unused area in the POH dungeon --- .../plugins/roofremoval/overrides.jsonc | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc b/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc index df0cc06c5e..04433ef5a0 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/roofremoval/overrides.jsonc @@ -3328,5 +3328,35 @@ "z1": 0, "z2": 0 } + ], + "7513": [ // POH styles 1-4 + { + "rx1": 24, + "ry1": 0, + "rx2": 31, + "ry2": 7, + "z1": 0, + "z2": 3 + } + ], + "7769": [ // POH styles 5-8 + { + "rx1": 24, + "ry1": 0, + "rx2": 31, + "ry2": 7, + "z1": 0, + "z2": 3 + } + ], + "8025": [ // POH styles 9-12 + { + "rx1": 24, + "ry1": 0, + "rx2": 31, + "ry2": 7, + "z1": 0, + "z2": 3 + } ] } From 13154de18f0e967c0d4e6868f46e7d766a00a279 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 30 Dec 2021 02:13:26 +0000 Subject: [PATCH 13/34] roof removal: add support for always hiding roofs in POH --- .../roofremoval/RoofRemovalConfig.java | 38 +++++++++++-- .../RoofRemovalConfigOverride.java | 45 ++++++++++++++++ .../roofremoval/RoofRemovalPlugin.java | 53 +++++++++++++++---- 3 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfigOverride.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java index 39bf615853..4a32c41b36 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfig.java @@ -27,16 +27,32 @@ package net.runelite.client.plugins.roofremoval; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; @ConfigGroup(RoofRemovalConfig.CONFIG_GROUP) public interface RoofRemovalConfig extends Config { String CONFIG_GROUP = "roofremoval"; + @ConfigSection( + name = "Modes", + description = "In what situations should roofs be removed", + position = 0 + ) + String modesSection = "modes"; + + @ConfigSection( + name = "Area Overrides", + description = "Always remove roofs in specific areas", + position = 1 + ) + String overridesSection = "overrides"; + @ConfigItem( keyName = "removePosition", name = "Player's position", - description = "Remove roofs above the player's position" + description = "Remove roofs above the player's position", + section = modesSection ) default boolean removePosition() { @@ -46,7 +62,8 @@ public interface RoofRemovalConfig extends Config @ConfigItem( keyName = "removeHovered", name = "Hovered tile", - description = "Remove roofs above the hovered tile" + description = "Remove roofs above the hovered tile", + section = modesSection ) default boolean removeHovered() { @@ -56,7 +73,8 @@ public interface RoofRemovalConfig extends Config @ConfigItem( keyName = "removeDestination", name = "Destination tile", - description = "Remove roofs above the destination tile" + description = "Remove roofs above the destination tile", + section = modesSection ) default boolean removeDestination() { @@ -66,10 +84,22 @@ public interface RoofRemovalConfig extends Config @ConfigItem( keyName = "removeBetween", name = "Between camera & player", - description = "Remove roofs between the camera and the player at low camera angles" + description = "Remove roofs between the camera and the player at low camera angles", + section = modesSection ) default boolean removeBetween() { return true; } + + @ConfigItem( + keyName = "overridePOH", + name = "Player Owned House", + description = "Always remove roofs while in the Player Owned House", + section = overridesSection + ) + default boolean overridePOH() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfigOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfigOverride.java new file mode 100644 index 0000000000..478f61ee4b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalConfigOverride.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Hydrox6 + * 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.client.plugins.roofremoval; + +import lombok.Getter; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +@Getter +enum RoofRemovalConfigOverride +{ + POH(RoofRemovalConfig::overridePOH, 7257, 7513, 7514, 7769, 7770, 8025, 8026); + + private final Predicate enabled; + private final List regions; + + RoofRemovalConfigOverride(Predicate enabled, Integer... regions) + { + this.enabled = enabled; + this.regions = Arrays.asList(regions); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java index d9d711ab41..622974387e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java @@ -34,8 +34,10 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -86,6 +88,7 @@ public class RoofRemovalPlugin extends Plugin private RoofRemovalConfig config; private final Map overrides = new HashMap<>(); + private final Set configOverrideRegions = new HashSet<>(); @Provides RoofRemovalConfig getConfig(ConfigManager configManager) @@ -139,7 +142,21 @@ public class RoofRemovalPlugin extends Plugin return; } - client.getScene().setRoofRemovalMode(buildRoofRemovalFlags()); + if (e.getKey().startsWith("remove")) + { + client.getScene().setRoofRemovalMode(buildRoofRemovalFlags()); + } + else if (e.getKey().startsWith("override")) + { + buildConfigOverrides(); + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + client.setGameState(GameState.LOADING); + } + }); + } } private int buildRoofRemovalFlags() @@ -164,6 +181,18 @@ public class RoofRemovalPlugin extends Plugin return roofRemovalMode; } + private void buildConfigOverrides() + { + configOverrideRegions.clear(); + for (RoofRemovalConfigOverride configOverride : RoofRemovalConfigOverride.values()) + { + if (configOverride.getEnabled().test(config)) + { + configOverrideRegions.addAll(configOverride.getRegions()); + } + } + } + private void performRoofRemoval() { assert client.isClientThread(); @@ -220,7 +249,7 @@ public class RoofRemovalPlugin extends Plugin { for (int z = 0; z < Constants.MAX_Z; z++) { - if (overrides.containsKey(regionID << 2 | z)) + if (overrides.containsKey(regionID << 2 | z) || configOverrideRegions.contains(regionID)) { regionsHaveOverrides = true; break outer; @@ -251,18 +280,20 @@ public class RoofRemovalPlugin extends Plugin final WorldPoint wp = WorldPoint.fromLocalInstance(client, tile.getLocalLocation(), tile.getPlane()); int regionAndPlane = wp.getRegionID() << 2 | wp.getPlane(); - if (!overrides.containsKey(regionAndPlane)) - { - continue; - } - - int rx = wp.getRegionX(); - int ry = wp.getRegionY(); - long[] region = overrides.get(regionAndPlane); - if ((region[ry] & (1L << rx)) != 0) + if (configOverrideRegions.contains(wp.getRegionID())) { settings[z][x][y] |= Constants.TILE_FLAG_UNDER_ROOF; } + else if (overrides.containsKey(regionAndPlane)) + { + int rx = wp.getRegionX(); + int ry = wp.getRegionY(); + long[] region = overrides.get(regionAndPlane); + if ((region[ry] & (1L << rx)) != 0) + { + settings[z][x][y] |= Constants.TILE_FLAG_UNDER_ROOF; + } + } } } } From fc5a7575c54c87f3cc3f2ea2bf92978eaa4c1433 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Thu, 30 Dec 2021 16:13:47 +0000 Subject: [PATCH 14/34] Release 1.8.8 --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- pom.xml | 4 ++-- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-jshell/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index c3a97e17de..70b562d4d7 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index 5252bba4d5..94f30ea2b3 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index 4b42efcf78..7023dc9ae0 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 cache diff --git a/pom.xml b/pom.xml index 49c443add6..bb77001d2e 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 pom RuneLite @@ -63,7 +63,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - HEAD + runelite-parent-1.8.8 diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 219f88d40d..7e453ea15f 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index e6062cb4fd..d6738ca2c7 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 client diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml index 97fa8eae63..f5c7712daa 100644 --- a/runelite-jshell/pom.xml +++ b/runelite-jshell/pom.xml @@ -30,7 +30,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 jshell diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 49ba0eb296..4f4fa072d6 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8-SNAPSHOT + 1.8.8 script-assembler-plugin From 92846981f0bea6acdb55e41cc34d3e0e7639846f Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Thu, 30 Dec 2021 16:13:58 +0000 Subject: [PATCH 15/34] Bump for 1.8.9-SNAPSHOT --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- pom.xml | 4 ++-- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-jshell/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index 70b562d4d7..3d03f7f633 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index 94f30ea2b3..e6be17e8fe 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index 7023dc9ae0..a0a550829f 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT cache diff --git a/pom.xml b/pom.xml index bb77001d2e..b1c83af9b6 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT pom RuneLite @@ -63,7 +63,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - runelite-parent-1.8.8 + HEAD diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 7e453ea15f..69e9fb736b 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index d6738ca2c7..1f59ac20b6 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT client diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml index f5c7712daa..93a6cf78aa 100644 --- a/runelite-jshell/pom.xml +++ b/runelite-jshell/pom.xml @@ -30,7 +30,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT jshell diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 4f4fa072d6..3e2594f3da 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.8 + 1.8.9-SNAPSHOT script-assembler-plugin From 3af75e6752deb963dc9da690d5afe4f442b041e7 Mon Sep 17 00:00:00 2001 From: Cody Massin Date: Thu, 30 Dec 2021 22:08:53 -0800 Subject: [PATCH 16/34] roof removal: build overrides for POH on startUp Signed-off-by: Cody Massin --- .../runelite/client/plugins/roofremoval/RoofRemovalPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java index 622974387e..c7019cee6f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java @@ -99,6 +99,7 @@ public class RoofRemovalPlugin extends Plugin @Override public void startUp() throws IOException { + buildConfigOverrides(); loadRoofOverrides(); clientThread.invoke(() -> { From 99b0a18a4c4c159b5a480c5fb2a069babf33469e Mon Sep 17 00:00:00 2001 From: Cody Massin Date: Thu, 30 Dec 2021 22:11:23 -0800 Subject: [PATCH 17/34] roof removal: optimize POH region override check Signed-off-by: Cody Massin --- .../client/plugins/roofremoval/RoofRemovalPlugin.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java index c7019cee6f..5d567a90c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roofremoval/RoofRemovalPlugin.java @@ -248,9 +248,14 @@ public class RoofRemovalPlugin extends Plugin outer: for (int regionID : client.getMapRegions()) { + if (configOverrideRegions.contains(regionID)) + { + regionsHaveOverrides = true; + break; + } for (int z = 0; z < Constants.MAX_Z; z++) { - if (overrides.containsKey(regionID << 2 | z) || configOverrideRegions.contains(regionID)) + if (overrides.containsKey(regionID << 2 | z)) { regionsHaveOverrides = true; break outer; From 31dc32c22536e757ace286de39870f491bf4dbcb Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 1 Jan 2022 17:52:39 -0500 Subject: [PATCH 18/34] Set macos quitStrategy to CLOSE_ALL_WINDOWS The quit strategy API existed in com.apple.eawt prior to Java 9, and was moved into java.desktop in 9. This move makes our orange-extensions API incompatiable with the 9 eawt package too, so we can not use Application.setQuitStrategy on 9+ either, without making orange-extensions multi-release too. Since Desktop.setQuitStrategy is the new standard way of doing this, use it if available, and otherwise use the Java 8 Application.setQuitStrategy instead. --- .../java/net/runelite/client/ui/ClientUI.java | 6 +++ .../runelite/client/ui/MacOSQuitStrategy.java | 48 +++++++++++++++++++ .../runelite/client/ui/MacOSQuitStrategy.java | 37 ++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/MacOSQuitStrategy.java create mode 100644 runelite-client/src/main/java11/net/runelite/client/ui/MacOSQuitStrategy.java diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 0cee8b636f..84a2e4858f 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -332,6 +332,12 @@ public class ClientUI frame.setResizable(true); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + if (OSType.getOSType() == OSType.MacOS) + { + // Change the default quit strategy to CLOSE_ALL_WINDOWS so that ctrl+q + // triggers the listener below instead of exiting. + MacOSQuitStrategy.setup(); + } frame.addWindowListener(new WindowAdapter() { @Override diff --git a/runelite-client/src/main/java/net/runelite/client/ui/MacOSQuitStrategy.java b/runelite-client/src/main/java/net/runelite/client/ui/MacOSQuitStrategy.java new file mode 100644 index 0000000000..4c191ed3ca --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/MacOSQuitStrategy.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, Adam + * 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.client.ui; + +import com.apple.eawt.Application; +import com.apple.eawt.QuitStrategy; + +class MacOSQuitStrategy +{ + public static void setup() + { + try + { + // com.apple.eawt.QuitStrategy was moved to java.desktop in Java 9, + // but our OrangeExtensions API targets 1.6, so this code is only valid + // on 8 below. + Application.getApplication() + .setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS); + } + catch (NoClassDefFoundError ex) + { + // IntelliJ doesn't handle our multi-release Maven setup well, and will run + // this class on 11+. Ignore the error so the client can launch. + } + } +} diff --git a/runelite-client/src/main/java11/net/runelite/client/ui/MacOSQuitStrategy.java b/runelite-client/src/main/java11/net/runelite/client/ui/MacOSQuitStrategy.java new file mode 100644 index 0000000000..6af420ea4c --- /dev/null +++ b/runelite-client/src/main/java11/net/runelite/client/ui/MacOSQuitStrategy.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022, Adam + * 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.client.ui; + +import java.awt.Desktop; +import java.awt.desktop.QuitStrategy; + +class MacOSQuitStrategy +{ + public static void setup() + { + Desktop.getDesktop() + .setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS); + } +} From 0da504769df58cb2f648d2fcc8048978c7997c5b Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 1 Jan 2022 19:59:47 -0500 Subject: [PATCH 19/34] ui: set DO_NOTHING_ON_CLOSE close op prior to disposing Disposed frames are still reachable via Window.getWindows() until gcd, and can receive and process events. We don't want the splash screen to close the app if it receives a window close event after being disposed. --- .../main/java/net/runelite/client/ui/SplashScreen.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java b/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java index 8eca11dd17..3668072a1c 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java @@ -30,7 +30,6 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import javax.annotation.Nullable; import javax.swing.ImageIcon; @@ -66,7 +65,7 @@ public class SplashScreen extends JFrame implements ActionListener private volatile String subActionText = ""; private volatile String progressText = null; - private SplashScreen() throws IOException + private SplashScreen() { BufferedImage logo = ImageUtil.loadImageResource(SplashScreen.class, "runelite_transparent.png"); @@ -204,6 +203,12 @@ public class SplashScreen extends JFrame implements ActionListener } INSTANCE.timer.stop(); + // The CLOSE_ALL_WINDOWS quit strategy on MacOS dispatches WINDOW_CLOSING events to each frame + // from Window.getWindows. However, getWindows uses weak refs and relies on gc to remove windows + // from its list, causing events to get dispatched to disposed frames. The frames handle the events + // regardless of being disposed and will run the configured close operation. Set the close operation + // to DO_NOTHING_ON_CLOSE prior to disposing to prevent this. + INSTANCE.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); INSTANCE.dispose(); INSTANCE = null; }); From d7f72f79ebf005dc6330ed8413e8ff6c577ab55b Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 3 Jan 2022 02:19:20 +1100 Subject: [PATCH 20/34] Revert "Remove http-api and http-service" This reverts commit 055f5c2d --- http-api/pom.xml | 75 ++++ .../http/api/discord/DiscordClient.java | 6 +- .../http/api/account/OAuthResponse.java | 35 ++ .../net/runelite/http/api/chat/Duels.java | 36 ++ .../runelite/http/api/chat/LayoutRoom.java | 50 +++ .../java/net/runelite/http/api/chat/Task.java | 36 ++ .../runelite/http/api/config/ConfigEntry.java | 38 ++ .../http/api/config/Configuration.java | 37 ++ .../net/runelite/http/api/feed/FeedItem.java | 42 ++ .../runelite/http/api/feed/FeedItemType.java | 32 ++ .../runelite/http/api/feed/FeedResult.java | 36 ++ .../http/api/ge/GrandExchangeTrade.java | 48 +++ .../http/api/gson/ColorTypeAdapter.java | 89 +++++ .../api/gson/IllegalReflectionExclusion.java | 71 ++++ .../http/api/gson/InstantTypeAdapter.java | 83 ++++ .../http/api/item/ItemEquipmentStats.java | 57 +++ .../net/runelite/http/api/item/ItemPrice.java | 36 ++ .../net/runelite/http/api/item/ItemType.java | 48 +++ .../http/api/loottracker/GameItem.java | 38 ++ .../http/api/loottracker/LootAggregate.java | 44 +++ .../http/api/loottracker/LootRecord.java | 44 +++ .../http/api/loottracker/LootRecordType.java | 34 ++ .../net/runelite/http/api/worlds/World.java | 46 +++ .../runelite/http/api/worlds/WorldRegion.java | 74 ++++ .../runelite/http/api/worlds/WorldResult.java | 54 +++ .../runelite/http/api/worlds/WorldType.java | 39 ++ .../api/ws/RuntimeTypeAdapterFactory.java | 240 ++++++++++++ .../http/api/ws/WebsocketGsonFactory.java | 88 +++++ .../http/api/ws/WebsocketMessage.java | 35 ++ .../http/api/ws/messages/Handshake.java | 35 ++ .../http/api/ws/messages/LoginResponse.java | 37 ++ .../http/api/ws/messages/party/Join.java | 38 ++ .../http/api/ws/messages/party/Part.java | 31 ++ .../ws/messages/party/PartyChatMessage.java | 33 ++ .../ws/messages/party/PartyMemberMessage.java | 12 + .../api/ws/messages/party/PartyMessage.java | 35 ++ .../http/api/ws/messages/party/UserJoin.java | 39 ++ .../http/api/ws/messages/party/UserPart.java | 37 ++ .../http/api/ws/messages/party/UserSync.java | 34 ++ .../net/runelite/http/api/xtea/XteaKey.java | 34 ++ .../runelite/http/api/xtea/XteaRequest.java | 41 ++ .../http/api/gson/ColorTypeAdapterTest.java | 58 +++ .../http/api/gson/InstantTypeAdapterTest.java | 54 +++ http-service/pom.xml | 269 +++++++++++++ .../service/SpringBootWebApplication.java | 228 +++++++++++ .../service/SpringSchedulingConfigurer.java | 52 +++ .../http/service/SpringWebMvcConfigurer.java | 65 ++++ .../http/service/account/AccountService.java | 284 ++++++++++++++ .../http/service/account/AuthFilter.java | 116 ++++++ .../runelite/http/service/account/State.java | 35 ++ .../http/service/account/UserInfo.java | 46 +++ .../service/account/beans/SessionEntry.java | 76 ++++ .../http/service/account/beans/UserEntry.java | 57 +++ .../runelite/http/service/cache/CacheDAO.java | 123 ++++++ .../http/service/cache/CacheService.java | 254 ++++++++++++ .../service/cache/beans/ArchiveEntry.java | 38 ++ .../http/service/cache/beans/CacheEntry.java | 36 ++ .../http/service/cache/beans/FileEntry.java | 36 ++ .../http/service/cache/beans/IndexEntry.java | 36 ++ .../http/service/chat/ChatController.java | 274 +++++++++++++ .../http/service/chat/ChatService.java | 263 +++++++++++++ .../http/service/chat/KillCountKey.java | 34 ++ .../http/service/config/ConfigController.java | 134 +++++++ .../http/service/config/ConfigService.java | 367 ++++++++++++++++++ .../http/service/feed/FeedController.java | 137 +++++++ .../http/service/feed/blog/BlogService.java | 143 +++++++ .../feed/osrsnews/OSRSNewsService.java | 143 +++++++ .../twitter/TwitterOAuth2TokenResponse.java | 38 ++ .../service/feed/twitter/TwitterService.java | 183 +++++++++ .../twitter/TwitterStatusesResponseItem.java | 35 ++ .../TwitterStatusesResponseItemUser.java | 38 ++ .../service/ge/GrandExchangeController.java | 158 ++++++++ .../http/service/ge/GrandExchangeService.java | 119 ++++++ .../service/ge/GrandExchangeTradeHistory.java | 38 ++ .../net/runelite/http/service/ge/Trade.java | 51 +++ .../runelite/http/service/ge/TradeAction.java | 31 ++ .../runelite/http/service/ge/TradeEntry.java | 40 ++ .../http/service/item/ItemController.java | 113 ++++++ .../runelite/http/service/item/ItemEntry.java | 39 ++ .../http/service/item/ItemService.java | 287 ++++++++++++++ .../http/service/item/PriceEntry.java | 40 ++ .../runelite/http/service/item/RSItem.java | 36 ++ .../http/service/item/RSItemResponse.java | 33 ++ .../runelite/http/service/item/RSPrices.java | 37 ++ .../http/service/loottracker/LootResult.java | 42 ++ .../loottracker/LootTrackerController.java | 118 ++++++ .../loottracker/LootTrackerService.java | 259 ++++++++++++ .../pluginhub/PluginHubController.java | 144 +++++++ .../http/service/util/InstantConverter.java | 48 +++ .../InternalServerErrorException.java | 38 ++ .../util/exception/NotFoundException.java | 35 ++ .../http/service/util/redis/RedisPool.java | 102 +++++ .../http/service/wiki/PriceResult.java | 44 +++ .../http/service/wiki/WikiPriceService.java | 140 +++++++ .../http/service/worlds/ServiceWorldType.java | 60 +++ .../http/service/worlds/WorldController.java | 68 ++++ .../http/service/worlds/WorldsService.java | 132 +++++++ .../runelite/http/service/xtea/XteaCache.java | 39 ++ .../http/service/xtea/XteaController.java | 86 ++++ .../runelite/http/service/xtea/XteaEntry.java | 40 ++ .../http/service/xtea/XteaService.java | 250 ++++++++++++ .../src/main/resources/application-dev.yaml | 29 ++ .../src/main/resources/application.yaml | 61 +++ http-service/src/main/templates/markdown.hbs | 110 ++++++ http-service/src/main/templates/operation.hbs | 71 ++++ http-service/src/main/templates/security.hbs | 88 +++++ .../src/main/templates/template.html.hbs | 49 +++ http-service/src/main/webapp/WEB-INF/web.xml | 32 ++ .../service/config/ConfigControllerTest.java | 85 ++++ .../service/config/ConfigServiceTest.java | 72 ++++ .../LootTrackerControllerTest.java | 104 +++++ .../service/worlds/WorldsServiceTest.java | 79 ++++ .../src/test/resources/application-test.yaml | 21 + .../runelite/http/service/worlds/worldlist | Bin 0 -> 5000 bytes .../client/plugins/xtea/XteaClient.java | 29 +- 115 files changed, 9128 insertions(+), 18 deletions(-) create mode 100644 http-api/pom.xml create mode 100644 http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java create mode 100644 http-api/src/main/java/net/runelite/http/api/chat/Duels.java create mode 100644 http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java create mode 100644 http-api/src/main/java/net/runelite/http/api/chat/Task.java create mode 100644 http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java create mode 100644 http-api/src/main/java/net/runelite/http/api/config/Configuration.java create mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java create mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java create mode 100644 http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java create mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java create mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java create mode 100644 http-api/src/main/java/net/runelite/http/api/item/ItemType.java create mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java create mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java create mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java create mode 100644 http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java create mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/World.java create mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java create mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java create mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java create mode 100644 http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java create mode 100644 http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java create mode 100644 http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java create mode 100644 http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java create mode 100644 http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java create mode 100644 http-service/pom.xml create mode 100644 http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java create mode 100644 http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java create mode 100644 http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/AccountService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/State.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/UserInfo.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java create mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/FeedController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java create mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/Trade.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java create mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItem.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java create mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSPrices.java create mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java create mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java create mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java create mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java create mode 100644 http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java create mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java create mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java create mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java create mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java create mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java create mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java create mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java create mode 100644 http-service/src/main/resources/application-dev.yaml create mode 100644 http-service/src/main/resources/application.yaml create mode 100644 http-service/src/main/templates/markdown.hbs create mode 100644 http-service/src/main/templates/operation.hbs create mode 100644 http-service/src/main/templates/security.hbs create mode 100644 http-service/src/main/templates/template.html.hbs create mode 100644 http-service/src/main/webapp/WEB-INF/web.xml create mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java create mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java create mode 100644 http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java create mode 100644 http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java create mode 100644 http-service/src/test/resources/application-test.yaml create mode 100644 http-service/src/test/resources/net/runelite/http/service/worlds/worldlist diff --git a/http-api/pom.xml b/http-api/pom.xml new file mode 100644 index 0000000000..6f4e9a635e --- /dev/null +++ b/http-api/pom.xml @@ -0,0 +1,75 @@ + + + + 4.0.0 + + net.runelite + runelite-parent + 1.8.8-SNAPSHOT + + + Web API + http-api + + + + com.squareup.okhttp3 + okhttp + 3.14.9 + + + com.google.code.gson + gson + + + org.slf4j + slf4j-api + + + org.projectlombok + lombok + provided + + + + junit + junit + 4.12 + test + + + org.slf4j + slf4j-simple + test + + + com.squareup.okhttp3 + mockwebserver + 3.14.9 + test + + + diff --git a/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java b/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java index 61383bbbc4..47b82fdf55 100644 --- a/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java +++ b/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java @@ -29,7 +29,7 @@ package com.openosrs.http.api.discord; import com.google.gson.Gson; import java.io.IOException; import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; +//import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -60,7 +60,7 @@ public class DiscordClient log.debug("Attempting to message with {}", discordMessage); - RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() + /* RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() { @Override @@ -95,6 +95,6 @@ public class DiscordClient log.debug("Submitted discord log record"); } } - }); + });*/ } } diff --git a/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java b/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java new file mode 100644 index 0000000000..930540b6eb --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/account/OAuthResponse.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.account; + +import java.util.UUID; +import lombok.Data; + +@Data +public class OAuthResponse +{ + private String oauthUrl; + private UUID uid; +} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/Duels.java b/http-api/src/main/java/net/runelite/http/api/chat/Duels.java new file mode 100644 index 0000000000..ba117a526a --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/chat/Duels.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Adam + * 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.api.chat; + +import lombok.Data; + +@Data +public class Duels +{ + private int wins; + private int losses; + private int winningStreak; + private int losingStreak; +} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java b/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java new file mode 100644 index 0000000000..3498f83eed --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/chat/LayoutRoom.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019, Adam + * 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.api.chat; + +public enum LayoutRoom +{ + START, + END, + SCAVENGERS, + FARMING, + EMPTY, + + TEKTON, + MUTTADILES, + GUARDIANS, + VESPULA, + SHAMANS, + VASA, + VANGUARDS, + MYSTICS, + UNKNOWN_COMBAT, + + CRABS, + ICE_DEMON, + TIGHTROPE, + THIEVING, + UNKNOWN_PUZZLE; +} diff --git a/http-api/src/main/java/net/runelite/http/api/chat/Task.java b/http-api/src/main/java/net/runelite/http/api/chat/Task.java new file mode 100644 index 0000000000..db38c90109 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/chat/Task.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Adam + * 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.api.chat; + +import lombok.Data; + +@Data +public class Task +{ + private String task; + private int amount; + private int initialAmount; + private String location; +} diff --git a/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java b/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java new file mode 100644 index 0000000000..d8b69dae72 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/config/ConfigEntry.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ConfigEntry +{ + private String key; + private String value; +} diff --git a/http-api/src/main/java/net/runelite/http/api/config/Configuration.java b/http-api/src/main/java/net/runelite/http/api/config/Configuration.java new file mode 100644 index 0000000000..44269b735a --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/config/Configuration.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.config; + +import java.util.ArrayList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Configuration +{ + private List config = new ArrayList<>(); +} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java new file mode 100644 index 0000000000..620f639d15 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/feed/FeedItem.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, Lotto + * 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.api.feed; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +@AllArgsConstructor +public class FeedItem +{ + private final FeedItemType type; + private String avatar; + private final String title; + private final String content; + private final String url; + private final long timestamp; +} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java new file mode 100644 index 0000000000..e3cc9443cd --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/feed/FeedItemType.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, Lotto + * 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.api.feed; + +public enum FeedItemType +{ + BLOG_POST, + TWEET, + OSRS_NEWS +} diff --git a/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java b/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java new file mode 100644 index 0000000000..cf862b5be0 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/feed/FeedResult.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018, Lotto + * 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.api.feed; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class FeedResult +{ + private List items; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java new file mode 100644 index 0000000000..fd6f6635d3 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019, Adam + * 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.api.ge; + +import java.time.Instant; +import lombok.Data; +import net.runelite.http.api.worlds.WorldType; + +@Data +public class GrandExchangeTrade +{ + private boolean buy; + private boolean cancel; + private boolean login; + private int itemId; + private int qty; + private int dqty; + private int total; + private int spent; + private int dspent; + private int offer; + private int slot; + private WorldType worldType; + private int seq; + private Instant resetTime; +} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java new file mode 100644 index 0000000000..feec0f6d66 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Abex + * 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.api.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.awt.Color; +import java.io.IOException; + +public class ColorTypeAdapter extends TypeAdapter +{ + @Override + public void write(JsonWriter out, Color value) throws IOException + { + if (value == null) + { + out.nullValue(); + return; + } + + int rgba = value.getRGB(); + out.value(String.format("#%08X", rgba)); + } + + @Override + public Color read(JsonReader in) throws IOException + { + switch (in.peek()) + { + case NULL: + in.nextNull(); + return null; + case STRING: + { + String value = in.nextString(); + if (value.charAt(0) == '#') + { + value = value.substring(1); + } + int intValue = Integer.parseUnsignedInt(value, 16); + return new Color(intValue, true); + } + case BEGIN_OBJECT: + { + in.beginObject(); + double value = 0; + while (in.peek() != JsonToken.END_OBJECT) + { + switch (in.nextName()) + { + case "value": + value = in.nextDouble(); + break; + default: + in.skipValue(); + break; + } + } + in.endObject(); + return new Color((int) value, true); + } + } + return null; // throws + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java b/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java new file mode 100644 index 0000000000..a25ffb79f7 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Abex + * 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.api.gson; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; + +public class IllegalReflectionExclusion implements ExclusionStrategy +{ + private static final Set PRIVATE_CLASSLOADERS = new HashSet<>(); + + static + { + for (ClassLoader cl = ClassLoader.getSystemClassLoader(); cl != null; ) + { + cl = cl.getParent(); + PRIVATE_CLASSLOADERS.add(cl); + } + } + + @Override + public boolean shouldSkipField(FieldAttributes f) + { + if (!PRIVATE_CLASSLOADERS.contains(f.getDeclaringClass().getClassLoader())) + { + return false; + } + + assert !Modifier.isPrivate(f.getDeclaringClass().getModifiers()) : "gsoning private class " + f.getDeclaringClass().getName(); + try + { + f.getDeclaringClass().getField(f.getName()); + } + catch (NoSuchFieldException e) + { + throw new AssertionError("gsoning private field " + f.getDeclaringClass() + "." + f.getName()); + } + return false; + } + + @Override + public boolean shouldSkipClass(Class clazz) + { + return false; + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java new file mode 100644 index 0000000000..d5162c0e01 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Abex + * 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.api.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.time.Instant; + +// Just add water! +public class InstantTypeAdapter extends TypeAdapter +{ + @Override + public void write(JsonWriter out, Instant value) throws IOException + { + if (value == null) + { + out.nullValue(); + return; + } + + out.value(value.toEpochMilli()); + } + + @Override + public Instant read(JsonReader in) throws IOException + { + if (in.peek() == JsonToken.NULL) + { + in.nextNull(); + return null; + } + + if (in.peek() == JsonToken.NUMBER) + { + long jsTime = in.nextLong(); + return Instant.ofEpochMilli(jsTime); + } + + long seconds = 0; + int nanos = 0; + in.beginObject(); + while (in.peek() != JsonToken.END_OBJECT) + { + switch (in.nextName()) + { + case "nanos": + nanos = in.nextInt(); + break; + case "seconds": + seconds = in.nextLong(); + break; + } + } + in.endObject(); + + return Instant.ofEpochSecond(seconds, nanos); + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java b/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java new file mode 100644 index 0000000000..5848513c00 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/item/ItemEquipmentStats.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.item; + +import com.google.gson.annotations.SerializedName; +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ItemEquipmentStats +{ + private int slot; + + @SerializedName("is2h") + private boolean isTwoHanded; + + private int astab; + private int aslash; + private int acrush; + private int amagic; + private int arange; + + private int dstab; + private int dslash; + private int dcrush; + private int dmagic; + private int drange; + + private int str; + private int rstr; + private int mdmg; + private int prayer; + private int aspeed; +} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java b/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java new file mode 100644 index 0000000000..faf5bfc3fb --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/item/ItemPrice.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.item; + +import lombok.Data; + +@Data +public class ItemPrice +{ + private int id; + private String name; + private int price; + private int wikiPrice; +} diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemType.java b/http-api/src/main/java/net/runelite/http/api/item/ItemType.java new file mode 100644 index 0000000000..9221f096b2 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/item/ItemType.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.item; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public enum ItemType +{ + DEFAULT; + + private static final Logger logger = LoggerFactory.getLogger(ItemType.class); + + public static ItemType of(String type) + { + try + { + return ItemType.valueOf(type.toUpperCase()); + } + catch (IllegalArgumentException ex) + { + logger.warn("unable to convert type", ex); + return DEFAULT; + } + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java b/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java new file mode 100644 index 0000000000..7e9b06c21b --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/GameItem.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, TheStonedTurtle + * 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.api.loottracker; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GameItem +{ + private int id; + private int qty; +} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java new file mode 100644 index 0000000000..a5437226cc --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootAggregate.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, Adam + * 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.api.loottracker; + +import java.time.Instant; +import java.util.Collection; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LootAggregate +{ + private String eventId; + private LootRecordType type; + private Collection drops; + private Instant first_time; + private Instant last_time; + private int amount; +} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java new file mode 100644 index 0000000000..a8e04aefd3 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018, TheStonedTurtle + * 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.api.loottracker; + +import java.time.Instant; +import java.util.Collection; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class LootRecord +{ + private String eventId; + private LootRecordType type; + private Object metadata; + private Collection drops; + private Instant time; + private Integer world; +} diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java new file mode 100644 index 0000000000..33e622de45 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecordType.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, TheStonedTurtle + * 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.api.loottracker; + +public enum LootRecordType +{ + NPC, + PLAYER, + EVENT, + PICKPOCKET, + UNKNOWN +} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/World.java b/http-api/src/main/java/net/runelite/http/api/worlds/World.java new file mode 100644 index 0000000000..70bc2c8237 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/worlds/World.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.worlds; + +import java.util.EnumSet; +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class World +{ + private int id; + private EnumSet types; + private String address; + private String activity; + private int location; + private int players; + + public WorldRegion getRegion() + { + return WorldRegion.valueOf(location); + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java new file mode 100644 index 0000000000..2c391e91f4 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, melky + * 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.api.worlds; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Holds the data for each world's region (location) + */ +@AllArgsConstructor +@Getter +public enum WorldRegion +{ + UNITED_STATES_OF_AMERICA("US", "USA"), + UNITED_KINGDOM("GB", "GBR"), + AUSTRALIA("AU", "AUS"), + GERMANY("DE", "DEU"); + + /** + * ISO-3166-1 alpha-2 country code + */ + private final String alpha2; + /** + * ISO-3166-1 alpha-3 country code + */ + private final String alpha3; + + /** + * Gets the region using the location id + * {@link WorldRegion} value. + * + * @param locationId the location id of world + * @return WorldRegion the region of the world + */ + public static WorldRegion valueOf(int locationId) + { + switch (locationId) + { + case 0: + return UNITED_STATES_OF_AMERICA; + case 1: + return UNITED_KINGDOM; + case 3: + return AUSTRALIA; + case 7: + return GERMANY; + default: + return null; + } + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java new file mode 100644 index 0000000000..a4afe23e85 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/worlds/WorldResult.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.worlds; + +import java.util.List; + +public class WorldResult +{ + private List worlds; + + public List getWorlds() + { + return worlds; + } + + public void setWorlds(List worlds) + { + this.worlds = worlds; + } + + public World findWorld(int worldNum) + { + for (World world : worlds) + { + if (world.getId() == worldNum) + { + return world; + } + } + return null; + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java new file mode 100644 index 0000000000..20639b5f3c --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/worlds/WorldType.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Lotto + * 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.api.worlds; + +public enum WorldType +{ + MEMBERS, + PVP, + BOUNTY, + SKILL_TOTAL, + HIGH_RISK, + LAST_MAN_STANDING, + NOSAVE_MODE, + DEADMAN, + TOURNAMENT, + SEASONAL; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000000..2819c92ceb --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.runelite.http.api.ws; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapter.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapter.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapter.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type"); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + JsonObject clone = new JsonObject(); + clone.add(typeFieldName, new JsonPrimitive(label)); + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java new file mode 100644 index 0000000000..328d0aa1a7 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.ws; + +import com.google.gson.Gson; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.ws.messages.Handshake; +import net.runelite.http.api.ws.messages.LoginResponse; +import net.runelite.http.api.ws.messages.party.Join; +import net.runelite.http.api.ws.messages.party.Part; +import net.runelite.http.api.ws.messages.party.PartyChatMessage; +import net.runelite.http.api.ws.messages.party.UserJoin; +import net.runelite.http.api.ws.messages.party.UserPart; +import net.runelite.http.api.ws.messages.party.UserSync; + +public class WebsocketGsonFactory +{ + private static final Collection> MESSAGES; + + static + { + final List> messages = new ArrayList<>(); + messages.add(Handshake.class); + messages.add(LoginResponse.class); + messages.add(Join.class); + messages.add(Part.class); + messages.add(UserJoin.class); + messages.add(UserPart.class); + messages.add(UserSync.class); + messages.add(PartyChatMessage.class); + MESSAGES = messages; + } + + public static RuntimeTypeAdapterFactory factory(final Collection> messages) + { + final RuntimeTypeAdapterFactory factory = RuntimeTypeAdapterFactory.of(WebsocketMessage.class); + + for (Class message : MESSAGES) + { + factory.registerSubtype(message); + } + + for (Class message : messages) + { + factory.registerSubtype(message); + } + + return factory; + } + + public static Gson build(final RuntimeTypeAdapterFactory factory) + { + return RuneLiteAPI.GSON.newBuilder() + .registerTypeAdapterFactory(factory) + .create(); + } + + public static Gson build() + { + return build(factory(Collections.emptyList())); + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java new file mode 100644 index 0000000000..d732c110cd --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketMessage.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.ws; + +public class WebsocketMessage +{ + protected boolean _party; + + public boolean isParty() + { + return _party; + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java new file mode 100644 index 0000000000..5320c95ab5 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/Handshake.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.ws.messages; + +import java.util.UUID; +import lombok.Data; +import net.runelite.http.api.ws.WebsocketMessage; + +@Data +public class Handshake extends WebsocketMessage +{ + private UUID session; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java new file mode 100644 index 0000000000..8f22db8f80 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/LoginResponse.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.ws.messages; + +import lombok.Data; +import net.runelite.http.api.ws.WebsocketMessage; + +/** + * Called after a successful login to the server + */ +@Data +public class LoginResponse extends WebsocketMessage +{ + private String username; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java new file mode 100644 index 0000000000..21aed0f653 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Join.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import java.util.UUID; +import lombok.EqualsAndHashCode; +import lombok.Value; +import net.runelite.http.api.ws.WebsocketMessage; + +@Value +@EqualsAndHashCode(callSuper = true) +public class Join extends WebsocketMessage +{ + private final UUID partyId; + private final String name; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java new file mode 100644 index 0000000000..e284ff0cf8 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/Part.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import net.runelite.http.api.ws.WebsocketMessage; + +public class Part extends WebsocketMessage +{ +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java new file mode 100644 index 0000000000..480e2660c1 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyChatMessage.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.api.ws.messages.party; + +import lombok.Value; + +@Value +public class PartyChatMessage extends PartyMemberMessage +{ + private final String value; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java new file mode 100644 index 0000000000..9d5cab8545 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMemberMessage.java @@ -0,0 +1,12 @@ +package net.runelite.http.api.ws.messages.party; + +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public abstract class PartyMemberMessage extends PartyMessage +{ + private UUID memberId; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java new file mode 100644 index 0000000000..709457ed8c --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/PartyMessage.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import net.runelite.http.api.ws.WebsocketMessage; + +public abstract class PartyMessage extends WebsocketMessage +{ + public PartyMessage() + { + _party = true; + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java new file mode 100644 index 0000000000..7f940e8060 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserJoin.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import java.util.UUID; +import lombok.EqualsAndHashCode; +import lombok.Value; +import net.runelite.http.api.ws.WebsocketMessage; + +@Value +@EqualsAndHashCode(callSuper = true) +public class UserJoin extends WebsocketMessage +{ + private final UUID memberId; + private final UUID partyId; + private final String name; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java new file mode 100644 index 0000000000..e80c6002bd --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserPart.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import java.util.UUID; +import lombok.EqualsAndHashCode; +import lombok.Value; +import net.runelite.http.api.ws.WebsocketMessage; + +@Value +@EqualsAndHashCode(callSuper = true) +public class UserPart extends WebsocketMessage +{ + private final UUID memberId; +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java new file mode 100644 index 0000000000..c95038c9fa --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/ws/messages/party/UserSync.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.api.ws.messages.party; + +import lombok.EqualsAndHashCode; +import lombok.Value; + +@Value +@EqualsAndHashCode(callSuper = true) +public class UserSync extends PartyMemberMessage +{ +} diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java new file mode 100644 index 0000000000..bed2a017f1 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/xtea/XteaKey.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.xtea; + +import lombok.Data; + +@Data +public class XteaKey +{ + private int region; + private int keys[]; +} diff --git a/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java new file mode 100644 index 0000000000..fdce607f59 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/xtea/XteaRequest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, Adam + * 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.api.xtea; + +import java.util.ArrayList; +import java.util.List; +import lombok.Data; + +@Data +public class XteaRequest +{ + private int revision; + private List keys = new ArrayList<>(); + + public void addKey(XteaKey key) + { + keys.add(key); + } +} diff --git a/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java new file mode 100644 index 0000000000..0fe0b2226a --- /dev/null +++ b/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Abex + * 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.api.gson; + +import java.awt.Color; +import net.runelite.http.api.RuneLiteAPI; +import org.junit.Assert; +import org.junit.Test; + +public class ColorTypeAdapterTest +{ + @Test + public void test() + { + test("null", null, true); + test("{\"value\":-13347208,\"falpha\":0.0}", new Color(0x12345678, false), false); + test("{\"value\":305419896,\"falpha\":0.0}", new Color(0x12345678, true), false); + test("{\"value\":-1.4221317E7,\"falpha\":0.0}", new Color(0xFF26FFFB, true), false); + test("\"#FF345678\"", new Color(0x12345678, false), true); + test("\"#12345678\"", new Color(0x12345678, true), true); + test("\"#FF26FFFB\"", new Color(0xFF26FFFB, true), true); + } + + private void test(String json, Color object, boolean exactEncoding) + { + Color parsed = RuneLiteAPI.GSON.fromJson(json, Color.class); + Assert.assertEquals(object, parsed); + String serialized = RuneLiteAPI.GSON.toJson(object); + if (exactEncoding) + { + Assert.assertEquals(json, serialized); + } + Color roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Color.class); + Assert.assertEquals(object, roundTripped); + } +} \ No newline at end of file diff --git a/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java new file mode 100644 index 0000000000..f9ed850843 --- /dev/null +++ b/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Abex + * 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.api.gson; + +import java.time.Instant; +import net.runelite.http.api.RuneLiteAPI; +import org.junit.Assert; +import org.junit.Test; + +public class InstantTypeAdapterTest +{ + @Test + public void test() + { + test("null", null, true); + test("{\"seconds\":1609538310,\"nanos\":291000000}", Instant.ofEpochSecond(1609538310, 291_000_000), false); + test("1609538310291", Instant.ofEpochSecond(1609538310, 291_000_000), true); + } + + private void test(String json, Instant object, boolean exactEncoding) + { + Instant parsed = RuneLiteAPI.GSON.fromJson(json, Instant.class); + Assert.assertEquals(object, parsed); + String serialized = RuneLiteAPI.GSON.toJson(object); + if (exactEncoding) + { + Assert.assertEquals(json, serialized); + } + Instant roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Instant.class); + Assert.assertEquals(object, roundTripped); + } +} \ No newline at end of file diff --git a/http-service/pom.xml b/http-service/pom.xml new file mode 100644 index 0000000000..d983f9e9da --- /dev/null +++ b/http-service/pom.xml @@ -0,0 +1,269 @@ + + + + 4.0.0 + + + net.runelite + runelite-parent + 1.8.8-SNAPSHOT + + + Web Service + http-service + war + + + 1.5.6.RELEASE + nogit + false + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.springframework.boot + spring-boot-devtools + true + + + org.springframework + spring-jdbc + + + + org.projectlombok + lombok + provided + + + + net.runelite + http-api + ${project.version} + + + net.runelite + cache + ${project.version} + + + + org.mariadb.jdbc + mariadb-java-client + 2.2.3 + provided + + + org.sql2o + sql2o + 1.5.4 + + + com.google.guava + guava + + + com.github.scribejava + scribejava-apis + 4.1.0 + + + io.minio + minio + 3.0.6 + + + redis.clients + jedis + 2.10.0 + + + org.apache.commons + commons-pool2 + + + + + org.mongodb + mongodb-driver-sync + 3.10.2 + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.squareup.okhttp3 + mockwebserver + 3.14.9 + test + + + com.h2database + h2 + test + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + runelite-${project.version} + + + + src/main/resources + true + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.1 + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + false + + + + com.github.kongchen + swagger-maven-plugin + 3.1.8 + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + + + true + + net.runelite + + + https + + api.runelite.net + /runelite-${project.version} + + ${project.parent.name} HTTP API + ${project.version} + ${project.description} + + https://tldrlegal.com/license/bsd-2-clause-license-(freebsd) + BSD 2-Clause "Simplified" + + + ${basedir}/src/main/templates/template.html.hbs + ${project.build.directory}/swagger-ui + ${project.build.directory}/site/api.html + true + json + + + + + + compile + + generate + + + + + + pl.project13.maven + git-commit-id-plugin + 2.2.6 + + + query-git-info + + revision + + + false + false + + true + + + git.commit.id.abbrev + git.dirty + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + + @ + + false + + + + + diff --git a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java new file mode 100644 index 0000000000..4c425cb0cf --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2017, Adam + * 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 ch.qos.logback.classic.LoggerContext; +import com.google.common.base.Strings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import java.io.IOException; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.naming.NamingException; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.ServletException; +import javax.sql.DataSource; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.service.util.InstantConverter; +import okhttp3.Cache; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.slf4j.ILoggerFactory; +import org.slf4j.impl.StaticLoggerBinder; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; +import org.springframework.jndi.JndiTemplate; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.sql2o.Sql2o; +import org.sql2o.converters.Converter; +import org.sql2o.quirks.NoQuirks; + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +@EnableScheduling +@Slf4j +public class SpringBootWebApplication extends SpringBootServletInitializer +{ + @Bean + protected ServletContextListener listener(OkHttpClient client) + { + return new ServletContextListener() + { + @Override + public void contextInitialized(ServletContextEvent sce) + { + log.info("RuneLite API started"); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) + { + // Destroy okhttp client + client.dispatcher().executorService().shutdown(); + client.connectionPool().evictAll(); + try + { + Cache cache = client.cache(); + if (cache != null) + { + cache.close(); + } + } + catch (IOException ex) + { + log.warn(null, ex); + } + + log.info("RuneLite API stopped"); + } + + }; + } + + @ConfigurationProperties(prefix = "datasource.runelite") + @Bean("dataSourceRuneLite") + public DataSourceProperties dataSourceProperties() + { + return new DataSourceProperties(); + } + + @ConfigurationProperties(prefix = "datasource.runelite-cache") + @Bean("dataSourceRuneLiteCache") + public DataSourceProperties dataSourcePropertiesCache() + { + return new DataSourceProperties(); + } + + @Bean(value = "runelite", destroyMethod = "") + public DataSource runeliteDataSource(@Qualifier("dataSourceRuneLite") DataSourceProperties dataSourceProperties) + { + return getDataSource(dataSourceProperties); + } + + @Bean(value = "runelite-cache", destroyMethod = "") + public DataSource runeliteCache2DataSource(@Qualifier("dataSourceRuneLiteCache") DataSourceProperties dataSourceProperties) + { + return getDataSource(dataSourceProperties); + } + + @Bean("Runelite SQL2O") + public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource) + { + return createSql2oFromDataSource(dataSource); + } + + @Bean("Runelite Cache SQL2O") + public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource) + { + return createSql2oFromDataSource(dataSource); + } + + @Bean(destroyMethod = "") + public MongoClient mongoClient(@Value("${mongo.host:}") String host, @Value("${mongo.jndiName:}") String jndiName) throws NamingException + { + if (!Strings.isNullOrEmpty(jndiName)) + { + JndiTemplate jndiTemplate = new JndiTemplate(); + return jndiTemplate.lookup(jndiName, MongoClient.class); + } + else if (!Strings.isNullOrEmpty(host)) + { + return MongoClients.create(host); + } + else + { + throw new RuntimeException("Either mongo.host or mongo.jndiName must be set"); + } + } + + private static DataSource getDataSource(DataSourceProperties dataSourceProperties) + { + if (!Strings.isNullOrEmpty(dataSourceProperties.getJndiName())) + { + // Use JNDI provided datasource, which is already configured with pooling + JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); + return dataSourceLookup.getDataSource(dataSourceProperties.getJndiName()); + } + else + { + return dataSourceProperties.initializeDataSourceBuilder().build(); + } + } + + private static Sql2o createSql2oFromDataSource(final DataSource dataSource) + { + final Map converters = new HashMap<>(); + converters.put(Instant.class, new InstantConverter()); + return new Sql2o(dataSource, new NoQuirks(converters)); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) + { + return application.sources(SpringBootWebApplication.class); + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException + { + super.onStartup(servletContext); + ILoggerFactory loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory(); + if (loggerFactory instanceof LoggerContext) + { + LoggerContext loggerContext = (LoggerContext) loggerFactory; + loggerContext.setPackagingDataEnabled(false); + log.debug("Disabling logback packaging data"); + } + } + + @Bean + public OkHttpClient okHttpClient( + @Value("${runelite.version}") String version, + @Value("${runelite.commit}") String commit, + @Value("${runelite.dirty}") boolean dirty + ) + { + final String userAgent = "RuneLite/" + version + "-" + commit + (dirty ? "+" : ""); + return new OkHttpClient.Builder() + .pingInterval(30, TimeUnit.SECONDS) + .addNetworkInterceptor(chain -> + { + Request userAgentRequest = chain.request() + .newBuilder() + .header("User-Agent", userAgent) + .build(); + return chain.proceed(userAgentRequest); + }) + .build(); + } + + public static void main(String[] args) + { + SpringApplication.run(SpringBootWebApplication.class, args); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java new file mode 100644 index 0000000000..6af0895619 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, Adam + * 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.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +@Configuration +public class SpringSchedulingConfigurer implements SchedulingConfigurer +{ + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) + { + // this is from ScheduledTaskRegistrar.scheduleTasks() but modified to give the scheduler thread a + // recognizable name + ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder() + .setNameFormat("scheduler-%d") + .build() + ); + TaskScheduler scheduler = new ConcurrentTaskScheduler(scheduledExecutorService); + taskRegistrar.setTaskScheduler(scheduler); + } +} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java new file mode 100644 index 0000000000..704e4f9cb2 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018, Adam + * 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.util.List; +import net.runelite.http.api.RuneLiteAPI; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableWebMvc +public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter +{ + /** + * Configure .js as application/json to trick Cloudflare into caching json responses + */ + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) + { + configurer.mediaType("js", MediaType.APPLICATION_JSON); + } + + /** + * Use GSON instead of Jackson for JSON serialization + * @param converters + */ + @Override + public void extendMessageConverters(List> converters) + { + // Could not figure out a better way to force GSON + converters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance); + + GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); + gsonHttpMessageConverter.setGson(RuneLiteAPI.GSON); + converters.add(gsonHttpMessageConverter); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java new file mode 100644 index 0000000000..10a289b927 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2017, Adam + * 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.account; + +import com.github.scribejava.apis.GoogleApi20; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +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.oauth.OAuth20Service; +import com.google.gson.Gson; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +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.account.OAuthResponse; +import net.runelite.http.api.ws.WebsocketGsonFactory; +import net.runelite.http.api.ws.WebsocketMessage; +import net.runelite.http.api.ws.messages.LoginResponse; +import net.runelite.http.service.account.beans.SessionEntry; +import net.runelite.http.service.account.beans.UserEntry; +import net.runelite.http.service.util.redis.RedisPool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +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.Sql2o; +import org.sql2o.Sql2oException; +import redis.clients.jedis.Jedis; + +@RestController +@RequestMapping("/account") +public class AccountService +{ + private static final Logger logger = LoggerFactory.getLogger(AccountService.class); + + private static final String CREATE_SESSIONS = "CREATE TABLE IF NOT EXISTS `sessions` (\n" + + " `user` int(11) NOT NULL PRIMARY KEY,\n" + + " `uuid` varchar(36) NOT NULL,\n" + + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" + + " `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" + + " UNIQUE KEY `uuid` (`uuid`),\n" + + " KEY `user` (`user`)\n" + + ") ENGINE=InnoDB"; + + private static final String CREATE_USERS = "CREATE TABLE IF NOT EXISTS `users` (\n" + + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + + " `username` tinytext NOT NULL,\n" + + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" + + " PRIMARY KEY (`id`),\n" + + " UNIQUE KEY `username` (`username`(64))\n" + + ") ENGINE=InnoDB"; + + private static final String SESSIONS_FK = "ALTER TABLE `sessions`\n" + + " ADD CONSTRAINT `id` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;"; + + private static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email"; + private static final String USERINFO = "https://www.googleapis.com/oauth2/v2/userinfo"; + private static final String RL_REDIR = "https://runelite.net/logged-in"; + + private final Gson gson = RuneLiteAPI.GSON; + private final Gson websocketGson = WebsocketGsonFactory.build(); + + private final Sql2o sql2o; + private final String oauthClientId; + private final String oauthClientSecret; + private final String oauthCallback; + private final String runeliteVersion; + private final AuthFilter auth; + private final RedisPool jedisPool; + + @Autowired + public AccountService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + @Value("${oauth.client-id}") String oauthClientId, + @Value("${oauth.client-secret}") String oauthClientSecret, + @Value("${oauth.callback}") String oauthCallback, + @Value("${runelite.version}") String runeliteVersion, + AuthFilter auth, + RedisPool jedisPool + ) + { + this.sql2o = sql2o; + this.oauthClientId = oauthClientId; + this.oauthClientSecret = oauthClientSecret; + this.oauthCallback = oauthCallback; + this.runeliteVersion = runeliteVersion; + this.auth = auth; + this.jedisPool = jedisPool; + + try (Connection con = sql2o.open()) + { + con.createQuery(CREATE_SESSIONS) + .executeUpdate(); + + con.createQuery(CREATE_USERS) + .executeUpdate(); + + try + { + con.createQuery(SESSIONS_FK) + .executeUpdate(); + } + catch (Sql2oException ex) + { + // Ignore, happens when index already exists + } + } + } + + @GetMapping("/login") + public OAuthResponse login(@RequestParam UUID uuid) + { + State state = new State(); + state.setUuid(uuid); + state.setApiVersion(runeliteVersion); + + OAuth20Service service = new ServiceBuilder() + .apiKey(oauthClientId) + .apiSecret(oauthClientSecret) + .scope(SCOPE) + .callback(oauthCallback) + .state(gson.toJson(state)) + .build(GoogleApi20.instance()); + + final Map additionalParams = new HashMap<>(); + additionalParams.put("prompt", "select_account"); + + String authorizationUrl = service.getAuthorizationUrl(additionalParams); + + OAuthResponse lr = new OAuthResponse(); + lr.setOauthUrl(authorizationUrl); + lr.setUid(uuid); + + return lr; + } + + @GetMapping("/callback") + public Object callback( + HttpServletRequest request, + HttpServletResponse response, + @RequestParam(required = false) String error, + @RequestParam String code, + @RequestParam("state") String stateStr + ) throws InterruptedException, ExecutionException, IOException + { + if (error != null) + { + logger.info("Error in oauth callback: {}", error); + return null; + } + + State state = gson.fromJson(stateStr, State.class); + + logger.info("Got authorization code {} for uuid {}", code, state.getUuid()); + + OAuth20Service service = new ServiceBuilder() + .apiKey(oauthClientId) + .apiSecret(oauthClientSecret) + .scope(SCOPE) + .callback(oauthCallback) + .state(gson.toJson(state)) + .build(GoogleApi20.instance()); + + OAuth2AccessToken accessToken = service.getAccessToken(code); + + // Access user info + OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO); + service.signRequest(accessToken, orequest); + + Response oresponse = service.execute(orequest); + + if (oresponse.getCode() / 100 != 2) + { + // Could be a forged result + return null; + } + + UserInfo userInfo = gson.fromJson(oresponse.getBody(), UserInfo.class); + + logger.info("Got user info: {}", userInfo); + + try (Connection con = sql2o.open()) + { + con.createQuery("insert ignore into users (username) values (:username)") + .addParameter("username", userInfo.getEmail()) + .executeUpdate(); + + UserEntry user = con.createQuery("select id from users where username = :username") + .addParameter("username", userInfo.getEmail()) + .executeAndFetchFirst(UserEntry.class); + + if (user == null) + { + logger.warn("Unable to find newly created user session"); + return null; // that's weird + } + + // insert session + con.createQuery("insert ignore into sessions (user, uuid) values (:user, :uuid)") + .addParameter("user", user.getId()) + .addParameter("uuid", state.getUuid().toString()) + .executeUpdate(); + + logger.info("Created session for user {}", userInfo.getEmail()); + } + + response.sendRedirect(RL_REDIR); + + notifySession(state.getUuid(), userInfo.getEmail()); + + return ""; + } + + private void notifySession(UUID uuid, String username) + { + LoginResponse response = new LoginResponse(); + response.setUsername(username); + + try (Jedis jedis = jedisPool.getResource()) + { + jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class)); + } + } + + @GetMapping("/logout") + public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException + { + SessionEntry session = auth.handle(request, response); + + if (session == null) + { + return; + } + + auth.invalidate(session.getUuid()); + + try (Connection con = sql2o.open()) + { + con.createQuery("delete from sessions where uuid = :uuid") + .addParameter("uuid", session.getUuid().toString()) + .executeUpdate(); + } + } + + @GetMapping("/session-check") + public void sessionCheck(HttpServletRequest request, HttpServletResponse response) throws IOException + { + auth.handle(request, response); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java new file mode 100644 index 0000000000..d283e71c5c --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017, Adam + * 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.account; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalNotification; +import java.io.IOException; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.runelite.http.api.RuneLiteAPI; +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.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.Sql2o; + +@Service +public class AuthFilter +{ + private final Sql2o sql2o; + + private final Cache sessionCache = CacheBuilder.newBuilder() + .maximumSize(10000L) + .expireAfterAccess(30, TimeUnit.MINUTES) + .removalListener(this::removalListener) + .build(); + + @Autowired + public AuthFilter(@Qualifier("Runelite SQL2O") Sql2o sql2o) + { + this.sql2o = sql2o; + } + + public SessionEntry handle(HttpServletRequest request, HttpServletResponse response) throws IOException + { + String runeliteAuth = request.getHeader(RuneLiteAPI.RUNELITE_AUTH); + if (runeliteAuth == null) + { + response.sendError(401, "Access denied"); + return null; + } + + UUID uuid = UUID.fromString(runeliteAuth); + SessionEntry sessionEntry = sessionCache.getIfPresent(uuid); + if (sessionEntry != null) + { + return sessionEntry; + } + + try (Connection con = sql2o.open()) + { + sessionEntry = con.createQuery("select user, uuid, created, last_used as lastUsed from sessions where uuid = :uuid") + .addParameter("uuid", uuid.toString()) + .executeAndFetchFirst(SessionEntry.class); + } + + if (sessionEntry == null) + { + response.sendError(401, "Access denied"); + return null; + } + + sessionCache.put(uuid, sessionEntry); + + return sessionEntry; + } + + private void removalListener(RemovalNotification notification) + { + UUID uuid = notification.getKey(); + Instant now = Instant.now(); + + try (Connection con = sql2o.open()) + { + con.createQuery("update sessions set last_used = :last_used where uuid = :uuid") + .addParameter("last_used", Timestamp.from(now)) + .addParameter("uuid", uuid.toString()) + .executeUpdate(); + } + } + + public void invalidate(UUID uuid) + { + // If we ever run multiple services, may need to publish something here to invalidate... + sessionCache.invalidate(uuid); + } + +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/State.java b/http-service/src/main/java/net/runelite/http/service/account/State.java new file mode 100644 index 0000000000..1412efa11a --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/State.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Adam + * 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.account; + +import java.util.UUID; +import lombok.Data; + +@Data +public class State +{ + private UUID uuid; + private String apiVersion; +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java b/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java new file mode 100644 index 0000000000..a1cde03f79 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Adam + * 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.account; + +public class UserInfo +{ + private String email; + + @Override + public String toString() + { + return "UserInfo{" + "email=" + email + '}'; + } + + public String getEmail() + { + return email; + } + + public void setEmail(String email) + { + this.email = email; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java new file mode 100644 index 0000000000..ded67c7a45 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Adam + * 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.account.beans; + +import java.time.Instant; +import java.util.UUID; + +public class SessionEntry +{ + private int user; + private UUID uuid; + private Instant created; + private Instant lastUsed; + + public int getUser() + { + return user; + } + + public void setUser(int user) + { + this.user = user; + } + + public UUID getUuid() + { + return uuid; + } + + public void setUuid(UUID uuid) + { + this.uuid = uuid; + } + + public Instant getCreated() + { + return created; + } + + public void setCreated(Instant created) + { + this.created = created; + } + + public Instant getLastUsed() + { + return lastUsed; + } + + public void setLastUsed(Instant lastUsed) + { + this.lastUsed = lastUsed; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java new file mode 100644 index 0000000000..83dd4152ac --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Adam + * 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.account.beans; + +public class UserEntry +{ + private int id; + private String username; + + @Override + public String toString() + { + return "UserEntry{" + "id=" + id + ", username=" + username + '}'; + } + + public int getId() + { + return id; + } + + public void setId(int id) + { + this.id = id; + } + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java new file mode 100644 index 0000000000..08282ca38e --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, Adam + * 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.cache; + +import java.util.List; +import net.runelite.cache.IndexType; +import net.runelite.http.service.cache.beans.ArchiveEntry; +import net.runelite.http.service.cache.beans.CacheEntry; +import net.runelite.http.service.cache.beans.FileEntry; +import net.runelite.http.service.cache.beans.IndexEntry; +import org.sql2o.Connection; +import org.sql2o.Query; +import org.sql2o.ResultSetIterable; + +class CacheDAO +{ + public List listCaches(Connection con) + { + return con.createQuery("select id, revision, date from cache") + .executeAndFetch(CacheEntry.class); + } + + public CacheEntry findMostRecent(Connection con) + { + return con.createQuery("select id, revision, date from cache order by revision desc, date desc limit 1") + .executeAndFetchFirst(CacheEntry.class); + } + + public List findIndexesForCache(Connection con, CacheEntry cache) + { + return con.createQuery("select id, indexId, crc, revision from `index` where cache = :cache") + .addParameter("cache", cache.getId()) + .executeAndFetch(IndexEntry.class); + } + + public IndexEntry findIndexForCache(Connection con, CacheEntry cache, int indexId) + { + return con.createQuery("select id, indexId, crc, revision from `index` " + + "where cache = :id " + + "and indexId = :indexId") + .addParameter("id", cache.getId()) + .addParameter("indexId", indexId) + .executeAndFetchFirst(IndexEntry.class); + } + + public ResultSetIterable findArchivesForIndex(Connection con, IndexEntry indexEntry) + { + return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," + + " archive.crc, archive.revision, archive.hash from index_archive " + + "join archive on index_archive.archive = archive.id " + + "where index_archive.index = :id") + .addParameter("id", indexEntry.getId()) + .executeAndFetchLazy(ArchiveEntry.class); + } + + public ArchiveEntry findArchiveForIndex(Connection con, IndexEntry indexEntry, int archiveId) + { + return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," + + " archive.crc, archive.revision, archive.hash from index_archive " + + "join archive on index_archive.archive = archive.id " + + "where index_archive.index = :id " + + "and archive.archiveId = :archiveId") + .addParameter("id", indexEntry.getId()) + .addParameter("archiveId", archiveId) + .executeAndFetchFirst(ArchiveEntry.class); + } + + public ArchiveEntry findArchiveByName(Connection con, CacheEntry cache, IndexType index, int nameHash) + { + return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," + + " archive.crc, archive.revision, archive.hash from archive " + + "join index_archive on index_archive.archive = archive.id " + + "join `index` on index.id = index_archive.index " + + "where index.cache = :cacheId " + + "and index.indexId = :indexId " + + "and archive.nameHash = :nameHash " + + "limit 1") + .addParameter("cacheId", cache.getId()) + .addParameter("indexId", index.getNumber()) + .addParameter("nameHash", nameHash) + .executeAndFetchFirst(ArchiveEntry.class); + } + + public ResultSetIterable findFilesForArchive(Connection con, ArchiveEntry archiveEntry) + { + Query findFilesForArchive = con.createQuery("select id, fileId, nameHash from file " + + "where archive = :archive"); + + return findFilesForArchive + .addParameter("archive", archiveEntry.getId()) + .executeAndFetchLazy(FileEntry.class); + } + + public CacheEntry findCache(Connection con, int cacheId) + { + return con.createQuery("select id, revision, date from cache " + + "where id = :cacheId") + .addParameter("cacheId", cacheId) + .executeAndFetchFirst(CacheEntry.class); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java new file mode 100644 index 0000000000..c0b767a68c --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2017-2018, Adam + * 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.cache; + +import com.google.common.collect.Iterables; +import com.google.common.io.BaseEncoding; +import com.google.common.io.ByteStreams; +import io.minio.MinioClient; +import io.minio.errors.ErrorResponseException; +import io.minio.errors.InsufficientDataException; +import io.minio.errors.InternalException; +import io.minio.errors.InvalidArgumentException; +import io.minio.errors.InvalidBucketNameException; +import io.minio.errors.InvalidEndpointException; +import io.minio.errors.InvalidPortException; +import io.minio.errors.NoResponseException; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import net.runelite.cache.ConfigType; +import net.runelite.cache.IndexType; +import net.runelite.cache.definitions.ItemDefinition; +import net.runelite.cache.definitions.loaders.ItemLoader; +import net.runelite.cache.fs.ArchiveFiles; +import net.runelite.cache.fs.Container; +import net.runelite.cache.fs.FSFile; +import net.runelite.http.service.cache.beans.ArchiveEntry; +import net.runelite.http.service.cache.beans.CacheEntry; +import net.runelite.http.service.cache.beans.FileEntry; +import net.runelite.http.service.cache.beans.IndexEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.ResultSetIterable; +import org.sql2o.Sql2o; +import org.xmlpull.v1.XmlPullParserException; + +@Service +@Slf4j +public class CacheService +{ + @Autowired + @Qualifier("Runelite Cache SQL2O") + private Sql2o sql2o; + + @Value("${minio.bucket}") + private String minioBucket; + + private final MinioClient minioClient; + + @Autowired + public CacheService( + @Value("${minio.endpoint}") String minioEndpoint, + @Value("${minio.accesskey}") String accessKey, + @Value("${minio.secretkey}") String secretKey + ) throws InvalidEndpointException, InvalidPortException + { + this.minioClient = new MinioClient(minioEndpoint, accessKey, secretKey); + } + + @Bean + public MinioClient minioClient() + { + return minioClient; + } + + /** + * retrieve archive from storage + * + * @param archiveEntry + * @return + */ + public byte[] getArchive(ArchiveEntry archiveEntry) + { + String hashStr = BaseEncoding.base16().encode(archiveEntry.getHash()); + String path = new StringBuilder() + .append(hashStr, 0, 2) + .append('/') + .append(hashStr.substring(2)) + .toString(); + + try (InputStream in = minioClient.getObject(minioBucket, path)) + { + return ByteStreams.toByteArray(in); + } + catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException + | IOException | InvalidKeyException | NoResponseException | XmlPullParserException + | ErrorResponseException | InternalException | InvalidArgumentException ex) + { + log.warn(null, ex); + return null; + } + } + + public ArchiveFiles getArchiveFiles(ArchiveEntry archiveEntry) throws IOException + { + CacheDAO cacheDao = new CacheDAO(); + + try (Connection con = sql2o.open(); + ResultSetIterable files = cacheDao.findFilesForArchive(con, archiveEntry)) + { + byte[] archiveData = getArchive(archiveEntry); + + if (archiveData == null) + { + return null; + } + + Container result = Container.decompress(archiveData, null); + if (result == null) + { + return null; + } + + byte[] decompressedData = result.data; + + ArchiveFiles archiveFiles = new ArchiveFiles(); + for (FileEntry fileEntry : files) + { + FSFile file = new FSFile(fileEntry.getFileId()); + archiveFiles.addFile(file); + file.setNameHash(fileEntry.getNameHash()); + } + archiveFiles.loadContents(decompressedData); + return archiveFiles; + } + } + + public List listCaches() + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.listCaches(con); + } + } + + public CacheEntry findCache(int cacheId) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findCache(con, cacheId); + } + } + + public CacheEntry findMostRecent() + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findMostRecent(con); + } + } + + public List findIndexesForCache(CacheEntry cacheEntry) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findIndexesForCache(con, cacheEntry); + } + } + + public IndexEntry findIndexForCache(CacheEntry cahceEntry, int indexId) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findIndexForCache(con, cahceEntry, indexId); + } + } + + public List findArchivesForIndex(IndexEntry indexEntry) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + ResultSetIterable archiveEntries = cacheDao.findArchivesForIndex(con, indexEntry); + List archives = new ArrayList<>(); + Iterables.addAll(archives, archiveEntries); + return archives; + } + } + + public ArchiveEntry findArchiveForIndex(IndexEntry indexEntry, int archiveId) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findArchiveForIndex(con, indexEntry, archiveId); + } + } + + public ArchiveEntry findArchiveForTypeAndName(CacheEntry cache, IndexType index, int nameHash) + { + try (Connection con = sql2o.open()) + { + CacheDAO cacheDao = new CacheDAO(); + return cacheDao.findArchiveByName(con, cache, index, nameHash); + } + } + + public List getItems() throws IOException + { + CacheEntry cache = findMostRecent(); + if (cache == null) + { + return Collections.emptyList(); + } + + IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber()); + ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId()); + ArchiveFiles archiveFiles = getArchiveFiles(archiveEntry); + final ItemLoader itemLoader = new ItemLoader(); + final List result = new ArrayList<>(archiveFiles.getFiles().size()); + for (FSFile file : archiveFiles.getFiles()) + { + ItemDefinition itemDef = itemLoader.load(file.getFileId(), file.getContents()); + result.add(itemDef); + } + return result; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java new file mode 100644 index 0000000000..acda96e77f --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, Adam + * 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.cache.beans; + +import lombok.Data; + +@Data +public class ArchiveEntry +{ + private int id; + private int archiveId; + private int nameHash; + private int crc; + private int revision; + private byte[] hash; +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java new file mode 100644 index 0000000000..231ad7c655 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.cache.beans; + +import java.time.Instant; +import lombok.Data; + +@Data +public class CacheEntry +{ + private int id; + private int revision; + private Instant date; +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java new file mode 100644 index 0000000000..c5f35a4cc3 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.cache.beans; + +import lombok.Data; + +@Data +public class FileEntry +{ + private int id; + private int archiveId; + private int fileId; + private int nameHash; +} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java new file mode 100644 index 0000000000..8d60927c71 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.cache.beans; + +import lombok.Data; + +@Data +public class IndexEntry +{ + private int id; + private int indexId; + private int crc; + private int revision; +} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java new file mode 100644 index 0000000000..954c90e94b --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2018, Adam + * 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.chat; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.runelite.http.api.chat.Duels; +import net.runelite.http.api.chat.LayoutRoom; +import net.runelite.http.api.chat.Task; +import net.runelite.http.service.util.exception.NotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.CacheControl; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/chat") +public class ChatController +{ + private static final Pattern STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]"); + private static final int STRING_MAX_LENGTH = 50; + private static final int MAX_LAYOUT_ROOMS = 16; + private static final int MAX_PETS = 256; + + private final Cache killCountCache = CacheBuilder.newBuilder() + .expireAfterWrite(2, TimeUnit.MINUTES) + .maximumSize(128L) + .build(); + + @Autowired + private ChatService chatService; + + @PostMapping("/kc") + public void submitKc(@RequestParam String name, @RequestParam String boss, @RequestParam int kc) + { + if (kc <= 0) + { + return; + } + + chatService.setKc(name, boss, kc); + killCountCache.put(new KillCountKey(name, boss), kc); + } + + @GetMapping("/kc") + public int getKc(@RequestParam String name, @RequestParam String boss) + { + Integer kc = killCountCache.getIfPresent(new KillCountKey(name, boss)); + if (kc == null) + { + kc = chatService.getKc(name, boss); + if (kc != null) + { + killCountCache.put(new KillCountKey(name, boss), kc); + } + } + + if (kc == null) + { + throw new NotFoundException(); + } + return kc; + } + + @PostMapping("/qp") + public void submitQp(@RequestParam String name, @RequestParam int qp) + { + if (qp < 0) + { + return; + } + + chatService.setQp(name, qp); + } + + @GetMapping("/qp") + public int getQp(@RequestParam String name) + { + Integer kc = chatService.getQp(name); + if (kc == null) + { + throw new NotFoundException(); + } + return kc; + } + + @PostMapping("/gc") + public void submitGc(@RequestParam String name, @RequestParam int gc) + { + if (gc < 0) + { + return; + } + + chatService.setGc(name, gc); + } + + @GetMapping("/gc") + public int getKc(@RequestParam String name) + { + Integer gc = chatService.getGc(name); + if (gc == null) + { + throw new NotFoundException(); + } + return gc; + } + + @PostMapping("/task") + public void submitTask(@RequestParam String name, @RequestParam("task") String taskName, @RequestParam int amount, + @RequestParam int initialAmount, @RequestParam String location) + { + Matcher mTask = STRING_VALIDATION.matcher(taskName); + Matcher mLocation = STRING_VALIDATION.matcher(location); + if (mTask.find() || taskName.length() > STRING_MAX_LENGTH || + mLocation.find() || location.length() > STRING_MAX_LENGTH) + { + return; + } + + Task task = new Task(); + task.setTask(taskName); + task.setAmount(amount); + task.setInitialAmount(initialAmount); + task.setLocation(location); + + chatService.setTask(name, task); + } + + @GetMapping("/task") + public ResponseEntity getTask(@RequestParam String name) + { + Task task = chatService.getTask(name); + if (task == null) + { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .build(); + } + + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(2, TimeUnit.MINUTES).cachePublic()) + .body(task); + } + + @PostMapping("/pb") + public void submitPb(@RequestParam String name, @RequestParam String boss, @RequestParam double pb) + { + if (pb < 0) + { + return; + } + + chatService.setPb(name, boss, pb); + } + + @GetMapping("/pb") + public double getPb(@RequestParam String name, @RequestParam String boss) + { + Double pb = chatService.getPb(name, boss); + if (pb == null) + { + throw new NotFoundException(); + } + return pb; + } + + @PostMapping("/duels") + public void submitDuels(@RequestParam String name, @RequestParam int wins, + @RequestParam int losses, + @RequestParam int winningStreak, @RequestParam int losingStreak) + { + if (wins < 0 || losses < 0 || winningStreak < 0 || losingStreak < 0) + { + return; + } + + Duels duels = new Duels(); + duels.setWins(wins); + duels.setLosses(losses); + duels.setWinningStreak(winningStreak); + duels.setLosingStreak(losingStreak); + + chatService.setDuels(name, duels); + } + + @GetMapping("/duels") + public Duels getDuels(@RequestParam String name) + { + Duels duels = chatService.getDuels(name); + if (duels == null) + { + throw new NotFoundException(); + } + return duels; + } + + @PostMapping("/layout") + public void submitLayout(@RequestParam String name, @RequestBody LayoutRoom[] rooms) + { + if (rooms.length > MAX_LAYOUT_ROOMS) + { + return; + } + + chatService.setLayout(name, rooms); + } + + @GetMapping("/layout") + public LayoutRoom[] getLayout(@RequestParam String name) + { + LayoutRoom[] layout = chatService.getLayout(name); + + if (layout == null) + { + throw new NotFoundException(); + } + + return layout; + } + + @PostMapping("/pets") + public void submitPetList(@RequestParam String name, @RequestBody int[] petList) + { + if (petList.length == 0 || petList.length > MAX_PETS) + { + return; + } + + chatService.setPetList(name, petList); + } + + @GetMapping("/pets") + public int[] getPetList(@RequestParam String name) + { + int[] petList = chatService.getPetList(name); + if (petList == null) + { + throw new NotFoundException(); + } + + return petList; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java new file mode 100644 index 0000000000..7748728aab --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2018, Adam + * 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.chat; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.runelite.http.api.chat.Duels; +import net.runelite.http.api.chat.LayoutRoom; +import net.runelite.http.api.chat.Task; +import net.runelite.http.service.util.redis.RedisPool; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import redis.clients.jedis.Jedis; + +@Service +public class ChatService +{ + private static final Duration EXPIRE = Duration.ofMinutes(2); + + private final RedisPool jedisPool; + + @Autowired + public ChatService(RedisPool jedisPool) + { + this.jedisPool = jedisPool; + } + + public Integer getKc(String name, String boss) + { + String value; + try (Jedis jedis = jedisPool.getResource()) + { + value = jedis.get("kc." + name + "." + boss); + } + return value == null ? null : Integer.parseInt(value); + } + + public void setKc(String name, String boss, int kc) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("kc." + name + "." + boss, (int) EXPIRE.getSeconds(), Integer.toString(kc)); + } + } + + public Integer getQp(String name) + { + String value; + try (Jedis jedis = jedisPool.getResource()) + { + value = jedis.get("qp." + name); + } + return value == null ? null : Integer.parseInt(value); + } + + public void setQp(String name, int qp) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("qp." + name, (int) EXPIRE.getSeconds(), Integer.toString(qp)); + } + } + + public Task getTask(String name) + { + Map map; + + try (Jedis jedis = jedisPool.getResource()) + { + map = jedis.hgetAll("task." + name); + } + + if (map.isEmpty()) + { + return null; + } + + Task task = new Task(); + task.setTask(map.get("task")); + task.setAmount(Integer.parseInt(map.get("amount"))); + task.setInitialAmount(Integer.parseInt(map.get("initialAmount"))); + task.setLocation(map.get("location")); + return task; + } + + public void setTask(String name, Task task) + { + Map taskMap = ImmutableMap.builderWithExpectedSize(4) + .put("task", task.getTask()) + .put("amount", Integer.toString(task.getAmount())) + .put("initialAmount", Integer.toString(task.getInitialAmount())) + .put("location", task.getLocation()) + .build(); + + String key = "task." + name; + + try (Jedis jedis = jedisPool.getResource()) + { + jedis.hmset(key, taskMap); + jedis.expire(key, (int) EXPIRE.getSeconds()); + } + } + + public Double getPb(String name, String boss) + { + String value; + try (Jedis jedis = jedisPool.getResource()) + { + value = jedis.get("pb." + boss + "." + name); + } + return value == null ? null : Double.parseDouble(value); + } + + public void setPb(String name, String boss, double pb) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("pb." + boss + "." + name, (int) EXPIRE.getSeconds(), Double.toString(pb)); + } + } + + public Integer getGc(String name) + { + String value; + try (Jedis jedis = jedisPool.getResource()) + { + value = jedis.get("gc." + name); + } + return value == null ? null : Integer.parseInt(value); + } + + public void setGc(String name, int gc) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("gc." + name, (int) EXPIRE.getSeconds(), Integer.toString(gc)); + } + } + + public Duels getDuels(String name) + { + Map map; + + try (Jedis jedis = jedisPool.getResource()) + { + map = jedis.hgetAll("duels." + name); + } + + if (map.isEmpty()) + { + return null; + } + + Duels duels = new Duels(); + duels.setWins(Integer.parseInt(map.get("wins"))); + duels.setLosses(Integer.parseInt(map.get("losses"))); + duels.setWinningStreak(Integer.parseInt(map.get("winningStreak"))); + duels.setLosingStreak(Integer.parseInt(map.get("losingStreak"))); + return duels; + } + + public void setDuels(String name, Duels duels) + { + Map duelsMap = ImmutableMap.builderWithExpectedSize(4) + .put("wins", Integer.toString(duels.getWins())) + .put("losses", Integer.toString(duels.getLosses())) + .put("winningStreak", Integer.toString(duels.getWinningStreak())) + .put("losingStreak", Integer.toString(duels.getLosingStreak())) + .build(); + + String key = "duels." + name; + + try (Jedis jedis = jedisPool.getResource()) + { + jedis.hmset(key, duelsMap); + jedis.expire(key, (int) EXPIRE.getSeconds()); + } + } + + public LayoutRoom[] getLayout(String name) + { + String layout; + try (Jedis jedis = jedisPool.getResource()) + { + layout = jedis.get("layout." + name); + } + + if (layout == null) + { + return null; + } + + List roomList = Splitter.on(' ').splitToList(layout); + return roomList.stream() + .map(LayoutRoom::valueOf) + .toArray(LayoutRoom[]::new); + } + + public void setLayout(String name, LayoutRoom[] rooms) + { + try (Jedis jedis = jedisPool.getResource()) + { + jedis.setex("layout." + name, (int) EXPIRE.getSeconds(), Joiner.on(' ').join(rooms)); + } + } + + public int[] getPetList(String name) + { + Set pets; + try (Jedis jedis = jedisPool.getResource()) + { + pets = jedis.smembers("pets." + name); + } + + if (pets.isEmpty()) + { + return null; + } + + return pets.stream() + .mapToInt(Integer::parseInt) + .toArray(); + } + + public void setPetList(String name, int[] petList) + { + String[] pets = Arrays.stream(petList).mapToObj(Integer::toString).toArray(String[]::new); + String key = "pets." + name; + try (Jedis jedis = jedisPool.getResource()) + { + jedis.sadd(key, pets); + jedis.expire(key, (int) EXPIRE.getSeconds()); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java b/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java new file mode 100644 index 0000000000..07ca775dad --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, Adam + * 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.chat; + +import lombok.Value; + +@Value +class KillCountKey +{ + private String username; + private String boss; +} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java new file mode 100644 index 0000000000..c247ecc0bc --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019, Adam + * 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.config; + +import java.io.IOException; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.runelite.http.api.config.Configuration; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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; + +@RestController +@RequestMapping("/config") +public class ConfigController +{ + private final ConfigService configService; + private final AuthFilter authFilter; + + @Autowired + public ConfigController(ConfigService configService, AuthFilter authFilter) + { + this.configService = configService; + this.authFilter = authFilter; + } + + @GetMapping + public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + + if (session == null) + { + return null; + } + + return configService.get(session.getUser()); + } + + @PatchMapping + public List patch( + HttpServletRequest request, + HttpServletResponse response, + @RequestBody Configuration changes + ) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + if (session == null) + { + return null; + } + + List failures = configService.patch(session.getUser(), changes); + if (failures.size() != 0) + { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return failures; + } + + return null; + } + + @RequestMapping(path = "/{key:.+}", method = PUT) + public void setKey( + HttpServletRequest request, + HttpServletResponse response, + @PathVariable String key, + @RequestBody(required = false) String value + ) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + + if (session == null) + { + return; + } + + if (!configService.setKey(session.getUser(), key, value)) + { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + + @RequestMapping(path = "/{key:.+}", method = DELETE) + public void unsetKey( + HttpServletRequest request, + HttpServletResponse response, + @PathVariable String key + ) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + + if (session == null) + { + return; + } + + if (!configService.unsetKey(session.getUser(), key)) + { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java new file mode 100644 index 0000000000..bb6050ad4b --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2017-2019, Adam + * 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.config; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import static com.mongodb.client.model.Filters.eq; +import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.Indexes; +import com.mongodb.client.model.UpdateOptions; +import static com.mongodb.client.model.Updates.combine; +import static com.mongodb.client.model.Updates.set; +import static com.mongodb.client.model.Updates.unset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import javax.annotation.Nullable; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.config.ConfigEntry; +import net.runelite.http.api.config.Configuration; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class ConfigService +{ + private static final Pattern MAYBE_JSON = Pattern.compile("^[\\-0-9{\\[\"]|true|false"); + private static final int MAX_DEPTH = 8; + private static final int MAX_VALUE_LENGTH = 262144; + + private final Gson GSON = RuneLiteAPI.GSON; + private final UpdateOptions upsertUpdateOptions = new UpdateOptions().upsert(true); + + private final MongoCollection mongoCollection; + + @Autowired + public ConfigService( + MongoClient mongoClient, + @Value("${mongo.database}") String databaseName + ) + { + + MongoDatabase database = mongoClient.getDatabase(databaseName); + MongoCollection collection = database.getCollection("config"); + this.mongoCollection = collection; + + // Create unique index on _userId + IndexOptions indexOptions = new IndexOptions().unique(true); + collection.createIndex(Indexes.ascending("_userId"), indexOptions); + } + + private Document getConfig(int userId) + { + return mongoCollection.find(eq("_userId", userId)).first(); + } + + public Configuration get(int userId) + { + Map configMap = getConfig(userId); + + if (configMap == null || configMap.isEmpty()) + { + return new Configuration(Collections.emptyList()); + } + + List config = new ArrayList<>(); + + for (String group : configMap.keySet()) + { + // Reserved keys + if (group.startsWith("_") || group.startsWith("$")) + { + continue; + } + + Map groupMap = (Map) configMap.get(group); + + for (Map.Entry entry : groupMap.entrySet()) + { + String key = entry.getKey(); + Object value = entry.getValue(); + + if (value instanceof Map || value instanceof Collection) + { + value = GSON.toJson(entry.getValue()); + } + else if (value == null) + { + continue; + } + + ConfigEntry configEntry = new ConfigEntry(); + configEntry.setKey(group + "." + key.replace(':', '.')); + configEntry.setValue(value.toString()); + config.add(configEntry); + } + } + + return new Configuration(config); + } + + public List patch(int userID, Configuration config) + { + List failures = new ArrayList<>(); + List sets = new ArrayList<>(config.getConfig().size()); + for (ConfigEntry entry : config.getConfig()) + { + Bson s = setForKV(entry.getKey(), entry.getValue()); + if (s == null) + { + failures.add(entry.getKey()); + } + else + { + sets.add(s); + } + } + + if (sets.size() > 0) + { + mongoCollection.updateOne( + eq("_userId", userID), + combine(sets), + upsertUpdateOptions + ); + } + + return failures; + } + + @Nullable + private Bson setForKV(String key, @Nullable String value) + { + if (key.startsWith("$") || key.startsWith("_")) + { + return null; + } + + String[] split = key.split("\\.", 2); + if (split.length != 2) + { + return null; + } + + String dbKey = split[0] + "." + split[1].replace('.', ':'); + + if (Strings.isNullOrEmpty(value)) + { + return unset(dbKey); + } + + Object jsonValue; + if (!isMaybeJson(value)) + { + if (!validateStr(value)) + { + return null; + } + + jsonValue = value; + } + else + { + if (!validateJson(value)) + { + return null; + } + + jsonValue = parseJsonString(value); + } + return set(dbKey, jsonValue); + } + + public boolean setKey( + int userId, + String key, + @Nullable String value + ) + { + Bson set = setForKV(key, value); + if (set == null) + { + return false; + } + + mongoCollection.updateOne(eq("_userId", userId), + set, + upsertUpdateOptions); + return true; + } + + public boolean unsetKey( + int userId, + String key + ) + { + Bson set = setForKV(key, null); + if (set == null) + { + return false; + } + + mongoCollection.updateOne(eq("_userId", userId), set); + return true; + } + + @VisibleForTesting + static Object parseJsonString(String value) + { + Object jsonValue; + try + { + jsonValue = RuneLiteAPI.GSON.fromJson(value, Object.class); + if (jsonValue == null) + { + return value; + } + else if (jsonValue instanceof Double || jsonValue instanceof Float) + { + Number number = (Number) jsonValue; + if (Math.floor(number.doubleValue()) == number.doubleValue() && !Double.isInfinite(number.doubleValue())) + { + // value is an int or long. 'number' might be truncated so parse it from 'value' + try + { + jsonValue = Integer.parseInt(value); + } + catch (NumberFormatException ex) + { + try + { + jsonValue = Long.parseLong(value); + } + catch (NumberFormatException ex2) + { + + } + } + } + } + } + catch (JsonSyntaxException ex) + { + jsonValue = value; + } + return jsonValue; + } + + @VisibleForTesting + static boolean isMaybeJson(String value) + { + return MAYBE_JSON.matcher(value).find(); + } + + private static boolean validateStr(String value) + { + return value.length() < MAX_VALUE_LENGTH; + } + + @VisibleForTesting + static boolean validateJson(String value) + { + try + { + // I couldn't figure out a better way to do this than a second json parse + JsonElement jsonElement = RuneLiteAPI.GSON.fromJson(value, JsonElement.class); + if (jsonElement == null) + { + return value.length() < MAX_VALUE_LENGTH; + } + return validateObject(jsonElement, 1); + } + catch (JsonSyntaxException ex) + { + // the client submits the string representation of objects which is not always valid json, + // eg. a value with a ':' in it. We just ignore it now. We can't json encode the values client + // side due to them already being strings, which prevents gson from being able to convert them + // to ints/floats/maps etc. + return value.length() < MAX_VALUE_LENGTH; + } + } + + private static boolean validateObject(JsonElement jsonElement, int depth) + { + if (depth >= MAX_DEPTH) + { + return false; + } + + if (jsonElement.isJsonObject()) + { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + for (Map.Entry entry : jsonObject.entrySet()) + { + JsonElement element = entry.getValue(); + + if (!validateObject(element, depth + 1)) + { + return false; + } + } + } + else if (jsonElement.isJsonArray()) + { + JsonArray jsonArray = jsonElement.getAsJsonArray(); + + for (int i = 0; i < jsonArray.size(); ++i) + { + JsonElement element = jsonArray.get(i); + + if (!validateObject(element, depth + 1)) + { + return false; + } + } + } + else if (jsonElement.isJsonPrimitive()) + { + JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive(); + String value = jsonPrimitive.getAsString(); + if (value.length() >= MAX_VALUE_LENGTH) + { + return false; + } + } + + return true; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java b/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java new file mode 100644 index 0000000000..9c799d9873 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed; + +import com.google.common.hash.HashCode; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.feed.FeedItem; +import net.runelite.http.api.feed.FeedResult; +import net.runelite.http.service.feed.blog.BlogService; +import net.runelite.http.service.feed.osrsnews.OSRSNewsService; +import net.runelite.http.service.feed.twitter.TwitterService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.CacheControl; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/feed") +@Slf4j +public class FeedController +{ + private final BlogService blogService; + private final TwitterService twitterService; + private final OSRSNewsService osrsNewsService; + + private static class MemoizedFeed + { + final FeedResult feedResult; + final String hash; + + MemoizedFeed(FeedResult feedResult) + { + this.feedResult = feedResult; + + Hasher hasher = Hashing.sha256().newHasher(); + for (FeedItem itemPrice : feedResult.getItems()) + { + hasher.putBytes(itemPrice.getTitle().getBytes(StandardCharsets.UTF_8)).putBytes(itemPrice.getContent().getBytes(StandardCharsets.UTF_8)); + } + HashCode code = hasher.hash(); + hash = code.toString(); + } + } + + private MemoizedFeed memoizedFeed; + + @Autowired + public FeedController(BlogService blogService, TwitterService twitterService, OSRSNewsService osrsNewsService) + { + this.blogService = blogService; + this.twitterService = twitterService; + this.osrsNewsService = osrsNewsService; + } + + @Scheduled(fixedDelay = 10 * 60 * 1000) + public void updateFeed() + { + List items = new ArrayList<>(); + + try + { + items.addAll(blogService.getBlogPosts()); + } + catch (Exception e) + { + log.warn("unable to fetch blogs", e); + } + + try + { + items.addAll(twitterService.getTweets()); + } + catch (Exception e) + { + log.warn("unable to fetch tweets", e); + } + + try + { + items.addAll(osrsNewsService.getNews()); + } + catch (Exception e) + { + log.warn("unable to fetch news", e); + } + + memoizedFeed = new MemoizedFeed(new FeedResult(items)); + } + + @GetMapping + public ResponseEntity getFeed() + { + if (memoizedFeed == null) + { + return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) + .cacheControl(CacheControl.noCache()) + .build(); + } + + return ResponseEntity.ok() + .eTag(memoizedFeed.hash) + .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) + .body(memoizedFeed.feedResult); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java b/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java new file mode 100644 index 0000000000..72f7938910 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.blog; + +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import net.runelite.http.api.feed.FeedItem; +import net.runelite.http.api.feed.FeedItemType; +import net.runelite.http.service.util.exception.InternalServerErrorException; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +@Service +public class BlogService +{ + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + + private final OkHttpClient okHttpClient; + private final HttpUrl rssUrl; + + @Autowired + public BlogService( + OkHttpClient okHttpClient, + @Value("${runelite.feed.rssUrl}") String rssUrl + ) + { + this.okHttpClient = okHttpClient; + this.rssUrl = HttpUrl.get(rssUrl); + } + + public List getBlogPosts() throws IOException + { + Request request = new Request.Builder() + .url(rssUrl) + .build(); + + try (Response response = okHttpClient.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Error getting blog posts: " + response); + } + + try + { + InputStream in = response.body().byteStream(); + Document document = DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(in); + + Element documentElement = document.getDocumentElement(); + NodeList documentItems = documentElement.getElementsByTagName("entry"); + + List items = new ArrayList<>(); + + for (int i = 0; i < Math.min(documentItems.getLength(), 3); i++) + { + Node item = documentItems.item(i); + NodeList children = item.getChildNodes(); + + String title = null; + String summary = null; + String link = null; + long timestamp = -1; + + for (int j = 0; j < children.getLength(); j++) + { + Node childItem = children.item(j); + String nodeName = childItem.getNodeName(); + + switch (nodeName) + { + case "title": + title = childItem.getTextContent(); + break; + case "summary": + summary = childItem.getTextContent().replace("\n", "").trim(); + break; + case "link": + link = childItem.getAttributes().getNamedItem("href").getTextContent(); + break; + case "updated": + timestamp = DATE_FORMAT.parse(childItem.getTextContent()).getTime(); + break; + } + } + + if (title == null || summary == null || link == null || timestamp == -1) + { + throw new InternalServerErrorException("Failed to find title, summary, link and/or timestamp in the blog post feed"); + } + + items.add(new FeedItem(FeedItemType.BLOG_POST, title, summary, link, timestamp)); + } + + return items; + } + catch (ParserConfigurationException | SAXException | ParseException e) + { + throw new InternalServerErrorException("Failed to parse blog posts: " + e.getMessage()); + } + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java b/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java new file mode 100644 index 0000000000..e53b2d8044 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.osrsnews; + +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import net.runelite.http.api.feed.FeedItem; +import net.runelite.http.api.feed.FeedItemType; +import net.runelite.http.service.util.exception.InternalServerErrorException; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +@Service +public class OSRSNewsService +{ + private static final SimpleDateFormat PUB_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy '00:00:00 GMT'", Locale.US); + + private final OkHttpClient okHttpClient; + private final HttpUrl rssUrl; + + @Autowired + public OSRSNewsService( + OkHttpClient okHttpClient, + @Value("${runelite.osrsnews.rssUrl}") String rssUrl + ) + { + this.okHttpClient = okHttpClient; + this.rssUrl = HttpUrl.get(rssUrl); + } + + public List getNews() throws IOException + { + Request request = new Request.Builder() + .url(rssUrl) + .build(); + + try (Response response = okHttpClient.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Error getting OSRS news: " + response); + } + + try + { + InputStream in = response.body().byteStream(); + Document document = DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(in); + + Element documentElement = document.getDocumentElement(); + NodeList documentItems = documentElement.getElementsByTagName("item"); + + List items = new ArrayList<>(); + + for (int i = 0; i < documentItems.getLength(); i++) + { + Node item = documentItems.item(i); + NodeList children = item.getChildNodes(); + + String title = null; + String description = null; + String link = null; + long timestamp = -1; + + for (int j = 0; j < children.getLength(); j++) + { + Node childItem = children.item(j); + String nodeName = childItem.getNodeName(); + + switch (nodeName) + { + case "title": + title = childItem.getTextContent(); + break; + case "description": + description = childItem.getTextContent().replace("\n", "").trim(); + break; + case "link": + link = childItem.getTextContent(); + break; + case "pubDate": + timestamp = PUB_DATE_FORMAT.parse(childItem.getTextContent()).getTime(); + break; + } + } + + if (title == null || description == null || link == null || timestamp == -1) + { + throw new InternalServerErrorException("Failed to find title, description, link and/or timestamp in the OSRS RSS feed"); + } + + items.add(new FeedItem(FeedItemType.OSRS_NEWS, title, description, link, timestamp)); + } + + return items; + } + catch (ParserConfigurationException | SAXException | ParseException e) + { + throw new InternalServerErrorException("Failed to parse OSRS news: " + e.getMessage()); + } + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java new file mode 100644 index 0000000000..24df0b6cf6 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.twitter; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +@Data +class TwitterOAuth2TokenResponse +{ + @SerializedName("token_type") + private String tokenType; + + @SerializedName("access_token") + private String token; +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java new file mode 100644 index 0000000000..4b7b026646 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.twitter; + +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.feed.FeedItem; +import net.runelite.http.api.feed.FeedItemType; +import net.runelite.http.service.util.exception.InternalServerErrorException; +import okhttp3.FormBody; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +@Service +public class TwitterService +{ + private static final HttpUrl AUTH_URL = HttpUrl.parse("https://api.twitter.com/oauth2/token"); + private static final HttpUrl LIST_STATUSES_URL = HttpUrl.parse("https://api.twitter.com/1.1/lists/statuses.json"); + + private final String credentials; + private final String listId; + private final OkHttpClient okHttpClient; + + private String token; + + @Autowired + public TwitterService( + @Value("${runelite.twitter.consumerkey}") String consumerKey, + @Value("${runelite.twitter.secretkey}") String consumerSecret, + @Value("${runelite.twitter.listid}") String listId, + OkHttpClient okHttpClient + ) + { + this.credentials = consumerKey + ":" + consumerSecret; + this.listId = listId; + this.okHttpClient = okHttpClient; + } + + public List getTweets() throws IOException + { + return getTweets(false); + } + + private List getTweets(boolean hasRetried) throws IOException + { + if (token == null) + { + updateToken(); + } + + HttpUrl url = LIST_STATUSES_URL.newBuilder() + .addQueryParameter("list_id", listId) + .addQueryParameter("count", "15") + .addQueryParameter("include_entities", "false") + .build(); + + Request request = new Request.Builder() + .url(url) + .header("Authorization", "Bearer " + token) + .build(); + + try (Response response = okHttpClient.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + switch (HttpStatus.valueOf(response.code())) + { + case BAD_REQUEST: + case UNAUTHORIZED: + updateToken(); + if (!hasRetried) + { + return getTweets(true); + } + throw new InternalServerErrorException("Could not auth to Twitter after trying once: " + response); + default: + throw new IOException("Error getting Twitter list: " + response); + } + } + + InputStream in = response.body().byteStream(); + Type listType = new TypeToken>() + { + }.getType(); + List statusesResponse = RuneLiteAPI.GSON + .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), listType); + + List items = new ArrayList<>(); + + for (TwitterStatusesResponseItem i : statusesResponse) + { + items.add(new FeedItem(FeedItemType.TWEET, + i.getUser().getProfileImageUrl(), + i.getUser().getScreenName(), + i.getText().replace("\n\n", " ").replaceAll("\n", " "), + "https://twitter.com/" + i.getUser().getScreenName() + "/status/" + i.getId(), + getTimestampFromSnowflake(i.getId()))); + } + + return items; + } + } + + private void updateToken() throws IOException + { + String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); + + Request request = new Request.Builder() + .url(AUTH_URL) + .header("Authorization", "Basic " + encodedCredentials) + .post(new FormBody.Builder().add("grant_type", "client_credentials").build()) + .build(); + + try (Response response = okHttpClient.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Error authing to Twitter: " + response); + } + + InputStream in = response.body().byteStream(); + TwitterOAuth2TokenResponse tokenResponse = RuneLiteAPI.GSON + .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), TwitterOAuth2TokenResponse.class); + + if (!tokenResponse.getTokenType().equals("bearer")) + { + throw new InternalServerErrorException("Returned token was not a bearer token"); + } + + if (tokenResponse.getToken() == null) + { + throw new InternalServerErrorException("Returned token was null"); + } + + token = tokenResponse.getToken(); + } + } + + /** + * Extracts the UTC timestamp from a Twitter snowflake as per + * https://github.com/client9/snowflake2time/blob/master/python/snowflake.py#L24 + */ + private long getTimestampFromSnowflake(long snowflake) + { + return (snowflake >> 22) + 1288834974657L; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java new file mode 100644 index 0000000000..90b37c5021 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.twitter; + +import lombok.Data; + +@Data +class TwitterStatusesResponseItem +{ + private long id; + private String text; + private TwitterStatusesResponseItemUser user; +} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java new file mode 100644 index 0000000000..94fe9360f9 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Lotto + * 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.feed.twitter; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +@Data +class TwitterStatusesResponseItemUser +{ + @SerializedName("screen_name") + private String screenName; + + @SerializedName("profile_image_url_https") + private String profileImageUrl; +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java new file mode 100644 index 0000000000..509f2bdb70 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2019, Adam + * 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.ge; + +import com.google.gson.Gson; +import java.io.IOException; +import java.time.Instant; +import java.util.Collection; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.ge.GrandExchangeTrade; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import net.runelite.http.service.util.redis.RedisPool; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import redis.clients.jedis.Jedis; + +@RestController +@RequestMapping("/ge") +public class GrandExchangeController +{ + private static final Gson GSON = RuneLiteAPI.GSON; + + private final GrandExchangeService grandExchangeService; + private final AuthFilter authFilter; + private final RedisPool redisPool; + + @Autowired + public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter, RedisPool redisPool) + { + this.grandExchangeService = grandExchangeService; + this.authFilter = authFilter; + this.redisPool = redisPool; + } + + @PostMapping + public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException + { + SessionEntry session = null; + if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) + { + session = authFilter.handle(request, response); + if (session == null) + { + // error is set here on the response, so we shouldn't continue + return; + } + } + Integer userId = session == null ? null : session.getUser(); + + // We don't keep track of pending trades in the web UI, so only add cancelled or completed trades + if (userId != null && + grandExchangeTrade.getQty() > 0 && + (grandExchangeTrade.isCancel() || grandExchangeTrade.getQty() == grandExchangeTrade.getTotal())) + { + grandExchangeService.add(userId, grandExchangeTrade); + } + + Trade trade = new Trade(); + trade.setBuy(grandExchangeTrade.isBuy()); + trade.setCancel(grandExchangeTrade.isCancel()); + trade.setLogin(grandExchangeTrade.isLogin()); + trade.setItemId(grandExchangeTrade.getItemId()); + trade.setQty(grandExchangeTrade.getQty()); + trade.setDqty(grandExchangeTrade.getDqty()); + trade.setTotal(grandExchangeTrade.getTotal()); + trade.setSpent(grandExchangeTrade.getDspent()); + trade.setOffer(grandExchangeTrade.getOffer()); + trade.setSlot(grandExchangeTrade.getSlot()); + trade.setTime((int) (System.currentTimeMillis() / 1000L)); + trade.setMachineId(request.getHeader(RuneLiteAPI.RUNELITE_MACHINEID)); + trade.setUserId(userId); + trade.setIp(request.getHeader("X-Forwarded-For")); + trade.setUa(request.getHeader("User-Agent")); + trade.setWorldType(grandExchangeTrade.getWorldType()); + trade.setSeq(grandExchangeTrade.getSeq()); + Instant resetTime = grandExchangeTrade.getResetTime(); + trade.setResetTime(resetTime == null ? 0L : resetTime.getEpochSecond()); + + String json = GSON.toJson(trade); + try (Jedis jedis = redisPool.getResource()) + { + jedis.publish("ge", json); + } + } + + @GetMapping + public Collection get(HttpServletRequest request, HttpServletResponse response, + @RequestParam(required = false, defaultValue = "1024") int limit, + @RequestParam(required = false, defaultValue = "0") int offset) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + + if (session == null) + { + return null; + } + + return grandExchangeService.get(session.getUser(), limit, offset).stream() + .map(GrandExchangeController::convert) + .collect(Collectors.toList()); + } + + private static GrandExchangeTradeHistory convert(TradeEntry tradeEntry) + { + GrandExchangeTradeHistory grandExchangeTrade = new GrandExchangeTradeHistory(); + grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY); + grandExchangeTrade.setItemId(tradeEntry.getItem()); + grandExchangeTrade.setQuantity(tradeEntry.getQuantity()); + grandExchangeTrade.setPrice(tradeEntry.getPrice()); + grandExchangeTrade.setTime(tradeEntry.getTime()); + return grandExchangeTrade; + } + + @DeleteMapping + public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException + { + SessionEntry session = authFilter.handle(request, response); + + if (session == null) + { + return; + } + + grandExchangeService.delete(session.getUser()); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java new file mode 100644 index 0000000000..227d5e1159 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2019, Adam + * 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.ge; + +import java.util.Collection; +import net.runelite.http.api.ge.GrandExchangeTrade; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.Sql2o; + +@Service +public class GrandExchangeService +{ + private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" + + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + + " `user` int(11) NOT NULL,\n" + + " `action` enum('BUY','SELL') NOT NULL,\n" + + " `item` int(11) NOT NULL,\n" + + " `quantity` int(11) NOT NULL,\n" + + " `price` int(11) NOT NULL,\n" + + " `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + + " PRIMARY KEY (`id`),\n" + + " KEY `user_time` (`user`, `time`),\n" + + " KEY `time` (`time`),\n" + + " CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" + + ") ENGINE=InnoDB;"; + + private final Sql2o sql2o; + private final int historyDays; + + @Autowired + public GrandExchangeService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + @Value("${runelite.ge.history}") int historyDays + ) + { + this.sql2o = sql2o; + this.historyDays = historyDays; + + // Ensure necessary tables exist + try (Connection con = sql2o.open()) + { + con.createQuery(CREATE_TABLE).executeUpdate(); + } + } + + public void add(int userId, GrandExchangeTrade grandExchangeTrade) + { + try (Connection con = sql2o.open()) + { + con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," + + " :action, :item, :quantity, :price)") + .addParameter("user", userId) + .addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL") + .addParameter("item", grandExchangeTrade.getItemId()) + .addParameter("quantity", grandExchangeTrade.getQty()) + .addParameter("price", grandExchangeTrade.getSpent() / grandExchangeTrade.getQty()) + .executeUpdate(); + } + } + + public Collection get(int userId, int limit, int offset) + { + try (Connection con = sql2o.open()) + { + return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset") + .addParameter("user", userId) + .addParameter("limit", limit) + .addParameter("offset", offset) + .executeAndFetch(TradeEntry.class); + } + } + + public void delete(int userId) + { + try (Connection con = sql2o.open()) + { + con.createQuery("delete from ge_trades where user = :user") + .addParameter("user", userId) + .executeUpdate(); + } + } + + @Scheduled(fixedDelay = 60 * 60 * 1000) + public void expire() + { + try (Connection con = sql2o.open()) + { + con.createQuery("delete from ge_trades where time < current_timestamp - interval " + historyDays + " day") + .executeUpdate(); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java new file mode 100644 index 0000000000..c45f5acf4f --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Adam + * 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.ge; + +import java.time.Instant; +import lombok.Data; + +@Data +class GrandExchangeTradeHistory +{ + private boolean buy; + private int itemId; + private int quantity; + private int price; + private Instant time; +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/Trade.java b/http-service/src/main/java/net/runelite/http/service/ge/Trade.java new file mode 100644 index 0000000000..7ad01f322a --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/Trade.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, Adam + * 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.ge; + +import lombok.Data; +import net.runelite.http.api.worlds.WorldType; + +@Data +class Trade +{ + private boolean buy; + private boolean cancel; + private boolean login; + private int itemId; + private int qty; + private int dqty; + private int total; + private int spent; + private int offer; + private int slot; + private int time; + private String machineId; + private Integer userId; + private String ip; + private String ua; + private WorldType worldType; + private int seq; + private long resetTime; +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java new file mode 100644 index 0000000000..fcc96d615f --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019, Adam + * 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.ge; + +enum TradeAction +{ + BUY, + SELL; +} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java new file mode 100644 index 0000000000..bca3869811 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, Adam + * 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.ge; + +import java.time.Instant; +import lombok.Data; + +@Data +class TradeEntry +{ + private int id; + private int user; + private TradeAction action; + private int item; + private int quantity; + private int price; + private Instant time; +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemController.java b/http-service/src/main/java/net/runelite/http/service/item/ItemController.java new file mode 100644 index 0000000000..e546344d4c --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/ItemController.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017-2018, Adam + * 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.item; + +import com.google.common.base.Suppliers; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import net.runelite.http.api.item.ItemPrice; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.CacheControl; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/item") +public class ItemController +{ + private static class MemoizedPrices + { + final ItemPrice[] prices; + final String hash; + + MemoizedPrices(ItemPrice[] prices) + { + this.prices = prices; + + Hasher hasher = Hashing.sha256().newHasher(); + for (ItemPrice itemPrice : prices) + { + hasher.putInt(itemPrice.getId()).putInt(itemPrice.getPrice()); + } + HashCode code = hasher.hash(); + hash = code.toString(); + } + } + + private final ItemService itemService; + private final int priceCache; + + private final Supplier memoizedPrices; + + @Autowired + public ItemController( + ItemService itemService, + @Value("${runelite.price.cache}") int priceCache + ) + { + this.itemService = itemService; + this.priceCache = priceCache; + + memoizedPrices = Suppliers.memoizeWithExpiration(() -> new MemoizedPrices(itemService.fetchPrices().stream() + .map(priceEntry -> + { + ItemPrice itemPrice = new ItemPrice(); + itemPrice.setId(priceEntry.getItem()); + itemPrice.setName(priceEntry.getName()); + itemPrice.setPrice(priceEntry.getPrice()); + itemPrice.setWikiPrice(computeWikiPrice(priceEntry)); + return itemPrice; + }) + .toArray(ItemPrice[]::new)), priceCache, TimeUnit.MINUTES); + } + + private static int computeWikiPrice(PriceEntry priceEntry) + { + if (priceEntry.getLow() > 0 && priceEntry.getHigh() > 0) + { + return (priceEntry.getLow() + priceEntry.getHigh()) / 2; + } + else + { + return Math.max(priceEntry.getLow(), priceEntry.getHigh()); + } + } + + @GetMapping("/prices") + public ResponseEntity prices() + { + MemoizedPrices memorizedPrices = this.memoizedPrices.get(); + return ResponseEntity.ok() + .eTag(memorizedPrices.hash) + .cacheControl(CacheControl.maxAge(priceCache, TimeUnit.MINUTES).cachePublic()) + .body(memorizedPrices.prices); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java b/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java new file mode 100644 index 0000000000..41186b1608 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017, Adam + * 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.item; + +import java.time.Instant; +import lombok.Data; +import net.runelite.http.api.item.ItemType; + +@Data +public class ItemEntry +{ + private int id; + private String name; + private String description; + private ItemType type; + private Instant timestamp; +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemService.java b/http-service/src/main/java/net/runelite/http/service/item/ItemService.java new file mode 100644 index 0000000000..bc3f03e70c --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/ItemService.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2017-2018, Adam + * 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.item; + +import com.google.gson.JsonParseException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Random; +import lombok.extern.slf4j.Slf4j; +import net.runelite.cache.definitions.ItemDefinition; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.item.ItemType; +import net.runelite.http.service.cache.CacheService; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.Query; +import org.sql2o.Sql2o; + +@Service +@Slf4j +public class ItemService +{ + private static final String CREATE_ITEMS = "CREATE TABLE IF NOT EXISTS `items` (\n" + + " `id` int(11) NOT NULL,\n" + + " `name` tinytext NOT NULL,\n" + + " `description` tinytext NOT NULL,\n" + + " `type` enum('DEFAULT') NOT NULL,\n" + + " `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" + + " PRIMARY KEY (`id`)\n" + + ") ENGINE=InnoDB"; + + private static final String CREATE_PRICES = "CREATE TABLE IF NOT EXISTS `prices` (\n" + + " `item` int(11) NOT NULL,\n" + + " `price` int(11) NOT NULL,\n" + + " `time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" + + " `fetched_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" + + " UNIQUE KEY `item_time` (`item`,`time`),\n" + + " KEY `item_fetched_time` (`item`,`fetched_time`)\n" + + ") ENGINE=InnoDB"; + + private final Sql2o sql2o; + private final CacheService cacheService; + private final OkHttpClient okHttpClient; + private final HttpUrl itemUrl; + private final HttpUrl priceUrl; + + private int[] tradeableItems; + private final Random random = new Random(); + + @Autowired + public ItemService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + CacheService cacheService, + OkHttpClient okHttpClient, + @Value("${runelite.item.itemUrl}") String itemUrl, + @Value("${runelite.item.priceUrl}") String priceUrl + ) + { + this.sql2o = sql2o; + this.cacheService = cacheService; + this.okHttpClient = okHttpClient; + this.itemUrl = HttpUrl.get(itemUrl); + this.priceUrl = HttpUrl.get(priceUrl); + + try (Connection con = sql2o.open()) + { + con.createQuery(CREATE_ITEMS) + .executeUpdate(); + + con.createQuery(CREATE_PRICES) + .executeUpdate(); + } + } + + public ItemEntry getItem(int itemId) + { + try (Connection con = sql2o.open()) + { + return con.createQuery("select id, name, description, type from items where id = :id") + .addParameter("id", itemId) + .executeAndFetchFirst(ItemEntry.class); + } + } + + public ItemEntry fetchItem(int itemId) + { + try + { + RSItem rsItem = fetchRSItem(itemId); + + try (Connection con = sql2o.open()) + { + con.createQuery("insert into items (id, name, description, type) values (:id," + + " :name, :description, :type) ON DUPLICATE KEY UPDATE name = :name," + + " description = :description, type = :type") + .addParameter("id", rsItem.getId()) + .addParameter("name", rsItem.getName()) + .addParameter("description", rsItem.getDescription()) + .addParameter("type", rsItem.getType()) + .executeUpdate(); + } + + ItemEntry item = new ItemEntry(); + item.setId(itemId); + item.setName(rsItem.getName()); + item.setDescription(rsItem.getDescription()); + item.setType(ItemType.of(rsItem.getType())); + return item; + } + catch (IOException ex) + { + log.warn("unable to fetch item {}", itemId, ex); + return null; + } + } + + private void fetchPrice(int itemId) + { + RSPrices rsprice; + try + { + rsprice = fetchRSPrices(itemId); + } + catch (IOException ex) + { + log.warn("unable to fetch price for item {}", itemId, ex); + return; + } + + try (Connection con = sql2o.beginTransaction()) + { + Instant now = Instant.now(); + + Query query = con.createQuery("insert into prices (item, price, time, fetched_time) values (:item, :price, :time, :fetched_time) " + + "ON DUPLICATE KEY UPDATE price = VALUES(price), fetched_time = VALUES(fetched_time)"); + + for (Map.Entry entry : rsprice.getDaily().entrySet()) + { + long ts = entry.getKey(); // ms since epoch + int price = entry.getValue(); // gp + + Instant time = Instant.ofEpochMilli(ts); + + query + .addParameter("item", itemId) + .addParameter("price", price) + .addParameter("time", time) + .addParameter("fetched_time", now) + .addToBatch(); + } + + query.executeBatch(); + con.commit(false); + } + } + + public List fetchPrices() + { + try (Connection con = sql2o.beginTransaction()) + { + Query query = con.createQuery("select t2.item, t3.name, t2.time, prices.price, prices.fetched_time, t4.high, t4.low" + + " from (select t1.item as item, max(t1.time) as time from prices t1 group by item) t2" + + " join prices on t2.item=prices.item and t2.time=prices.time" + + " join items t3 on t2.item=t3.id" + + " join wiki_prices t4 on t2.item=t4.item_id"); + return query.executeAndFetch(PriceEntry.class); + } + } + + private RSItem fetchRSItem(int itemId) throws IOException + { + HttpUrl itemUrl = this.itemUrl + .newBuilder() + .addQueryParameter("item", "" + itemId) + .build(); + + Request request = new Request.Builder() + .url(itemUrl) + .build(); + + RSItemResponse itemResponse = fetchJson(request, RSItemResponse.class); + return itemResponse.getItem(); + + } + + private RSPrices fetchRSPrices(int itemId) throws IOException + { + HttpUrl priceUrl = this.priceUrl + .newBuilder() + .addPathSegment(itemId + ".json") + .build(); + + Request request = new Request.Builder() + .url(priceUrl) + .build(); + + return fetchJson(request, RSPrices.class); + } + + private T fetchJson(Request request, Class clazz) throws IOException + { + try (Response response = okHttpClient.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Unsuccessful http response: " + response); + } + + InputStream in = response.body().byteStream(); + return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), clazz); + } + catch (JsonParseException ex) + { + throw new IOException(ex); + } + } + + @Scheduled(fixedDelay = 20_000) + public void crawlPrices() + { + if (tradeableItems == null || tradeableItems.length == 0) + { + return; + } + + int idx = random.nextInt(tradeableItems.length); + int id = tradeableItems[idx]; + + log.debug("Fetching price for {}", id); + + // check if the item name or description has changed + fetchItem(id); + fetchPrice(id); + } + + @Scheduled(fixedDelay = 1_800_000) // 30 minutes + public void reloadItems() throws IOException + { + List items = cacheService.getItems(); + if (items.isEmpty()) + { + log.warn("Failed to load any items from cache, item price updating will be disabled"); + } + + tradeableItems = items.stream() + .filter(ItemDefinition::isTradeable) + .mapToInt(ItemDefinition::getId) + .toArray(); + + log.debug("Loaded {} tradeable items", tradeableItems.length); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java b/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java new file mode 100644 index 0000000000..4d29d7e98d --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, Adam + * 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.item; + +import java.time.Instant; +import lombok.Data; + +@Data +class PriceEntry +{ + private int item; + private String name; + private int price; + private Instant time; + private Instant fetched_time; + private int high; + private int low; +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItem.java b/http-service/src/main/java/net/runelite/http/service/item/RSItem.java new file mode 100644 index 0000000000..17e3352f6d --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/RSItem.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, Adam + * 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.item; + +import lombok.Data; + +@Data +class RSItem +{ + private int id; + private String name; + private String description; + private String type; +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java b/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java new file mode 100644 index 0000000000..c0305cd552 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017, Adam + * 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.item; + +import lombok.Data; + +@Data +class RSItemResponse +{ + private RSItem item; +} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java b/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java new file mode 100644 index 0000000000..04331d753e --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, Adam + * 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.item; + +import java.util.Map; +import lombok.Data; + +@Data +public class RSPrices +{ + /** + * unix time in ms to price in gp + */ + private Map daily; +} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java new file mode 100644 index 0000000000..4cb3375154 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, Adam + * 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.loottracker; + +import java.time.Instant; +import lombok.Data; +import net.runelite.http.api.loottracker.LootRecordType; + +@Data +class LootResult +{ + private int killId; + private Instant first_time; + private Instant last_time; + private LootRecordType type; + private String eventId; + private int amount; + private int itemId; + private int itemQuantity; +} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java new file mode 100644 index 0000000000..ef39ac0d50 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018, TheStonedTurtle + * Copyright (c) 2018, Adam + * 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.loottracker; + +import com.google.api.client.http.HttpStatusCodes; +import com.google.gson.Gson; +import java.io.IOException; +import java.util.Collection; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.loottracker.LootAggregate; +import net.runelite.http.api.loottracker.LootRecord; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import net.runelite.http.service.util.redis.RedisPool; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import redis.clients.jedis.Jedis; + +@RestController +@RequestMapping("/loottracker") +public class LootTrackerController +{ + private static final Gson GSON = RuneLiteAPI.GSON; + + @Autowired + private LootTrackerService service; + + @Autowired + private RedisPool redisPool; + + @Autowired + private AuthFilter auth; + + @RequestMapping(method = RequestMethod.POST) + public void storeLootRecord(HttpServletRequest request, HttpServletResponse response, @RequestBody Collection records) throws IOException + { + SessionEntry session = null; + if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) + { + session = auth.handle(request, response); + if (session == null) + { + // error is set here on the response, so we shouldn't continue + return; + } + } + Integer userId = session == null ? null : session.getUser(); + + if (userId != null) + { + service.store(records, userId); + } + response.setStatus(HttpStatusCodes.STATUS_CODE_OK); + + try (Jedis jedis = redisPool.getResource()) + { + jedis.publish("drops", GSON.toJson(records)); + } + } + + @GetMapping + public Collection getLootAggregate(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException + { + SessionEntry e = auth.handle(request, response); + if (e == null) + { + response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); + return null; + } + + return service.get(e.getUser(), count, start); + } + + @DeleteMapping + public void deleteLoot(HttpServletRequest request, HttpServletResponse response, + @RequestParam(required = false) String eventId) throws IOException + { + SessionEntry e = auth.handle(request, response); + if (e == null) + { + response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); + return; + } + + service.delete(e.getUser(), eventId); + } +} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java new file mode 100644 index 0000000000..4836afd97d --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2018, TheStonedTurtle + * Copyright (c) 2018, Adam + * 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.loottracker; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.http.api.loottracker.GameItem; +import net.runelite.http.api.loottracker.LootAggregate; +import net.runelite.http.api.loottracker.LootRecord; +import net.runelite.http.api.loottracker.LootRecordType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.Query; +import org.sql2o.Sql2o; + +@Service +public class LootTrackerService +{ + private static final String CREATE_KILLS = "CREATE TABLE IF NOT EXISTS `loottracker_kills` (\n" + + " `id` bigint NOT NULL AUTO_INCREMENT,\n" + + " `first_time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + + " `last_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n" + + " `accountId` int(11) NOT NULL,\n" + + " `type` enum('NPC','PLAYER','EVENT','PICKPOCKET','UNKNOWN') NOT NULL,\n" + + " `eventId` varchar(255) NOT NULL,\n" + + " `amount` int(11) NOT NULL,\n" + + " PRIMARY KEY (`id`),\n" + + " FOREIGN KEY (accountId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,\n" + + " INDEX idx_acc_lasttime (`accountId` ,`last_time`),\n" + + " UNIQUE INDEX idx_acc_type_event (`accountId`, `type`, `eventId`),\n" + + " INDEX idx_time (last_time)" + + ") ENGINE=InnoDB;"; + + private static final String CREATE_DROPS = "CREATE TABLE IF NOT EXISTS `loottracker_drops` (\n" + + " `killId` bigint NOT NULL,\n" + + " `itemId` int(11) NOT NULL,\n" + + " `itemQuantity` int(11) NOT NULL,\n" + + " UNIQUE INDEX idx_kill_item (`killId`, `itemId`),\n" + + " FOREIGN KEY (killId) REFERENCES loottracker_kills(id) ON DELETE CASCADE\n" + + ") ENGINE=InnoDB;\n"; + + // Queries for inserting kills + private static final String INSERT_KILL_QUERY = "INSERT INTO loottracker_kills (accountId, type, eventId, amount) VALUES (:accountId, :type, :eventId, :kills) ON DUPLICATE KEY UPDATE amount = amount + :kills"; + private static final String INSERT_DROP_QUERY = "INSERT INTO loottracker_drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity) ON DUPLICATE KEY UPDATE itemQuantity = itemQuantity + :itemQuantity"; + + private static final String SELECT_LOOT_QUERY = "SELECT killId,first_time,last_time,type,eventId,amount,itemId,itemQuantity FROM loottracker_kills JOIN loottracker_drops ON loottracker_drops.killId = loottracker_kills.id WHERE accountId = :accountId ORDER BY last_time DESC LIMIT :limit OFFSET :offset"; + + private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM loottracker_kills WHERE accountId = :accountId"; + private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM loottracker_kills WHERE accountId = :accountId AND eventId = :eventId"; + + private final Sql2o sql2o; + private final int historyDays; + + @Autowired + public LootTrackerService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + @Value("${runelite.loottracker.history}") int historyDays + ) + { + this.sql2o = sql2o; + this.historyDays = historyDays; + + // Ensure necessary tables exist + try (Connection con = sql2o.open()) + { + con.createQuery(CREATE_KILLS).executeUpdate(); + con.createQuery(CREATE_DROPS).executeUpdate(); + } + } + + @RequiredArgsConstructor + @EqualsAndHashCode(exclude = {"kills", "drops"}) + @Getter + private static class AggregateLootRecord + { + final LootRecordType type; + final String eventId; + int kills = 0; + Map drops = new HashMap<>(); + } + + @RequiredArgsConstructor + @EqualsAndHashCode(exclude = "qty") + @Getter + private static class AggregateDrop + { + final int id; + int qty = 0; + } + + private static Collection aggregate(Collection records) + { + Map combinedRecords = new HashMap<>(); + for (LootRecord record : records) + { + AggregateLootRecord r = new AggregateLootRecord(record.getType(), record.getEventId()); + r = combinedRecords.computeIfAbsent(r, (k) -> k); + ++r.kills; + + // Combine drops + for (GameItem gameItem : record.getDrops()) + { + AggregateDrop cd = new AggregateDrop(gameItem.getId()); + cd = r.drops.computeIfAbsent(cd, (k) -> k); + cd.qty += gameItem.getQty(); + } + } + return combinedRecords.values(); + } + + /** + * Store LootRecord + * + * @param records LootRecords to store + * @param accountId runelite account id to tie data too + */ + public void store(Collection records, int accountId) + { + Collection combinedRecords = aggregate(records); + + try (Connection con = sql2o.beginTransaction()) + { + Query killQuery = con.createQuery(INSERT_KILL_QUERY, true); + Query insertDrop = con.createQuery(INSERT_DROP_QUERY); + + for (AggregateLootRecord record : combinedRecords) + { + killQuery + .addParameter("accountId", accountId) + .addParameter("type", record.getType()) + .addParameter("eventId", record.getEventId()) + .addParameter("kills", record.getKills()) + .executeUpdate(); + Object[] keys = con.getKeys(); + + for (AggregateDrop drop : record.getDrops().values()) + { + insertDrop + .addParameter("killId", keys[0]) + .addParameter("itemId", drop.getId()) + .addParameter("itemQuantity", drop.getQty()) + .addToBatch(); + } + + insertDrop.executeBatch(); + } + + con.commit(false); + } + } + + public Collection get(int accountId, int limit, int offset) + { + List lootResults; + + try (Connection con = sql2o.open()) + { + lootResults = con.createQuery(SELECT_LOOT_QUERY) + .addParameter("accountId", accountId) + .addParameter("limit", limit) + .addParameter("offset", offset) + .executeAndFetch(LootResult.class); + } + + LootResult current = null; + List lootRecords = new ArrayList<>(); + List gameItems = new ArrayList<>(); + + for (LootResult lootResult : lootResults) + { + if (current == null || current.getKillId() != lootResult.getKillId()) + { + if (!gameItems.isEmpty()) + { + LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); + lootRecords.add(lootRecord); + + gameItems = new ArrayList<>(); + } + + current = lootResult; + } + + GameItem gameItem = new GameItem(lootResult.getItemId(), lootResult.getItemQuantity()); + gameItems.add(gameItem); + } + + if (!gameItems.isEmpty()) + { + LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); + lootRecords.add(lootRecord); + } + + return lootRecords; + } + + public void delete(int accountId, String eventId) + { + try (Connection con = sql2o.open()) + { + if (eventId == null) + { + con.createQuery(DELETE_LOOT_ACCOUNT) + .addParameter("accountId", accountId) + .executeUpdate(); + } + else + { + con.createQuery(DELETE_LOOT_ACCOUNT_EVENTID) + .addParameter("accountId", accountId) + .addParameter("eventId", eventId) + .executeUpdate(); + } + } + } + + @Scheduled(fixedDelay = 60 * 60 * 1000) + public void expire() + { + try (Connection con = sql2o.open()) + { + con.createQuery("delete from loottracker_kills where last_time < current_timestamp() - interval " + historyDays + " day") + .executeUpdate(); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java b/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java new file mode 100644 index 0000000000..f9f424dca7 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020, Adam + * 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.pluginhub; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; +import javax.servlet.http.HttpServletRequest; +import net.runelite.http.service.util.redis.RedisPool; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.CacheControl; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import redis.clients.jedis.Jedis; + +@RestController +@RequestMapping("/pluginhub") +public class PluginHubController +{ + @Value("${pluginhub.stats.days:7}") + private int days; + + @Value("${pluginhub.stats.expire:90}") + private int expireDays; + + @Autowired + private RedisPool redisPool; + + private final Cache pluginCache = CacheBuilder.newBuilder() + .maximumSize(512L) + .build(); + + private Map pluginCounts = Collections.emptyMap(); + + @GetMapping + public ResponseEntity> get() + { + if (pluginCounts.isEmpty()) + { + return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) + .cacheControl(CacheControl.noCache()) + .build(); + } + + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES).cachePublic()) + .body(pluginCounts); + } + + @PostMapping + public void submit(HttpServletRequest request, @RequestBody String[] plugins) + { + final String date = Instant.now().atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE); + final String ip = request.getHeader("X-Forwarded-For"); + try (Jedis jedis = redisPool.getResource()) + { + for (String plugin : plugins) + { + if (!plugin.matches("[a-z0-9-]+")) + { + continue; + } + + jedis.pfadd("pluginhub." + plugin + "." + date, ip); + + if (pluginCache.getIfPresent(plugin) == null) + { + jedis.sadd("pluginhub.plugins", plugin); + // additionally set the ttl on the hyperloglog since it might be a new key + jedis.expire("pluginhub." + plugin + "." + date, (int) (Duration.ofDays(expireDays).toMillis() / 1000L)); + + pluginCache.put(plugin, plugin); + } + } + } + } + + @Scheduled(fixedDelay = 1_800_000, initialDelay = 30_000) // 30 minutes with 30 second initial delay + public void rebuildCounts() + { + Map counts = new HashMap<>(); + try (Jedis jedis = redisPool.getResource()) + { + Set plugins = jedis.smembers("pluginhub.plugins"); + ZonedDateTime time = Instant.now().atZone(ZoneOffset.UTC); + + for (String plugin : plugins) + { + // When called with multiple keys, pfcount returns the approximated + // cardinality of the union of the HyperLogLogs. We use this to determine + // the number of users in the last N days. + String[] keys = IntStream.range(0, days - 1) + .mapToObj(time::minusDays) + .map(zdt -> "pluginhub." + plugin + "." + zdt.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .toArray(String[]::new); + long cnt = jedis.pfcount(keys); + if (cnt > 0) + { + counts.put(plugin, cnt); + } + } + } + pluginCounts = counts; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java b/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java new file mode 100644 index 0000000000..785ad00266 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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 HOLDER 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.util; + +import java.sql.Timestamp; +import java.time.Instant; +import org.sql2o.converters.Converter; +import org.sql2o.converters.ConverterException; + +public class InstantConverter implements Converter +{ + @Override + public Instant convert(Object val) throws ConverterException + { + Timestamp ts = (Timestamp) val; + return ts.toInstant(); + } + + @Override + public Object toDatabaseParam(Instant val) + { + return Timestamp.from(val); + } + +} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java new file mode 100644 index 0000000000..62adc5b6fc --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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 HOLDER 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.util.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class InternalServerErrorException extends RuntimeException +{ + public InternalServerErrorException(String message) + { + super(message); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java new file mode 100644 index 0000000000..83e04ceca6 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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 HOLDER 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.util.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not found") +public class NotFoundException extends RuntimeException +{ + +} diff --git a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java b/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java new file mode 100644 index 0000000000..c0d4a65a29 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019, Adam + * 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.util.redis; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import redis.clients.jedis.Jedis; + +@Component +@Slf4j +public class RedisPool +{ + private final String redisHost; + private final BlockingQueue queue; + + RedisPool(@Value("${redis.pool.size:10}") int queueSize, @Value("${redis.host:localhost}") String redisHost) + { + this.redisHost = redisHost; + + queue = new ArrayBlockingQueue<>(queueSize); + for (int i = 0; i < queueSize; ++i) + { + Jedis jedis = new PooledJedis(redisHost); + queue.offer(jedis); + } + } + + public Jedis getResource() + { + Jedis jedis; + try + { + jedis = queue.poll(1, TimeUnit.SECONDS); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + if (jedis == null) + { + throw new RuntimeException("Unable to acquire connection from pool, timeout"); + } + return jedis; + } + + class PooledJedis extends Jedis + { + PooledJedis(String host) + { + super(host); + } + + @Override + public void close() + { + if (!getClient().isBroken()) + { + queue.offer(this); + return; + } + + log.warn("jedis client is broken, creating new client"); + + try + { + super.close(); + } + catch (Exception e) + { + log.warn("unable to close broken jedis", e); + } + + queue.offer(new PooledJedis(redisHost)); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java b/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java new file mode 100644 index 0000000000..0723063b02 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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 HOLDER 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.wiki; + +import java.util.Map; +import lombok.Data; + +@Data +class PriceResult +{ + @Data + static class Item + { + private int high; + private int highTime; + private int low; + private int lowTime; + } + + private Map data; +} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java b/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java new file mode 100644 index 0000000000..2e32fc1808 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 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 HOLDER 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.wiki; + +import com.google.gson.JsonSyntaxException; +import java.io.IOException; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.sql2o.Connection; +import org.sql2o.Query; +import org.sql2o.Sql2o; + +@Service +@Slf4j +public class WikiPriceService +{ + private static final String CREATE = "CREATE TABLE IF NOT EXISTS `wiki_prices` (\n" + + " `item_id` int(11) NOT NULL,\n" + + " `high` int(11) NOT NULL,\n" + + " `highTime` int(11) NOT NULL,\n" + + " `low` int(11) NOT NULL,\n" + + " `lowTime` int(11) NOT NULL,\n" + + " `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" + + " PRIMARY KEY (`item_id`)\n" + + ") ENGINE=InnoDB;"; + + private final Sql2o sql2o; + private final OkHttpClient okHttpClient; + private final HttpUrl wikiUrl; + + @Autowired + public WikiPriceService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + OkHttpClient okHttpClient, + @Value("${runelite.wiki.url}") String url + ) + { + this.sql2o = sql2o; + this.okHttpClient = okHttpClient; + this.wikiUrl = HttpUrl.get(url); + + try (Connection con = sql2o.open()) + { + con.createQuery(CREATE).executeUpdate(); + } + } + + @Scheduled(initialDelay = 1000 * 5, fixedDelayString = "${runelite.wiki.poll.ms}") + private void updateDatabase() + { + try + { + PriceResult summary = getPrices(); + + try (Connection con = sql2o.beginTransaction()) + { + Query query = con.createQuery("INSERT INTO wiki_prices (item_id, high, highTime, low, lowTime)" + + " VALUES (:itemId, :high, :highTime, :low, :lowTime)" + + " ON DUPLICATE KEY UPDATE high = VALUES(high), highTime = VALUES(highTime)," + + " low = VALUES(low), lowTime = VALUES(lowTime)"); + + for (Map.Entry entry : summary.getData().entrySet()) + { + Integer itemId = entry.getKey(); + PriceResult.Item item = entry.getValue(); + + query + .addParameter("itemId", itemId) + .addParameter("high", item.getHigh()) + .addParameter("highTime", item.getHighTime()) + .addParameter("low", item.getLow()) + .addParameter("lowTime", item.getLowTime()) + .addToBatch(); + } + + query.executeBatch(); + con.commit(false); + } + } + catch (IOException e) + { + log.warn("Error while updating wiki prices", e); + } + } + + private PriceResult getPrices() throws IOException + { + Request request = new Request.Builder() + .url(wikiUrl) + .header("User-Agent", "RuneLite") + .build(); + + try (Response responseOk = okHttpClient.newCall(request).execute()) + { + if (!responseOk.isSuccessful()) + { + throw new IOException("Error retrieving prices: " + responseOk.message()); + } + + return RuneLiteAPI.GSON.fromJson(responseOk.body().string(), PriceResult.class); + } + catch (JsonSyntaxException ex) + { + throw new IOException(ex); + } + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java b/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java new file mode 100644 index 0000000000..642cd0440a --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, Lotto + * 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.worlds; + +import net.runelite.http.api.worlds.WorldType; + +enum ServiceWorldType +{ + MEMBERS(WorldType.MEMBERS, 1), + PVP(WorldType.PVP, 1 << 2), + BOUNTY(WorldType.BOUNTY, 1 << 5), + SKILL_TOTAL(WorldType.SKILL_TOTAL, 1 << 7), + HIGH_RISK(WorldType.HIGH_RISK, 1 << 10), + LAST_MAN_STANDING(WorldType.LAST_MAN_STANDING, 1 << 14), + NOSAVE_MODE(WorldType.NOSAVE_MODE, 1 << 25), + TOURNAMENT(WorldType.TOURNAMENT, 1 << 26), + DEADMAN(WorldType.DEADMAN, 1 << 29), + SEASONAL(WorldType.SEASONAL, 1 << 30); + + private final WorldType apiType; + private final int mask; + + ServiceWorldType(WorldType apiType, int mask) + { + this.apiType = apiType; + this.mask = mask; + } + + public WorldType getApiType() + { + return apiType; + } + + public int getMask() + { + return mask; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java new file mode 100644 index 0000000000..a0c71af52c --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018, Adam + * 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.worlds; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import net.runelite.http.api.worlds.WorldResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.CacheControl; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/worlds") +public class WorldController +{ + @Autowired + private WorldsService worldsService; + + private WorldResult worldResult; + + @GetMapping + public ResponseEntity listWorlds() + { + if (worldResult == null) + { + return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) + .cacheControl(CacheControl.noCache()) + .build(); + } + + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) + .body(worldResult); + } + + @Scheduled(fixedDelay = 60_000L) + public void refreshWorlds() throws IOException + { + worldResult = worldsService.getWorlds(); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java new file mode 100644 index 0000000000..1f8debe7eb --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2017, Adam + * 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.worlds; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldResult; +import net.runelite.http.api.worlds.WorldType; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class WorldsService +{ + private final OkHttpClient okHttpClient; + private final HttpUrl url; + + @Autowired + public WorldsService( + OkHttpClient okHttpClient, + @Value("${runelite.worlds.url}") String url + ) + { + this.okHttpClient = okHttpClient; + this.url = HttpUrl.get(url); + } + + public WorldResult getWorlds() throws IOException + { + Request okrequest = new Request.Builder() + .url(url) + .build(); + + byte[] b; + + try (Response okresponse = okHttpClient.newCall(okrequest).execute()) + { + b = okresponse.body().bytes(); + } + + List worlds = new ArrayList<>(); + ByteBuffer buf = ByteBuffer.wrap(b); + + int length = buf.getInt(); + buf.limit(length + 4); + + int num = buf.getShort() & 0xFFFF; + + for (int i = 0; i < num; ++i) + { + final World.WorldBuilder worldBuilder = World.builder() + .id(buf.getShort() & 0xFFFF) + .types(getTypes(buf.getInt())) + .address(readString(buf)) + .activity(readString(buf)) + .location(buf.get() & 0xFF) + .players(buf.getShort()); + + worlds.add(worldBuilder.build()); + } + + WorldResult result = new WorldResult(); + result.setWorlds(worlds); + return result; + } + + private static EnumSet getTypes(int mask) + { + EnumSet types = EnumSet.noneOf(WorldType.class); + + for (ServiceWorldType type : ServiceWorldType.values()) + { + if ((mask & type.getMask()) != 0) + { + types.add(type.getApiType()); + } + } + + return types; + } + + private static String readString(ByteBuffer buf) + { + byte b; + StringBuilder sb = new StringBuilder(); + + for (;;) + { + b = buf.get(); + + if (b == 0) + { + break; + } + + sb.append((char) b); + } + + return sb.toString(); + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java new file mode 100644 index 0000000000..7c5f2bb5b0 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Adam + * 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.xtea; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +class XteaCache +{ + private int region; + private int key1; + private int key2; + private int key3; + private int key4; +} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java new file mode 100644 index 0000000000..3868acb8c6 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018, Adam + * 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.xtea; + +import java.util.List; +import java.util.stream.Collectors; +import net.runelite.http.api.xtea.XteaKey; +import net.runelite.http.api.xtea.XteaRequest; +import net.runelite.http.service.util.exception.NotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +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; + +@RestController +@RequestMapping("/xtea") +public class XteaController +{ + @Autowired + private XteaService xteaService; + + @RequestMapping(method = POST) + public void submit(@RequestBody XteaRequest xteaRequest) + { + xteaService.submit(xteaRequest); + } + + @GetMapping + public List get() + { + return xteaService.get().stream() + .map(XteaController::entryToKey) + .collect(Collectors.toList()); + } + + @GetMapping("/{region}") + public XteaKey getRegion(@PathVariable int region) + { + XteaEntry xteaRegion = xteaService.getRegion(region); + if (xteaRegion == null) + { + throw new NotFoundException(); + } + + return entryToKey(xteaRegion); + } + + private static XteaKey entryToKey(XteaEntry xe) + { + XteaKey xteaKey = new XteaKey(); + xteaKey.setRegion(xe.getRegion()); + xteaKey.setKeys(new int[] + { + xe.getKey1(), + xe.getKey2(), + xe.getKey3(), + xe.getKey4() + }); + return xteaKey; + } +} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java new file mode 100644 index 0000000000..c5e60b1119 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, Adam + * 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.xtea; + +import java.time.Instant; +import lombok.Data; + +@Data +class XteaEntry +{ + private int region; + private Instant time; + private int rev; + private int key1; + private int key2; + private int key3; + private int key4; +} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java new file mode 100644 index 0000000000..8a5d651b05 --- /dev/null +++ b/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017, Adam + * 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.xtea; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import java.io.IOException; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import net.runelite.cache.IndexType; +import net.runelite.cache.fs.Container; +import net.runelite.cache.util.Djb2; +import net.runelite.http.api.xtea.XteaKey; +import net.runelite.http.api.xtea.XteaRequest; +import net.runelite.http.service.cache.CacheService; +import net.runelite.http.service.cache.beans.ArchiveEntry; +import net.runelite.http.service.cache.beans.CacheEntry; +import net.runelite.http.service.util.exception.InternalServerErrorException; +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.Query; +import org.sql2o.Sql2o; + +@Service +@Slf4j +public class XteaService +{ + private static final String CREATE_SQL = "CREATE TABLE IF NOT EXISTS `xtea` (\n" + + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + + " `region` int(11) NOT NULL,\n" + + " `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" + + " `rev` int(11) NOT NULL,\n" + + " `key1` int(11) NOT NULL,\n" + + " `key2` int(11) NOT NULL,\n" + + " `key3` int(11) NOT NULL,\n" + + " `key4` int(11) NOT NULL,\n" + + " PRIMARY KEY (`id`),\n" + + " KEY `region` (`region`,`time`)\n" + + ") ENGINE=InnoDB"; + + private final Sql2o sql2o; + private final CacheService cacheService; + + private final Cache keyCache = CacheBuilder.newBuilder() + .maximumSize(1024) + .build(); + + @Autowired + public XteaService( + @Qualifier("Runelite SQL2O") Sql2o sql2o, + CacheService cacheService + ) + { + this.sql2o = sql2o; + this.cacheService = cacheService; + + try (Connection con = sql2o.beginTransaction()) + { + con.createQuery(CREATE_SQL) + .executeUpdate(); + } + } + + private XteaEntry findLatestXtea(Connection con, int region) + { + return con.createQuery("select region, time, key1, key2, key3, key4 from xtea " + + "where region = :region " + + "order by time desc " + + "limit 1") + .addParameter("region", region) + .executeAndFetchFirst(XteaEntry.class); + } + + public void submit(XteaRequest xteaRequest) + { + boolean cached = true; + for (XteaKey key : xteaRequest.getKeys()) + { + int region = key.getRegion(); + int[] keys = key.getKeys(); + + if (keys.length != 4) + { + throw new IllegalArgumentException("Key length must be 4"); + } + + XteaCache xteaCache = keyCache.getIfPresent(region); + if (xteaCache == null + || xteaCache.getKey1() != keys[0] + || xteaCache.getKey2() != keys[1] + || xteaCache.getKey3() != keys[2] + || xteaCache.getKey4() != keys[3]) + { + cached = false; + keyCache.put(region, new XteaCache(region, keys[0], keys[1], keys[2], keys[3])); + } + } + + if (cached) + { + return; + } + + try (Connection con = sql2o.beginTransaction()) + { + CacheEntry cache = cacheService.findMostRecent(); + + if (cache == null) + { + throw new InternalServerErrorException("No most recent cache"); + } + + Query query = null; + + for (XteaKey key : xteaRequest.getKeys()) + { + int region = key.getRegion(); + int[] keys = key.getKeys(); + + XteaEntry xteaEntry = findLatestXtea(con, region); + + // already have these? + if (xteaEntry != null + && xteaEntry.getKey1() == keys[0] + && xteaEntry.getKey2() == keys[1] + && xteaEntry.getKey3() == keys[2] + && xteaEntry.getKey4() == keys[3]) + { + continue; + } + + ArchiveEntry archiveEntry = archiveForRegion(cache, region); + if (archiveEntry == null) + { + // the client sends 0,0,0,0 for non-existent regions, just ignore them + continue; + } + + if (!checkKeys(archiveEntry, keys)) + { + continue; + } + + if (query == null) + { + query = con.createQuery("insert into xtea (region, rev, key1, key2, key3, key4) " + + "values (:region, :rev, :key1, :key2, :key3, :key4)"); + } + + query.addParameter("region", region) + .addParameter("rev", xteaRequest.getRevision()) + .addParameter("key1", keys[0]) + .addParameter("key2", keys[1]) + .addParameter("key3", keys[2]) + .addParameter("key4", keys[3]) + .addToBatch(); + + log.debug("Inserted keys for {}: {}, {}, {}, {}", region, keys[0], keys[1], keys[2], keys[3]); + } + + if (query != null) + { + query.executeBatch(); + con.commit(false); + } + } + } + + public List get() + { + try (Connection con = sql2o.open()) + { + return con.createQuery( + "select t1.region, t2.time, t2.rev, t2.key1, t2.key2, t2.key3, t2.key4 from " + + "(select region,max(id) as id from xtea group by region) t1 " + + "join xtea t2 on t1.id = t2.id") + .executeAndFetch(XteaEntry.class); + } + } + + public XteaEntry getRegion(int region) + { + try (Connection con = sql2o.open()) + { + return con.createQuery("select region, time, rev, key1, key2, key3, key4 from xtea " + + "where region = :region order by time desc limit 1") + .addParameter("region", region) + .executeAndFetchFirst(XteaEntry.class); + } + } + + private ArchiveEntry archiveForRegion(CacheEntry cache, int regionId) + { + int x = regionId >>> 8; + int y = regionId & 0xFF; + + String archiveName = new StringBuilder() + .append('l') + .append(x) + .append('_') + .append(y) + .toString(); + int archiveNameHash = Djb2.hash(archiveName); + + return cacheService.findArchiveForTypeAndName(cache, IndexType.MAPS, archiveNameHash); + } + + private boolean checkKeys(ArchiveEntry archiveEntry, int[] keys) + { + byte[] data = cacheService.getArchive(archiveEntry); + if (data == null) + { + throw new InternalServerErrorException("Unable to get archive data for archive " + archiveEntry.getArchiveId()); + } + + try + { + Container.decompress(data, keys); + return true; + } + catch (IOException ex) + { + return false; + } + } +} diff --git a/http-service/src/main/resources/application-dev.yaml b/http-service/src/main/resources/application-dev.yaml new file mode 100644 index 0000000000..2b24790c51 --- /dev/null +++ b/http-service/src/main/resources/application-dev.yaml @@ -0,0 +1,29 @@ +# Enable debug logging +debug: true +logging.level.net.runelite: DEBUG + +# Development data sources +datasource: + runelite: + jndiName: + driverClassName: org.mariadb.jdbc.Driver + type: org.mariadb.jdbc.MariaDbDataSource + url: jdbc:mariadb://localhost:3306/runelite + username: runelite + password: runelite + runelite-cache: + jndiName: + driverClassName: org.mariadb.jdbc.Driver + type: org.mariadb.jdbc.MariaDbDataSource + url: jdbc:mariadb://localhost:3306/cache + username: runelite + password: runelite + +# Development mongo +mongo: + jndiName: + host: mongodb://localhost:27017 + +# Development oauth callback (without proxy) +oauth: + callback: http://localhost:8080/account/callback diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml new file mode 100644 index 0000000000..7431545cbb --- /dev/null +++ b/http-service/src/main/resources/application.yaml @@ -0,0 +1,61 @@ +datasource: + runelite: + jndiName: java:comp/env/jdbc/runelite + runelite-cache: + jndiName: java:comp/env/jdbc/runelite-cache2 + +# By default Spring tries to register the datasource as an MXBean, +# so if multiple apis are deployed on one web container with +# shared datasource it tries to register it multiples times and +# fails when starting the 2nd api +spring.jmx.enabled: false + +# Google OAuth client +oauth: + client-id: + client-secret: + callback: https://api.runelite.net/oauth/ + +# Minio client storage for cache +minio: + endpoint: http://localhost:9000 + accesskey: AM54M27O4WZK65N6F8IP + secretkey: /PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP + bucket: runelite + +# Redis client +redis: + pool.size: 10 + host: tcp://localhost:6379 + +mongo: + jndiName: java:comp/env/mongodb/runelite + database: runelite + +runelite: + version: @project.version@ + commit: @git.commit.id.abbrev@ + dirty: @git.dirty@ + # Twitter client for feed + twitter: + consumerkey: + secretkey: + listid: 1185897074786742273 + ge: + history: 90 # days + loottracker: + history: 90 # days + wiki: + poll.ms: 300000 # 5 minutes + url: https://prices.runescape.wiki/api/v1/osrs/latest + price: + cache: 30 # minutes + feed: + rssUrl: https://runelite.net/atom.xml + worlds: + url: http://www.runescape.com/g=oldscape/slr.ws?order=LPWM + osrsnews: + rssUrl: https://services.runescape.com/m=news/latest_news.rss?oldschool=true + item: + itemUrl: https://services.runescape.com/m=itemdb_oldschool/api/catalogue/detail.json + priceUrl: https://services.runescape.com/m=itemdb_oldschool/api/graph \ No newline at end of file diff --git a/http-service/src/main/templates/markdown.hbs b/http-service/src/main/templates/markdown.hbs new file mode 100644 index 0000000000..1beacd052a --- /dev/null +++ b/http-service/src/main/templates/markdown.hbs @@ -0,0 +1,110 @@ +{{#info}} +# {{title}} +{{join schemes " | "}}://{{host}}{{basePath}} + +{{description}} + +{{#contact}} +[**Contact the developer**](mailto:{{email}}) +{{/contact}} + +**Version** {{version}} + +{{#if termsOfService}} +[**Terms of Service**]({{termsOfService}}) +{{/if}} + +{{/info}} + +{{#if consumes}}__Consumes:__ {{join consumes ", "}}{{/if}} + +{{#if produces}}__Produces:__ {{join produces ", "}}{{/if}} + +{{#if securityDefinitions}} +# Security Definitions +{{> security}} +{{/if}} + +
+Table Of Contents +[toc] +
+ +# APIs + +{{#each paths}} +## {{@key}} +{{#this}} +{{#get}} +### GET +{{> operation}} +{{/get}} + +{{#put}} +### PUT +{{> operation}} +{{/put}} + +{{#post}} +### POST + +{{> operation}} + +{{/post}} + +{{#delete}} +### DELETE +{{> operation}} +{{/delete}} + +{{#option}} +### OPTION +{{> operation}} +{{/option}} + +{{#patch}} +### PATCH +{{> operation}} +{{/patch}} + +{{#head}} +### HEAD +{{> operation}} +{{/head}} + +{{/this}} +{{/each}} + +# Definitions +{{#each definitions}} +## {{@key}} + + + + + + + + + + {{#each this.properties}} + + + + + + + + {{/each}} +
nametyperequireddescriptionexample
{{@key}} + {{#ifeq type "array"}} + {{#items.$ref}} + {{type}}[{{basename items.$ref}}] + {{/items.$ref}} + {{^items.$ref}}{{type}}[{{items.type}}]{{/items.$ref}} + {{else}} + {{#$ref}}{{basename $ref}}{{/$ref}} + {{^$ref}}{{type}}{{#format}} ({{format}}){{/format}}{{/$ref}} + {{/ifeq}} + {{#required}}required{{/required}}{{^required}}optional{{/required}}{{#description}}{{{description}}}{{/description}}{{^description}}-{{/description}}{{example}}
+{{/each}} diff --git a/http-service/src/main/templates/operation.hbs b/http-service/src/main/templates/operation.hbs new file mode 100644 index 0000000000..f7015850b8 --- /dev/null +++ b/http-service/src/main/templates/operation.hbs @@ -0,0 +1,71 @@ +{{#deprecated}}-deprecated-{{/deprecated}} +{{summary}} + +{{description}} + +{{#if externalDocs.url}}{{externalDocs.description}}. [See external documents for more details]({{externalDocs.url}}) +{{/if}} + +{{#if security}} +#### Security +{{/if}} + +{{#security}} +{{#each this}} +* {{@key}} +{{#this}} * {{this}} +{{/this}} +{{/each}} +{{/security}} + +#### Request + +{{#if consumes}}__Content-Type:__ {{join consumes ", "}}{{/if}} + +##### Parameters +{{#if parameters}} + + + + + + + + + +{{/if}} + +{{#parameters}} + + + + + + +{{#ifeq in "body"}} + +{{else}} + {{#ifeq type "array"}} + + {{else}} + + {{/ifeq}} +{{/ifeq}} + +{{/parameters}} +{{#if parameters}} +
NameLocated inRequiredDescriptionDefaultSchema
{{name}}{{in}}{{#if required}}yes{{else}}no{{/if}}{{description}}{{#if pattern}} (**Pattern**: `{{pattern}}`){{/if}} - + {{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}} + {{#schema.$ref}}{{basename schema.$ref}} {{/schema.$ref}} + Array[{{items.type}}] ({{collectionFormat}}){{type}} {{#format}}({{format}}){{/format}}
+{{/if}} + + +#### Response + +{{#if produces}}__Content-Type:__ {{join produces ", "}}{{/if}} + +| Status Code | Reason | Response Model | +|-------------|-------------|----------------| +{{#each responses}}| {{@key}} | {{description}} | {{#schema.$ref}}{{basename schema.$ref}}{{/schema.$ref}}{{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}}{{^schema}} - {{/schema}}| +{{/each}} diff --git a/http-service/src/main/templates/security.hbs b/http-service/src/main/templates/security.hbs new file mode 100644 index 0000000000..04f86e8380 --- /dev/null +++ b/http-service/src/main/templates/security.hbs @@ -0,0 +1,88 @@ +{{#each securityDefinitions}} +### {{@key}} +{{#this}} +{{#ifeq type "oauth2"}} + + + + + +{{#if description}} + + + + +{{/if}} +{{#if authorizationUrl}} + + + + +{{/if}} +{{#if flow}} + + + + +{{/if}} +{{#if tokenUrl}} + + + + +{{/if}} +{{#if scopes}} + + +{{#each scopes}} + + + + +{{/each}} + +{{/if}} +
type{{type}}
description{{description}}
authorizationUrl{{authorizationUrl}}
flow{{flow}}
tokenUrl{{tokenUrl}}
scopes{{@key}}{{this}}
+{{/ifeq}} +{{#ifeq type "apiKey"}} + + + + + +{{#if description}} + + + + +{{/if}} +{{#if name}} + + + + +{{/if}} +{{#if in}} + + + + +{{/if}} +
type{{type}}
description{{description}}
name{{name}}
in{{in}}
+{{/ifeq}} +{{#ifeq type "basic"}} + + + + + +{{#if description}} + + + + +{{/if}} +
type{{type}}
description{{description}}
+{{/ifeq}} +{{/this}} +{{/each}} \ No newline at end of file diff --git a/http-service/src/main/templates/template.html.hbs b/http-service/src/main/templates/template.html.hbs new file mode 100644 index 0000000000..da587c2cc4 --- /dev/null +++ b/http-service/src/main/templates/template.html.hbs @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + {{info.title}} {{info.version}} + + + + + \ No newline at end of file diff --git a/http-service/src/main/webapp/WEB-INF/web.xml b/http-service/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..0b07dbb973 --- /dev/null +++ b/http-service/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,32 @@ + + + + RuneLite API + \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java new file mode 100644 index 0000000000..27320f3f72 --- /dev/null +++ b/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019, Adam + * 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.config; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@WebMvcTest(ConfigController.class) +@ActiveProfiles("test") +public class ConfigControllerTest +{ + @Autowired + private MockMvc mockMvc; + + @MockBean + private ConfigService configService; + + @MockBean + private AuthFilter authFilter; + + @Before + public void before() throws IOException + { + when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) + .thenReturn(mock(SessionEntry.class)); + + when(configService.setKey(anyInt(), anyString(), anyString())).thenReturn(true); + } + + @Test + public void testSetKey() throws Exception + { + mockMvc.perform(put("/config/key") + .content("value") + .contentType(MediaType.TEXT_PLAIN)) + .andExpect(status().isOk()); + + verify(configService).setKey(anyInt(), eq("key"), eq("value")); + } +} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java new file mode 100644 index 0000000000..a08a9a7160 --- /dev/null +++ b/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019, Adam + * 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.config; + +import com.google.common.collect.ImmutableMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class ConfigServiceTest +{ + @Test + public void testParseJsonString() + { + assertEquals(1, ConfigService.parseJsonString("1")); + assertEquals(3.14, ConfigService.parseJsonString("3.14")); + assertEquals(1L << 32, ConfigService.parseJsonString("4294967296")); + assertEquals("test", ConfigService.parseJsonString("test")); + assertEquals("test", ConfigService.parseJsonString("\"test\"")); + assertEquals(ImmutableMap.of("key", "value"), ConfigService.parseJsonString("{\"key\": \"value\"}")); + } + + @Test + public void testValidateJson() + { + assertTrue(ConfigService.validateJson("1")); + assertTrue(ConfigService.validateJson("3.14")); + assertTrue(ConfigService.validateJson("test")); + assertTrue(ConfigService.validateJson("\"test\"")); + assertTrue(ConfigService.validateJson("key:value")); + assertTrue(ConfigService.validateJson("{\"key\": \"value\"}")); + assertTrue(ConfigService.validateJson("\n")); + } + + @Test + public void testMaybeJson() + { + assertFalse(ConfigService.isMaybeJson("string")); + assertFalse(ConfigService.isMaybeJson("string with spaces")); + + assertTrue(ConfigService.isMaybeJson("true")); + assertTrue(ConfigService.isMaybeJson("false")); + assertTrue(ConfigService.isMaybeJson("1")); + assertTrue(ConfigService.isMaybeJson("1.2")); + assertTrue(ConfigService.isMaybeJson("\"quote\"")); + assertTrue(ConfigService.isMaybeJson("{\"key\": \"value\"}")); + assertTrue(ConfigService.isMaybeJson("[42]")); + } +} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java new file mode 100644 index 0000000000..68e64270d6 --- /dev/null +++ b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019, Adam + * 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.loottracker; + +import java.io.IOException; +import java.time.Instant; +import java.time.temporal.ChronoField; +import java.util.Collections; +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.loottracker.GameItem; +import net.runelite.http.api.loottracker.LootRecord; +import net.runelite.http.api.loottracker.LootRecordType; +import net.runelite.http.service.account.AuthFilter; +import net.runelite.http.service.account.beans.SessionEntry; +import net.runelite.http.service.util.redis.RedisPool; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import redis.clients.jedis.Jedis; + +@RunWith(SpringRunner.class) +@WebMvcTest(LootTrackerController.class) +@ActiveProfiles("test") +public class LootTrackerControllerTest +{ + @Autowired + private MockMvc mockMvc; + + @MockBean + private LootTrackerService lootTrackerService; + + @MockBean + private AuthFilter authFilter; + + @MockBean + private RedisPool redisPool; + + @Before + public void before() throws IOException + { + when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) + .thenReturn(mock(SessionEntry.class)); + + when(redisPool.getResource()).thenReturn(mock(Jedis.class)); + } + + @Test + public void storeLootRecord() throws Exception + { + LootRecord lootRecord = new LootRecord(); + lootRecord.setType(LootRecordType.NPC); + lootRecord.setTime(Instant.now().with(ChronoField.NANO_OF_SECOND, 0)); + lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1))); + + String data = RuneLiteAPI.GSON.toJson(Collections.singletonList(lootRecord)); + mockMvc.perform(post("/loottracker") + .header(RuneLiteAPI.RUNELITE_AUTH, UUID.nameUUIDFromBytes("test".getBytes())) + .content(data) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + verify(lootTrackerService).store(eq(Collections.singletonList(lootRecord)), anyInt()); + } +} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java new file mode 100644 index 0000000000..b6275d7c48 --- /dev/null +++ b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, Adam + * 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.worlds; + +import java.io.IOException; +import java.io.InputStream; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldResult; +import net.runelite.http.api.worlds.WorldType; +import okhttp3.OkHttpClient; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okio.Buffer; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sql2o.tools.IOUtils; + +public class WorldsServiceTest +{ + @Rule + public final MockWebServer server = new MockWebServer(); + + @Before + public void before() throws IOException + { + InputStream in = WorldsServiceTest.class.getResourceAsStream("worldlist"); + byte[] worldData = IOUtils.toByteArray(in); + + Buffer buffer = new Buffer(); + buffer.write(worldData); + + server.enqueue(new MockResponse().setBody(buffer)); + } + + @Test + public void testListWorlds() throws Exception + { + WorldsService worlds = new WorldsService(new OkHttpClient(), server.url("/").toString()); + + WorldResult worldResult = worlds.getWorlds(); + assertEquals(82, worldResult.getWorlds().size()); + + World world = worldResult.findWorld(385); + assertNotNull(world); + assertTrue(world.getTypes().contains(WorldType.SKILL_TOTAL)); + + for (World testWorld : worldResult.getWorlds()) + { + assertNotNull("Missing a region in WorldRegion enum", testWorld.getRegion()); + } + } + +} diff --git a/http-service/src/test/resources/application-test.yaml b/http-service/src/test/resources/application-test.yaml new file mode 100644 index 0000000000..3a8e416a54 --- /dev/null +++ b/http-service/src/test/resources/application-test.yaml @@ -0,0 +1,21 @@ +# Use in-memory database for tests +datasource: + runelite: + jndiName: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:runelite + runelite-cache: + jndiName: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:cache + runelite-tracker: + jndiName: + driverClassName: org.h2.Driver + type: org.h2.jdbcx.JdbcDataSource + url: jdbc:h2:mem:xptracker + +mongo: + jndiName: + host: mongodb://localhost:27017 \ No newline at end of file diff --git a/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist b/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist new file mode 100644 index 0000000000000000000000000000000000000000..1d1360e5795d066b068e095cf2a033a504405ad6 GIT binary patch literal 5000 zcmeHKOK%%h6uu{Nt&HNnr;&XfUL@?A&0Xv2`>KbrNjykW>2xs2%({goUE2ojRl+UsP2YF3kRF>f)3pl!mq&wAvxSj*vi<` zL+jfJeGeWY1bdoC8M!GddJqr^AHcJOR^c?>rfy383=~o`EgbG-%g){BFW?y(jytE( z4^`J~%Z8WuXg~ztgnJ0Z;z}$8;g*g%lgkR9g4r$CbK^cTzJkXHugooe2$gZDT;KJ# z5d9785>A!3$~+oBz{>`Iajg@H&p1F21Jocycp5{fJHd`3fGmV+CeBADvbNG8Q=gAg+81nq!QO^DM%tc zH84YRq~rOT1m2nR1XRk~LWtMl z2?8qTYY^fMxR-z|?j4iUn{bAJO8M>y@ir_|5ZBq9v=3&$j#M`;+($4^Kz81CLVOIX z1XRx3&dih&0dYfNN^lGwCz$dW(8M2bzu9)u-NWLb!G;%fdpdSwciSv#@4%DfT!$yP zy1S%QDC@Z54Bq;|-nLCR)x1LhZ{@=TRN|n~^~Azc4`7oJ9Bu?UG(mg|W^`uNI=ou5 zV}1u~1XSjxXa=61?0Kqh-a8QA!y^>W{gDj_Pwfn+1K_|vg{*8_w7Fr@Z4pEK3@ao= zi5q7TSJ7xN?r_2eTlg3smkZiQ>aTDSse5UI%lt;=mP-)7LxqI1c!!s9`_+D14&VOS z7COW1M get() throws IOException { HttpUrl url = apiBase.newBuilder() - .addPathSegment("xtea") - .build(); + .addPathSegment("xtea") + .build(); Request request = new Request.Builder() - .url(url) - .build(); + .url(url) + .build(); try (Response response = client.newCall(request).execute()) { @@ -125,13 +124,13 @@ public class XteaClient public XteaKey get(int region) throws IOException { HttpUrl url = apiBase.newBuilder() - .addPathSegment("xtea") - .addPathSegment(Integer.toString(region)) - .build(); + .addPathSegment("xtea") + .addPathSegment(Integer.toString(region)) + .build(); Request request = new Request.Builder() - .url(url) - .build(); + .url(url) + .build(); try (Response response = client.newCall(request).execute()) { From 88af9303a606475e5aa8e7a601e066fa5c59d72a Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 3 Jan 2022 02:56:01 +1100 Subject: [PATCH 21/34] upstream: merge --- buildSrc/src/main/kotlin/Dependencies.kt | 4 +- .../runelite/cache/region/RegionLoader.java | 6 +- .../runelite/cache/util/XteaKeyManager.java | 25 +- config/checkstyle/checkstyle.xml | 8 +- http-api/http-api.gradle.kts | 1 + .../http/api/discord/DiscordClient.java | 6 +- .../net/runelite/http/api/RuneLiteAPI.java | 28 +- .../http/api/ge/GrandExchangeClient.java | 105 +++-- .../api/ws/RuntimeTypeAdapterFactory.java | 12 +- .../runelite/http/api}/xtea/XteaClient.java | 6 +- http-service/pom.xml | 269 ------------- .../service/SpringBootWebApplication.java | 228 ----------- .../service/SpringSchedulingConfigurer.java | 52 --- .../http/service/SpringWebMvcConfigurer.java | 65 ---- .../http/service/account/AccountService.java | 284 -------------- .../http/service/account/AuthFilter.java | 116 ------ .../runelite/http/service/account/State.java | 35 -- .../http/service/account/UserInfo.java | 46 --- .../service/account/beans/SessionEntry.java | 76 ---- .../http/service/account/beans/UserEntry.java | 57 --- .../runelite/http/service/cache/CacheDAO.java | 123 ------ .../http/service/cache/CacheService.java | 254 ------------ .../service/cache/beans/ArchiveEntry.java | 38 -- .../http/service/cache/beans/CacheEntry.java | 36 -- .../http/service/cache/beans/FileEntry.java | 36 -- .../http/service/cache/beans/IndexEntry.java | 36 -- .../http/service/chat/ChatController.java | 274 ------------- .../http/service/chat/ChatService.java | 263 ------------- .../http/service/chat/KillCountKey.java | 34 -- .../http/service/config/ConfigController.java | 134 ------- .../http/service/config/ConfigService.java | 367 ------------------ .../http/service/feed/FeedController.java | 137 ------- .../http/service/feed/blog/BlogService.java | 143 ------- .../feed/osrsnews/OSRSNewsService.java | 143 ------- .../twitter/TwitterOAuth2TokenResponse.java | 38 -- .../service/feed/twitter/TwitterService.java | 183 --------- .../twitter/TwitterStatusesResponseItem.java | 35 -- .../TwitterStatusesResponseItemUser.java | 38 -- .../service/ge/GrandExchangeController.java | 158 -------- .../http/service/ge/GrandExchangeService.java | 119 ------ .../service/ge/GrandExchangeTradeHistory.java | 38 -- .../net/runelite/http/service/ge/Trade.java | 51 --- .../runelite/http/service/ge/TradeAction.java | 31 -- .../runelite/http/service/ge/TradeEntry.java | 40 -- .../http/service/item/ItemController.java | 113 ------ .../runelite/http/service/item/ItemEntry.java | 39 -- .../http/service/item/ItemService.java | 287 -------------- .../http/service/item/PriceEntry.java | 40 -- .../runelite/http/service/item/RSItem.java | 36 -- .../http/service/item/RSItemResponse.java | 33 -- .../runelite/http/service/item/RSPrices.java | 37 -- .../http/service/loottracker/LootResult.java | 42 -- .../loottracker/LootTrackerController.java | 118 ------ .../loottracker/LootTrackerService.java | 259 ------------ .../pluginhub/PluginHubController.java | 144 ------- .../http/service/util/InstantConverter.java | 48 --- .../InternalServerErrorException.java | 38 -- .../util/exception/NotFoundException.java | 35 -- .../http/service/wiki/PriceResult.java | 44 --- .../http/service/wiki/WikiPriceService.java | 140 ------- .../http/service/worlds/ServiceWorldType.java | 60 --- .../http/service/worlds/WorldController.java | 68 ---- .../http/service/worlds/WorldsService.java | 132 ------- .../runelite/http/service/xtea/XteaCache.java | 39 -- .../http/service/xtea/XteaController.java | 86 ---- .../runelite/http/service/xtea/XteaEntry.java | 40 -- .../http/service/xtea/XteaService.java | 250 ------------ .../src/main/resources/application-dev.yaml | 29 -- .../src/main/resources/application.yaml | 61 --- http-service/src/main/templates/markdown.hbs | 110 ------ http-service/src/main/templates/operation.hbs | 71 ---- http-service/src/main/templates/security.hbs | 88 ----- .../src/main/templates/template.html.hbs | 49 --- http-service/src/main/webapp/WEB-INF/web.xml | 32 -- .../service/config/ConfigControllerTest.java | 85 ---- .../service/config/ConfigServiceTest.java | 72 ---- .../LootTrackerControllerTest.java | 104 ----- .../service/worlds/WorldsServiceTest.java | 79 ---- .../src/test/resources/application-test.yaml | 21 - .../runelite/http/service/worlds/worldlist | Bin 5000 -> 0 bytes .../net/runelite/client/SessionClient.java | 2 - .../runelite/client/config/ConfigManager.java | 1 - .../net/runelite/client/game/ItemClient.java | 1 - .../client/plugins/xtea/XteaPlugin.java | 5 +- .../net/runelite/client/rs/ClientLoader.java | 2 +- .../runelite/client/ui/MacOSQuitStrategy.java | 37 -- .../net/runelite/client/runelite.properties | 6 +- 87 files changed, 96 insertions(+), 7065 deletions(-) rename http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java => http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java (50%) rename {runelite-client/src/main/java/net/runelite/client/plugins => http-api/src/main/java/net/runelite/http/api}/xtea/XteaClient.java (94%) delete mode 100644 http-service/pom.xml delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/AccountService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/State.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/UserInfo.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/CacheService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/ChatService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/config/ConfigService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/FeedController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/Trade.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/ItemService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItem.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/item/RSPrices.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java delete mode 100644 http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java delete mode 100644 http-service/src/main/resources/application-dev.yaml delete mode 100644 http-service/src/main/resources/application.yaml delete mode 100644 http-service/src/main/templates/markdown.hbs delete mode 100644 http-service/src/main/templates/operation.hbs delete mode 100644 http-service/src/main/templates/security.hbs delete mode 100644 http-service/src/main/templates/template.html.hbs delete mode 100644 http-service/src/main/webapp/WEB-INF/web.xml delete mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java delete mode 100644 http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java delete mode 100644 http-service/src/test/resources/application-test.yaml delete mode 100644 http-service/src/test/resources/net/runelite/http/service/worlds/worldlist delete mode 100644 runelite-client/src/main/java11/net/runelite/client/ui/MacOSQuitStrategy.java diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index c49cb897aa..0443812cbf 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,9 +25,9 @@ object ProjectVersions { const val launcherVersion = "2.2.0" - const val rlVersion = "1.8.7.1" + const val rlVersion = "1.8.8" - const val openosrsVersion = "4.17.1" + const val openosrsVersion = "4.17.2" const val rsversion = 202 const val cacheversion = 165 diff --git a/cache/src/main/java/net/runelite/cache/region/RegionLoader.java b/cache/src/main/java/net/runelite/cache/region/RegionLoader.java index 2dc3176678..21f4868a9a 100644 --- a/cache/src/main/java/net/runelite/cache/region/RegionLoader.java +++ b/cache/src/main/java/net/runelite/cache/region/RegionLoader.java @@ -60,7 +60,6 @@ public class RegionLoader this.store = store; index = store.getIndex(IndexType.MAPS); keyManager = new XteaKeyManager(); - keyManager.loadKeys(); } public void loadRegions() throws IOException @@ -98,10 +97,9 @@ public class RegionLoader Region region = new Region(i); region.loadTerrain(mapDef); - Integer[] keysTmp = keyManager.getKeys(i); - if (keysTmp != null) + int[] keys = keyManager.getKeys(i); + if (keys != null) { - int[] keys = {keysTmp[0], keysTmp[1], keysTmp[2], keysTmp[3]}; try { data = land.decompress(storage.loadArchive(land), keys); diff --git a/cache/src/main/java/net/runelite/cache/util/XteaKeyManager.java b/cache/src/main/java/net/runelite/cache/util/XteaKeyManager.java index 08ffbfb3ba..b139026c3c 100644 --- a/cache/src/main/java/net/runelite/cache/util/XteaKeyManager.java +++ b/cache/src/main/java/net/runelite/cache/util/XteaKeyManager.java @@ -24,10 +24,15 @@ */ package net.runelite.cache.util; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.xtea.XteaClient; +import net.runelite.http.api.xtea.XteaKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,18 +40,24 @@ public class XteaKeyManager { private static final Logger logger = LoggerFactory.getLogger(XteaKeyManager.class); - private Map keys = new HashMap<>(); + private final Map keys = new HashMap<>(); - public void loadKeys() + public void loadKeys(InputStream in) { - XteaClient xteaClient = new XteaClient(RuneLiteAPI.CLIENT); + // CHECKSTYLE:OFF + List k = new Gson() + .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), new TypeToken>() { }.getType()); + // CHECKSTYLE:ON - keys = null; + for (XteaKey key : k) + { + keys.put(key.getRegion(), key.getKeys()); + } logger.info("Loaded {} keys", keys.size()); } - public Integer[] getKeys(int region) + public int[] getKeys(int region) { return keys.get(region); } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 855e9306fa..85a02c0a69 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> + @@ -60,4 +61,7 @@ + + + diff --git a/http-api/http-api.gradle.kts b/http-api/http-api.gradle.kts index a3997728cc..6acef6f2ef 100644 --- a/http-api/http-api.gradle.kts +++ b/http-api/http-api.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation(group = "com.google.code.gson", name = "gson", version = "2.8.5") implementation(group = "com.google.guava", name = "guava", version = "30.1.1-jre") + implementation(group = "com.google.inject", name = "guice", version = "5.0.1") implementation(group = "com.squareup.okhttp3", name = "okhttp", version = "4.9.1") implementation(group = "org.apache.commons", name = "commons-csv", version = "1.9.0") implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.32") diff --git a/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java b/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java index 47b82fdf55..61383bbbc4 100644 --- a/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java +++ b/http-api/src/main/java/com/openosrs/http/api/discord/DiscordClient.java @@ -29,7 +29,7 @@ package com.openosrs.http.api.discord; import com.google.gson.Gson; import java.io.IOException; import lombok.extern.slf4j.Slf4j; -//import net.runelite.http.api.RuneLiteAPI; +import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -60,7 +60,7 @@ public class DiscordClient log.debug("Attempting to message with {}", discordMessage); - /* RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() + RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() { @Override @@ -95,6 +95,6 @@ public class DiscordClient log.debug("Submitted discord log record"); } } - });*/ + }); } } diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 745474880a..b7c91c2f75 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -51,14 +51,12 @@ public class RuneLiteAPI public static final String RUNELITE_AUTH = "RUNELITE-AUTH"; public static final String RUNELITE_MACHINEID = "RUNELITE-MACHINEID"; - public static final OkHttpClient CLIENT; + public static OkHttpClient CLIENT; public static final Gson GSON; public static final MediaType JSON = MediaType.parse("application/json"); public static String userAgent; private static final String BASE = "https://api.runelite.net"; - private static final String WSBASE = "https://api.runelite.net/ws"; - private static final String STATICBASE = "https://static.runelite.net"; private static final String OPENOSRS_SESSION = "https://session.openosrs.dev"; private static final String OPENOSRS_XTEA = "https://xtea.openosrs.dev"; @@ -140,30 +138,6 @@ public class RuneLiteAPI return HttpUrl.parse(BASE + "/runelite-" + getVersion()); } - public static HttpUrl getStaticBase() - { - final String prop = System.getProperty("runelite.static.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(STATICBASE); - } - - public static HttpUrl getWsEndpoint() - { - final String prop = System.getProperty("runelite.ws.url"); - - if (prop != null && !prop.isEmpty()) - { - return HttpUrl.parse(prop); - } - - return HttpUrl.parse(WSBASE); - } - public static HttpUrl getXteaBase() { return HttpUrl.parse(OPENOSRS_XTEA); diff --git a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java similarity index 50% rename from http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java rename to http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java index c0d4a65a29..1d898ccf27 100644 --- a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java +++ b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeClient.java @@ -22,81 +22,72 @@ * (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.util.redis; +package net.runelite.http.api.ge; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; +import com.google.gson.Gson; +import java.io.IOException; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import redis.clients.jedis.Jedis; +import net.runelite.http.api.RuneLiteAPI; +import static net.runelite.http.api.RuneLiteAPI.JSON; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; -@Component @Slf4j -public class RedisPool +@RequiredArgsConstructor +public class GrandExchangeClient { - private final String redisHost; - private final BlockingQueue queue; + private static final Gson GSON = RuneLiteAPI.GSON; - RedisPool(@Value("${redis.pool.size:10}") int queueSize, @Value("${redis.host:localhost}") String redisHost) + private final OkHttpClient client; + + @Setter + private UUID uuid; + @Setter + private String machineId; + + public void submit(GrandExchangeTrade grandExchangeTrade) { - this.redisHost = redisHost; + final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("ge") + .build(); - queue = new ArrayBlockingQueue<>(queueSize); - for (int i = 0; i < queueSize; ++i) + Request.Builder builder = new Request.Builder(); + if (uuid != null) { - Jedis jedis = new PooledJedis(redisHost); - queue.offer(jedis); + builder.header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString()); } - } - - public Jedis getResource() - { - Jedis jedis; - try + if (machineId != null) { - jedis = queue.poll(1, TimeUnit.SECONDS); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - if (jedis == null) - { - throw new RuntimeException("Unable to acquire connection from pool, timeout"); - } - return jedis; - } - - class PooledJedis extends Jedis - { - PooledJedis(String host) - { - super(host); + builder.header(RuneLiteAPI.RUNELITE_MACHINEID, machineId); } - @Override - public void close() + Request request = builder + .post(RequestBody.create(JSON, GSON.toJson(grandExchangeTrade))) + .url(url) + .build(); + + client.newCall(request).enqueue(new Callback() { - if (!getClient().isBroken()) + @Override + public void onFailure(Call call, IOException e) { - queue.offer(this); - return; + log.debug("unable to submit trade", e); } - log.warn("jedis client is broken, creating new client"); - - try + @Override + public void onResponse(Call call, Response response) { - super.close(); + log.debug("Submitted trade"); + response.close(); } - catch (Exception e) - { - log.warn("unable to close broken jedis", e); - } - - queue.offer(new PooledJedis(redisHost)); - } + }); } } diff --git a/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java index 2819c92ceb..b8afb20cec 100644 --- a/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java +++ b/http-api/src/main/java/net/runelite/http/api/ws/RuntimeTypeAdapterFactory.java @@ -187,9 +187,9 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { } final Map> labelToDelegate - = new LinkedHashMap>(); + = new LinkedHashMap>(); final Map, TypeAdapter> subtypeToDelegate - = new LinkedHashMap, TypeAdapter>(); + = new LinkedHashMap, TypeAdapter>(); for (Map.Entry> entry : labelToSubtype.entrySet()) { TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); labelToDelegate.put(entry.getKey(), delegate); @@ -202,14 +202,14 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); if (labelJsonElement == null) { throw new JsonParseException("cannot deserialize " + baseType - + " because it does not define a field named " + typeFieldName); + + " because it does not define a field named " + typeFieldName); } String label = labelJsonElement.getAsString(); @SuppressWarnings("unchecked") // registration requires that subtype extends T TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); if (delegate == null) { throw new JsonParseException("cannot deserialize " + baseType + " subtype named " - + label + "; did you forget to register a subtype?"); + + label + "; did you forget to register a subtype?"); } return delegate.fromJsonTree(jsonElement); } @@ -221,12 +221,12 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); if (delegate == null) { throw new JsonParseException("cannot serialize " + srcType.getName() - + "; did you forget to register a subtype?"); + + "; did you forget to register a subtype?"); } JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); if (jsonObject.has(typeFieldName)) { throw new JsonParseException("cannot serialize " + srcType.getName() - + " because it already defines a field named " + typeFieldName); + + " because it already defines a field named " + typeFieldName); } JsonObject clone = new JsonObject(); clone.add(typeFieldName, new JsonPrimitive(label)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java b/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java similarity index 94% rename from runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java rename to http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java index d81ea7b6bd..5c9cc34d92 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xtea/XteaClient.java +++ b/http-api/src/main/java/net/runelite/http/api/xtea/XteaClient.java @@ -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.client.plugins.xtea; +package net.runelite.http.api.xtea; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; @@ -36,8 +36,6 @@ import javax.inject.Named; import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import static net.runelite.http.api.RuneLiteAPI.JSON; -import net.runelite.http.api.xtea.XteaKey; -import net.runelite.http.api.xtea.XteaRequest; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -53,7 +51,7 @@ public class XteaClient private final HttpUrl apiBase; @Inject - private XteaClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) + public XteaClient(OkHttpClient client, @Named("runelite.api.base") HttpUrl apiBase) { this.client = client; this.apiBase = apiBase; diff --git a/http-service/pom.xml b/http-service/pom.xml deleted file mode 100644 index d983f9e9da..0000000000 --- a/http-service/pom.xml +++ /dev/null @@ -1,269 +0,0 @@ - - - - 4.0.0 - - - net.runelite - runelite-parent - 1.8.8-SNAPSHOT - - - Web Service - http-service - war - - - 1.5.6.RELEASE - nogit - false - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-devtools - true - - - org.springframework - spring-jdbc - - - - org.projectlombok - lombok - provided - - - - net.runelite - http-api - ${project.version} - - - net.runelite - cache - ${project.version} - - - - org.mariadb.jdbc - mariadb-java-client - 2.2.3 - provided - - - org.sql2o - sql2o - 1.5.4 - - - com.google.guava - guava - - - com.github.scribejava - scribejava-apis - 4.1.0 - - - io.minio - minio - 3.0.6 - - - redis.clients - jedis - 2.10.0 - - - org.apache.commons - commons-pool2 - - - - - org.mongodb - mongodb-driver-sync - 3.10.2 - provided - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.squareup.okhttp3 - mockwebserver - 3.14.9 - test - - - com.h2database - h2 - test - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - - runelite-${project.version} - - - - src/main/resources - true - - - - - - org.apache.maven.plugins - maven-war-plugin - 3.3.1 - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - false - - - - com.github.kongchen - swagger-maven-plugin - 3.1.8 - - - - javax.xml.bind - jaxb-api - 2.3.1 - - - - - - true - - net.runelite - - - https - - api.runelite.net - /runelite-${project.version} - - ${project.parent.name} HTTP API - ${project.version} - ${project.description} - - https://tldrlegal.com/license/bsd-2-clause-license-(freebsd) - BSD 2-Clause "Simplified" - - - ${basedir}/src/main/templates/template.html.hbs - ${project.build.directory}/swagger-ui - ${project.build.directory}/site/api.html - true - json - - - - - - compile - - generate - - - - - - pl.project13.maven - git-commit-id-plugin - 2.2.6 - - - query-git-info - - revision - - - false - false - - true - - - git.commit.id.abbrev - git.dirty - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - 2.7 - - - @ - - false - - - - - diff --git a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java b/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java deleted file mode 100644 index 4c425cb0cf..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringBootWebApplication.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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 ch.qos.logback.classic.LoggerContext; -import com.google.common.base.Strings; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoClients; -import java.io.IOException; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.naming.NamingException; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletException; -import javax.sql.DataSource; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.service.util.InstantConverter; -import okhttp3.Cache; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import org.slf4j.ILoggerFactory; -import org.slf4j.impl.StaticLoggerBinder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.web.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; -import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; -import org.springframework.jndi.JndiTemplate; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.sql2o.Sql2o; -import org.sql2o.converters.Converter; -import org.sql2o.quirks.NoQuirks; - -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) -@EnableScheduling -@Slf4j -public class SpringBootWebApplication extends SpringBootServletInitializer -{ - @Bean - protected ServletContextListener listener(OkHttpClient client) - { - return new ServletContextListener() - { - @Override - public void contextInitialized(ServletContextEvent sce) - { - log.info("RuneLite API started"); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) - { - // Destroy okhttp client - client.dispatcher().executorService().shutdown(); - client.connectionPool().evictAll(); - try - { - Cache cache = client.cache(); - if (cache != null) - { - cache.close(); - } - } - catch (IOException ex) - { - log.warn(null, ex); - } - - log.info("RuneLite API stopped"); - } - - }; - } - - @ConfigurationProperties(prefix = "datasource.runelite") - @Bean("dataSourceRuneLite") - public DataSourceProperties dataSourceProperties() - { - return new DataSourceProperties(); - } - - @ConfigurationProperties(prefix = "datasource.runelite-cache") - @Bean("dataSourceRuneLiteCache") - public DataSourceProperties dataSourcePropertiesCache() - { - return new DataSourceProperties(); - } - - @Bean(value = "runelite", destroyMethod = "") - public DataSource runeliteDataSource(@Qualifier("dataSourceRuneLite") DataSourceProperties dataSourceProperties) - { - return getDataSource(dataSourceProperties); - } - - @Bean(value = "runelite-cache", destroyMethod = "") - public DataSource runeliteCache2DataSource(@Qualifier("dataSourceRuneLiteCache") DataSourceProperties dataSourceProperties) - { - return getDataSource(dataSourceProperties); - } - - @Bean("Runelite SQL2O") - public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource) - { - return createSql2oFromDataSource(dataSource); - } - - @Bean("Runelite Cache SQL2O") - public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource) - { - return createSql2oFromDataSource(dataSource); - } - - @Bean(destroyMethod = "") - public MongoClient mongoClient(@Value("${mongo.host:}") String host, @Value("${mongo.jndiName:}") String jndiName) throws NamingException - { - if (!Strings.isNullOrEmpty(jndiName)) - { - JndiTemplate jndiTemplate = new JndiTemplate(); - return jndiTemplate.lookup(jndiName, MongoClient.class); - } - else if (!Strings.isNullOrEmpty(host)) - { - return MongoClients.create(host); - } - else - { - throw new RuntimeException("Either mongo.host or mongo.jndiName must be set"); - } - } - - private static DataSource getDataSource(DataSourceProperties dataSourceProperties) - { - if (!Strings.isNullOrEmpty(dataSourceProperties.getJndiName())) - { - // Use JNDI provided datasource, which is already configured with pooling - JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); - return dataSourceLookup.getDataSource(dataSourceProperties.getJndiName()); - } - else - { - return dataSourceProperties.initializeDataSourceBuilder().build(); - } - } - - private static Sql2o createSql2oFromDataSource(final DataSource dataSource) - { - final Map converters = new HashMap<>(); - converters.put(Instant.class, new InstantConverter()); - return new Sql2o(dataSource, new NoQuirks(converters)); - } - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) - { - return application.sources(SpringBootWebApplication.class); - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException - { - super.onStartup(servletContext); - ILoggerFactory loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory(); - if (loggerFactory instanceof LoggerContext) - { - LoggerContext loggerContext = (LoggerContext) loggerFactory; - loggerContext.setPackagingDataEnabled(false); - log.debug("Disabling logback packaging data"); - } - } - - @Bean - public OkHttpClient okHttpClient( - @Value("${runelite.version}") String version, - @Value("${runelite.commit}") String commit, - @Value("${runelite.dirty}") boolean dirty - ) - { - final String userAgent = "RuneLite/" + version + "-" + commit + (dirty ? "+" : ""); - return new OkHttpClient.Builder() - .pingInterval(30, TimeUnit.SECONDS) - .addNetworkInterceptor(chain -> - { - Request userAgentRequest = chain.request() - .newBuilder() - .header("User-Agent", userAgent) - .build(); - return chain.proceed(userAgentRequest); - }) - .build(); - } - - public static void main(String[] args) - { - SpringApplication.run(SpringBootWebApplication.class, args); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java deleted file mode 100644 index 6af0895619..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringSchedulingConfigurer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * 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.common.util.concurrent.ThreadFactoryBuilder; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.annotation.SchedulingConfigurer; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.scheduling.config.ScheduledTaskRegistrar; - -@Configuration -public class SpringSchedulingConfigurer implements SchedulingConfigurer -{ - @Override - public void configureTasks(ScheduledTaskRegistrar taskRegistrar) - { - // this is from ScheduledTaskRegistrar.scheduleTasks() but modified to give the scheduler thread a - // recognizable name - ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder() - .setNameFormat("scheduler-%d") - .build() - ); - TaskScheduler scheduler = new ConcurrentTaskScheduler(scheduledExecutorService); - taskRegistrar.setTaskScheduler(scheduler); - } -} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java b/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java deleted file mode 100644 index 704e4f9cb2..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/SpringWebMvcConfigurer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.util.List; -import net.runelite.http.api.RuneLiteAPI; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.GsonHttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; - -@Configuration -@EnableWebMvc -public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter -{ - /** - * Configure .js as application/json to trick Cloudflare into caching json responses - */ - @Override - public void configureContentNegotiation(ContentNegotiationConfigurer configurer) - { - configurer.mediaType("js", MediaType.APPLICATION_JSON); - } - - /** - * Use GSON instead of Jackson for JSON serialization - * @param converters - */ - @Override - public void extendMessageConverters(List> converters) - { - // Could not figure out a better way to force GSON - converters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance); - - GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); - gsonHttpMessageConverter.setGson(RuneLiteAPI.GSON); - converters.add(gsonHttpMessageConverter); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java b/http-service/src/main/java/net/runelite/http/service/account/AccountService.java deleted file mode 100644 index 10a289b927..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/AccountService.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import com.github.scribejava.apis.GoogleApi20; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.model.OAuth2AccessToken; -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.oauth.OAuth20Service; -import com.google.gson.Gson; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -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.account.OAuthResponse; -import net.runelite.http.api.ws.WebsocketGsonFactory; -import net.runelite.http.api.ws.WebsocketMessage; -import net.runelite.http.api.ws.messages.LoginResponse; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.account.beans.UserEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.GetMapping; -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.Sql2o; -import org.sql2o.Sql2oException; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/account") -public class AccountService -{ - private static final Logger logger = LoggerFactory.getLogger(AccountService.class); - - private static final String CREATE_SESSIONS = "CREATE TABLE IF NOT EXISTS `sessions` (\n" - + " `user` int(11) NOT NULL PRIMARY KEY,\n" - + " `uuid` varchar(36) NOT NULL,\n" - + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " UNIQUE KEY `uuid` (`uuid`),\n" - + " KEY `user` (`user`)\n" - + ") ENGINE=InnoDB"; - - private static final String CREATE_USERS = "CREATE TABLE IF NOT EXISTS `users` (\n" - + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" - + " `username` tinytext NOT NULL,\n" - + " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " PRIMARY KEY (`id`),\n" - + " UNIQUE KEY `username` (`username`(64))\n" - + ") ENGINE=InnoDB"; - - private static final String SESSIONS_FK = "ALTER TABLE `sessions`\n" - + " ADD CONSTRAINT `id` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;"; - - private static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email"; - private static final String USERINFO = "https://www.googleapis.com/oauth2/v2/userinfo"; - private static final String RL_REDIR = "https://runelite.net/logged-in"; - - private final Gson gson = RuneLiteAPI.GSON; - private final Gson websocketGson = WebsocketGsonFactory.build(); - - private final Sql2o sql2o; - private final String oauthClientId; - private final String oauthClientSecret; - private final String oauthCallback; - private final String runeliteVersion; - private final AuthFilter auth; - private final RedisPool jedisPool; - - @Autowired - public AccountService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${oauth.client-id}") String oauthClientId, - @Value("${oauth.client-secret}") String oauthClientSecret, - @Value("${oauth.callback}") String oauthCallback, - @Value("${runelite.version}") String runeliteVersion, - AuthFilter auth, - RedisPool jedisPool - ) - { - this.sql2o = sql2o; - this.oauthClientId = oauthClientId; - this.oauthClientSecret = oauthClientSecret; - this.oauthCallback = oauthCallback; - this.runeliteVersion = runeliteVersion; - this.auth = auth; - this.jedisPool = jedisPool; - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_SESSIONS) - .executeUpdate(); - - con.createQuery(CREATE_USERS) - .executeUpdate(); - - try - { - con.createQuery(SESSIONS_FK) - .executeUpdate(); - } - catch (Sql2oException ex) - { - // Ignore, happens when index already exists - } - } - } - - @GetMapping("/login") - public OAuthResponse login(@RequestParam UUID uuid) - { - State state = new State(); - state.setUuid(uuid); - state.setApiVersion(runeliteVersion); - - OAuth20Service service = new ServiceBuilder() - .apiKey(oauthClientId) - .apiSecret(oauthClientSecret) - .scope(SCOPE) - .callback(oauthCallback) - .state(gson.toJson(state)) - .build(GoogleApi20.instance()); - - final Map additionalParams = new HashMap<>(); - additionalParams.put("prompt", "select_account"); - - String authorizationUrl = service.getAuthorizationUrl(additionalParams); - - OAuthResponse lr = new OAuthResponse(); - lr.setOauthUrl(authorizationUrl); - lr.setUid(uuid); - - return lr; - } - - @GetMapping("/callback") - public Object callback( - HttpServletRequest request, - HttpServletResponse response, - @RequestParam(required = false) String error, - @RequestParam String code, - @RequestParam("state") String stateStr - ) throws InterruptedException, ExecutionException, IOException - { - if (error != null) - { - logger.info("Error in oauth callback: {}", error); - return null; - } - - State state = gson.fromJson(stateStr, State.class); - - logger.info("Got authorization code {} for uuid {}", code, state.getUuid()); - - OAuth20Service service = new ServiceBuilder() - .apiKey(oauthClientId) - .apiSecret(oauthClientSecret) - .scope(SCOPE) - .callback(oauthCallback) - .state(gson.toJson(state)) - .build(GoogleApi20.instance()); - - OAuth2AccessToken accessToken = service.getAccessToken(code); - - // Access user info - OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO); - service.signRequest(accessToken, orequest); - - Response oresponse = service.execute(orequest); - - if (oresponse.getCode() / 100 != 2) - { - // Could be a forged result - return null; - } - - UserInfo userInfo = gson.fromJson(oresponse.getBody(), UserInfo.class); - - logger.info("Got user info: {}", userInfo); - - try (Connection con = sql2o.open()) - { - con.createQuery("insert ignore into users (username) values (:username)") - .addParameter("username", userInfo.getEmail()) - .executeUpdate(); - - UserEntry user = con.createQuery("select id from users where username = :username") - .addParameter("username", userInfo.getEmail()) - .executeAndFetchFirst(UserEntry.class); - - if (user == null) - { - logger.warn("Unable to find newly created user session"); - return null; // that's weird - } - - // insert session - con.createQuery("insert ignore into sessions (user, uuid) values (:user, :uuid)") - .addParameter("user", user.getId()) - .addParameter("uuid", state.getUuid().toString()) - .executeUpdate(); - - logger.info("Created session for user {}", userInfo.getEmail()); - } - - response.sendRedirect(RL_REDIR); - - notifySession(state.getUuid(), userInfo.getEmail()); - - return ""; - } - - private void notifySession(UUID uuid, String username) - { - LoginResponse response = new LoginResponse(); - response.setUsername(username); - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class)); - } - } - - @GetMapping("/logout") - public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = auth.handle(request, response); - - if (session == null) - { - return; - } - - auth.invalidate(session.getUuid()); - - try (Connection con = sql2o.open()) - { - con.createQuery("delete from sessions where uuid = :uuid") - .addParameter("uuid", session.getUuid().toString()) - .executeUpdate(); - } - } - - @GetMapping("/session-check") - public void sessionCheck(HttpServletRequest request, HttpServletResponse response) throws IOException - { - auth.handle(request, response); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java b/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java deleted file mode 100644 index d283e71c5c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/AuthFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalNotification; -import java.io.IOException; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -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.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Sql2o; - -@Service -public class AuthFilter -{ - private final Sql2o sql2o; - - private final Cache sessionCache = CacheBuilder.newBuilder() - .maximumSize(10000L) - .expireAfterAccess(30, TimeUnit.MINUTES) - .removalListener(this::removalListener) - .build(); - - @Autowired - public AuthFilter(@Qualifier("Runelite SQL2O") Sql2o sql2o) - { - this.sql2o = sql2o; - } - - public SessionEntry handle(HttpServletRequest request, HttpServletResponse response) throws IOException - { - String runeliteAuth = request.getHeader(RuneLiteAPI.RUNELITE_AUTH); - if (runeliteAuth == null) - { - response.sendError(401, "Access denied"); - return null; - } - - UUID uuid = UUID.fromString(runeliteAuth); - SessionEntry sessionEntry = sessionCache.getIfPresent(uuid); - if (sessionEntry != null) - { - return sessionEntry; - } - - try (Connection con = sql2o.open()) - { - sessionEntry = con.createQuery("select user, uuid, created, last_used as lastUsed from sessions where uuid = :uuid") - .addParameter("uuid", uuid.toString()) - .executeAndFetchFirst(SessionEntry.class); - } - - if (sessionEntry == null) - { - response.sendError(401, "Access denied"); - return null; - } - - sessionCache.put(uuid, sessionEntry); - - return sessionEntry; - } - - private void removalListener(RemovalNotification notification) - { - UUID uuid = notification.getKey(); - Instant now = Instant.now(); - - try (Connection con = sql2o.open()) - { - con.createQuery("update sessions set last_used = :last_used where uuid = :uuid") - .addParameter("last_used", Timestamp.from(now)) - .addParameter("uuid", uuid.toString()) - .executeUpdate(); - } - } - - public void invalidate(UUID uuid) - { - // If we ever run multiple services, may need to publish something here to invalidate... - sessionCache.invalidate(uuid); - } - -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/State.java b/http-service/src/main/java/net/runelite/http/service/account/State.java deleted file mode 100644 index 1412efa11a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/State.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -import java.util.UUID; -import lombok.Data; - -@Data -public class State -{ - private UUID uuid; - private String apiVersion; -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java b/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java deleted file mode 100644 index a1cde03f79..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/UserInfo.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account; - -public class UserInfo -{ - private String email; - - @Override - public String toString() - { - return "UserInfo{" + "email=" + email + '}'; - } - - public String getEmail() - { - return email; - } - - public void setEmail(String email) - { - this.email = email; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java deleted file mode 100644 index ded67c7a45..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/beans/SessionEntry.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account.beans; - -import java.time.Instant; -import java.util.UUID; - -public class SessionEntry -{ - private int user; - private UUID uuid; - private Instant created; - private Instant lastUsed; - - public int getUser() - { - return user; - } - - public void setUser(int user) - { - this.user = user; - } - - public UUID getUuid() - { - return uuid; - } - - public void setUuid(UUID uuid) - { - this.uuid = uuid; - } - - public Instant getCreated() - { - return created; - } - - public void setCreated(Instant created) - { - this.created = created; - } - - public Instant getLastUsed() - { - return lastUsed; - } - - public void setLastUsed(Instant lastUsed) - { - this.lastUsed = lastUsed; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java b/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java deleted file mode 100644 index 83dd4152ac..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/account/beans/UserEntry.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.account.beans; - -public class UserEntry -{ - private int id; - private String username; - - @Override - public String toString() - { - return "UserEntry{" + "id=" + id + ", username=" + username + '}'; - } - - public int getId() - { - return id; - } - - public void setId(int id) - { - this.id = id; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java deleted file mode 100644 index 08282ca38e..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/CacheDAO.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache; - -import java.util.List; -import net.runelite.cache.IndexType; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.cache.beans.FileEntry; -import net.runelite.http.service.cache.beans.IndexEntry; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.ResultSetIterable; - -class CacheDAO -{ - public List listCaches(Connection con) - { - return con.createQuery("select id, revision, date from cache") - .executeAndFetch(CacheEntry.class); - } - - public CacheEntry findMostRecent(Connection con) - { - return con.createQuery("select id, revision, date from cache order by revision desc, date desc limit 1") - .executeAndFetchFirst(CacheEntry.class); - } - - public List findIndexesForCache(Connection con, CacheEntry cache) - { - return con.createQuery("select id, indexId, crc, revision from `index` where cache = :cache") - .addParameter("cache", cache.getId()) - .executeAndFetch(IndexEntry.class); - } - - public IndexEntry findIndexForCache(Connection con, CacheEntry cache, int indexId) - { - return con.createQuery("select id, indexId, crc, revision from `index` " - + "where cache = :id " - + "and indexId = :indexId") - .addParameter("id", cache.getId()) - .addParameter("indexId", indexId) - .executeAndFetchFirst(IndexEntry.class); - } - - public ResultSetIterable findArchivesForIndex(Connection con, IndexEntry indexEntry) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from index_archive " - + "join archive on index_archive.archive = archive.id " - + "where index_archive.index = :id") - .addParameter("id", indexEntry.getId()) - .executeAndFetchLazy(ArchiveEntry.class); - } - - public ArchiveEntry findArchiveForIndex(Connection con, IndexEntry indexEntry, int archiveId) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from index_archive " - + "join archive on index_archive.archive = archive.id " - + "where index_archive.index = :id " - + "and archive.archiveId = :archiveId") - .addParameter("id", indexEntry.getId()) - .addParameter("archiveId", archiveId) - .executeAndFetchFirst(ArchiveEntry.class); - } - - public ArchiveEntry findArchiveByName(Connection con, CacheEntry cache, IndexType index, int nameHash) - { - return con.createQuery("select archive.id, archive.archiveId, archive.nameHash," - + " archive.crc, archive.revision, archive.hash from archive " - + "join index_archive on index_archive.archive = archive.id " - + "join `index` on index.id = index_archive.index " - + "where index.cache = :cacheId " - + "and index.indexId = :indexId " - + "and archive.nameHash = :nameHash " - + "limit 1") - .addParameter("cacheId", cache.getId()) - .addParameter("indexId", index.getNumber()) - .addParameter("nameHash", nameHash) - .executeAndFetchFirst(ArchiveEntry.class); - } - - public ResultSetIterable findFilesForArchive(Connection con, ArchiveEntry archiveEntry) - { - Query findFilesForArchive = con.createQuery("select id, fileId, nameHash from file " - + "where archive = :archive"); - - return findFilesForArchive - .addParameter("archive", archiveEntry.getId()) - .executeAndFetchLazy(FileEntry.class); - } - - public CacheEntry findCache(Connection con, int cacheId) - { - return con.createQuery("select id, revision, date from cache " - + "where id = :cacheId") - .addParameter("cacheId", cacheId) - .executeAndFetchFirst(CacheEntry.class); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java b/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java deleted file mode 100644 index c0b767a68c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/CacheService.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.cache; - -import com.google.common.collect.Iterables; -import com.google.common.io.BaseEncoding; -import com.google.common.io.ByteStreams; -import io.minio.MinioClient; -import io.minio.errors.ErrorResponseException; -import io.minio.errors.InsufficientDataException; -import io.minio.errors.InternalException; -import io.minio.errors.InvalidArgumentException; -import io.minio.errors.InvalidBucketNameException; -import io.minio.errors.InvalidEndpointException; -import io.minio.errors.InvalidPortException; -import io.minio.errors.NoResponseException; -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.ConfigType; -import net.runelite.cache.IndexType; -import net.runelite.cache.definitions.ItemDefinition; -import net.runelite.cache.definitions.loaders.ItemLoader; -import net.runelite.cache.fs.ArchiveFiles; -import net.runelite.cache.fs.Container; -import net.runelite.cache.fs.FSFile; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.cache.beans.FileEntry; -import net.runelite.http.service.cache.beans.IndexEntry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.ResultSetIterable; -import org.sql2o.Sql2o; -import org.xmlpull.v1.XmlPullParserException; - -@Service -@Slf4j -public class CacheService -{ - @Autowired - @Qualifier("Runelite Cache SQL2O") - private Sql2o sql2o; - - @Value("${minio.bucket}") - private String minioBucket; - - private final MinioClient minioClient; - - @Autowired - public CacheService( - @Value("${minio.endpoint}") String minioEndpoint, - @Value("${minio.accesskey}") String accessKey, - @Value("${minio.secretkey}") String secretKey - ) throws InvalidEndpointException, InvalidPortException - { - this.minioClient = new MinioClient(minioEndpoint, accessKey, secretKey); - } - - @Bean - public MinioClient minioClient() - { - return minioClient; - } - - /** - * retrieve archive from storage - * - * @param archiveEntry - * @return - */ - public byte[] getArchive(ArchiveEntry archiveEntry) - { - String hashStr = BaseEncoding.base16().encode(archiveEntry.getHash()); - String path = new StringBuilder() - .append(hashStr, 0, 2) - .append('/') - .append(hashStr.substring(2)) - .toString(); - - try (InputStream in = minioClient.getObject(minioBucket, path)) - { - return ByteStreams.toByteArray(in); - } - catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException - | IOException | InvalidKeyException | NoResponseException | XmlPullParserException - | ErrorResponseException | InternalException | InvalidArgumentException ex) - { - log.warn(null, ex); - return null; - } - } - - public ArchiveFiles getArchiveFiles(ArchiveEntry archiveEntry) throws IOException - { - CacheDAO cacheDao = new CacheDAO(); - - try (Connection con = sql2o.open(); - ResultSetIterable files = cacheDao.findFilesForArchive(con, archiveEntry)) - { - byte[] archiveData = getArchive(archiveEntry); - - if (archiveData == null) - { - return null; - } - - Container result = Container.decompress(archiveData, null); - if (result == null) - { - return null; - } - - byte[] decompressedData = result.data; - - ArchiveFiles archiveFiles = new ArchiveFiles(); - for (FileEntry fileEntry : files) - { - FSFile file = new FSFile(fileEntry.getFileId()); - archiveFiles.addFile(file); - file.setNameHash(fileEntry.getNameHash()); - } - archiveFiles.loadContents(decompressedData); - return archiveFiles; - } - } - - public List listCaches() - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.listCaches(con); - } - } - - public CacheEntry findCache(int cacheId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findCache(con, cacheId); - } - } - - public CacheEntry findMostRecent() - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findMostRecent(con); - } - } - - public List findIndexesForCache(CacheEntry cacheEntry) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findIndexesForCache(con, cacheEntry); - } - } - - public IndexEntry findIndexForCache(CacheEntry cahceEntry, int indexId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findIndexForCache(con, cahceEntry, indexId); - } - } - - public List findArchivesForIndex(IndexEntry indexEntry) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - ResultSetIterable archiveEntries = cacheDao.findArchivesForIndex(con, indexEntry); - List archives = new ArrayList<>(); - Iterables.addAll(archives, archiveEntries); - return archives; - } - } - - public ArchiveEntry findArchiveForIndex(IndexEntry indexEntry, int archiveId) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findArchiveForIndex(con, indexEntry, archiveId); - } - } - - public ArchiveEntry findArchiveForTypeAndName(CacheEntry cache, IndexType index, int nameHash) - { - try (Connection con = sql2o.open()) - { - CacheDAO cacheDao = new CacheDAO(); - return cacheDao.findArchiveByName(con, cache, index, nameHash); - } - } - - public List getItems() throws IOException - { - CacheEntry cache = findMostRecent(); - if (cache == null) - { - return Collections.emptyList(); - } - - IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber()); - ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId()); - ArchiveFiles archiveFiles = getArchiveFiles(archiveEntry); - final ItemLoader itemLoader = new ItemLoader(); - final List result = new ArrayList<>(archiveFiles.getFiles().size()); - for (FSFile file : archiveFiles.getFiles()) - { - ItemDefinition itemDef = itemLoader.load(file.getFileId(), file.getContents()); - result.add(itemDef); - } - return result; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java deleted file mode 100644 index acda96e77f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/ArchiveEntry.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class ArchiveEntry -{ - private int id; - private int archiveId; - private int nameHash; - private int crc; - private int revision; - private byte[] hash; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java deleted file mode 100644 index 231ad7c655..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/CacheEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import java.time.Instant; -import lombok.Data; - -@Data -public class CacheEntry -{ - private int id; - private int revision; - private Instant date; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java deleted file mode 100644 index c5f35a4cc3..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/FileEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class FileEntry -{ - private int id; - private int archiveId; - private int fileId; - private int nameHash; -} diff --git a/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java b/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java deleted file mode 100644 index 8d60927c71..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/cache/beans/IndexEntry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.cache.beans; - -import lombok.Data; - -@Data -public class IndexEntry -{ - private int id; - private int indexId; - private int crc; - private int revision; -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java deleted file mode 100644 index 954c90e94b..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import net.runelite.http.api.chat.Duels; -import net.runelite.http.api.chat.LayoutRoom; -import net.runelite.http.api.chat.Task; -import net.runelite.http.service.util.exception.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/chat") -public class ChatController -{ - private static final Pattern STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]"); - private static final int STRING_MAX_LENGTH = 50; - private static final int MAX_LAYOUT_ROOMS = 16; - private static final int MAX_PETS = 256; - - private final Cache killCountCache = CacheBuilder.newBuilder() - .expireAfterWrite(2, TimeUnit.MINUTES) - .maximumSize(128L) - .build(); - - @Autowired - private ChatService chatService; - - @PostMapping("/kc") - public void submitKc(@RequestParam String name, @RequestParam String boss, @RequestParam int kc) - { - if (kc <= 0) - { - return; - } - - chatService.setKc(name, boss, kc); - killCountCache.put(new KillCountKey(name, boss), kc); - } - - @GetMapping("/kc") - public int getKc(@RequestParam String name, @RequestParam String boss) - { - Integer kc = killCountCache.getIfPresent(new KillCountKey(name, boss)); - if (kc == null) - { - kc = chatService.getKc(name, boss); - if (kc != null) - { - killCountCache.put(new KillCountKey(name, boss), kc); - } - } - - if (kc == null) - { - throw new NotFoundException(); - } - return kc; - } - - @PostMapping("/qp") - public void submitQp(@RequestParam String name, @RequestParam int qp) - { - if (qp < 0) - { - return; - } - - chatService.setQp(name, qp); - } - - @GetMapping("/qp") - public int getQp(@RequestParam String name) - { - Integer kc = chatService.getQp(name); - if (kc == null) - { - throw new NotFoundException(); - } - return kc; - } - - @PostMapping("/gc") - public void submitGc(@RequestParam String name, @RequestParam int gc) - { - if (gc < 0) - { - return; - } - - chatService.setGc(name, gc); - } - - @GetMapping("/gc") - public int getKc(@RequestParam String name) - { - Integer gc = chatService.getGc(name); - if (gc == null) - { - throw new NotFoundException(); - } - return gc; - } - - @PostMapping("/task") - public void submitTask(@RequestParam String name, @RequestParam("task") String taskName, @RequestParam int amount, - @RequestParam int initialAmount, @RequestParam String location) - { - Matcher mTask = STRING_VALIDATION.matcher(taskName); - Matcher mLocation = STRING_VALIDATION.matcher(location); - if (mTask.find() || taskName.length() > STRING_MAX_LENGTH || - mLocation.find() || location.length() > STRING_MAX_LENGTH) - { - return; - } - - Task task = new Task(); - task.setTask(taskName); - task.setAmount(amount); - task.setInitialAmount(initialAmount); - task.setLocation(location); - - chatService.setTask(name, task); - } - - @GetMapping("/task") - public ResponseEntity getTask(@RequestParam String name) - { - Task task = chatService.getTask(name); - if (task == null) - { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(2, TimeUnit.MINUTES).cachePublic()) - .body(task); - } - - @PostMapping("/pb") - public void submitPb(@RequestParam String name, @RequestParam String boss, @RequestParam double pb) - { - if (pb < 0) - { - return; - } - - chatService.setPb(name, boss, pb); - } - - @GetMapping("/pb") - public double getPb(@RequestParam String name, @RequestParam String boss) - { - Double pb = chatService.getPb(name, boss); - if (pb == null) - { - throw new NotFoundException(); - } - return pb; - } - - @PostMapping("/duels") - public void submitDuels(@RequestParam String name, @RequestParam int wins, - @RequestParam int losses, - @RequestParam int winningStreak, @RequestParam int losingStreak) - { - if (wins < 0 || losses < 0 || winningStreak < 0 || losingStreak < 0) - { - return; - } - - Duels duels = new Duels(); - duels.setWins(wins); - duels.setLosses(losses); - duels.setWinningStreak(winningStreak); - duels.setLosingStreak(losingStreak); - - chatService.setDuels(name, duels); - } - - @GetMapping("/duels") - public Duels getDuels(@RequestParam String name) - { - Duels duels = chatService.getDuels(name); - if (duels == null) - { - throw new NotFoundException(); - } - return duels; - } - - @PostMapping("/layout") - public void submitLayout(@RequestParam String name, @RequestBody LayoutRoom[] rooms) - { - if (rooms.length > MAX_LAYOUT_ROOMS) - { - return; - } - - chatService.setLayout(name, rooms); - } - - @GetMapping("/layout") - public LayoutRoom[] getLayout(@RequestParam String name) - { - LayoutRoom[] layout = chatService.getLayout(name); - - if (layout == null) - { - throw new NotFoundException(); - } - - return layout; - } - - @PostMapping("/pets") - public void submitPetList(@RequestParam String name, @RequestBody int[] petList) - { - if (petList.length == 0 || petList.length > MAX_PETS) - { - return; - } - - chatService.setPetList(name, petList); - } - - @GetMapping("/pets") - public int[] getPetList(@RequestParam String name) - { - int[] petList = chatService.getPetList(name); - if (petList == null) - { - throw new NotFoundException(); - } - - return petList; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java deleted file mode 100644 index 7748728aab..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import net.runelite.http.api.chat.Duels; -import net.runelite.http.api.chat.LayoutRoom; -import net.runelite.http.api.chat.Task; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import redis.clients.jedis.Jedis; - -@Service -public class ChatService -{ - private static final Duration EXPIRE = Duration.ofMinutes(2); - - private final RedisPool jedisPool; - - @Autowired - public ChatService(RedisPool jedisPool) - { - this.jedisPool = jedisPool; - } - - public Integer getKc(String name, String boss) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("kc." + name + "." + boss); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setKc(String name, String boss, int kc) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("kc." + name + "." + boss, (int) EXPIRE.getSeconds(), Integer.toString(kc)); - } - } - - public Integer getQp(String name) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("qp." + name); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setQp(String name, int qp) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("qp." + name, (int) EXPIRE.getSeconds(), Integer.toString(qp)); - } - } - - public Task getTask(String name) - { - Map map; - - try (Jedis jedis = jedisPool.getResource()) - { - map = jedis.hgetAll("task." + name); - } - - if (map.isEmpty()) - { - return null; - } - - Task task = new Task(); - task.setTask(map.get("task")); - task.setAmount(Integer.parseInt(map.get("amount"))); - task.setInitialAmount(Integer.parseInt(map.get("initialAmount"))); - task.setLocation(map.get("location")); - return task; - } - - public void setTask(String name, Task task) - { - Map taskMap = ImmutableMap.builderWithExpectedSize(4) - .put("task", task.getTask()) - .put("amount", Integer.toString(task.getAmount())) - .put("initialAmount", Integer.toString(task.getInitialAmount())) - .put("location", task.getLocation()) - .build(); - - String key = "task." + name; - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.hmset(key, taskMap); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } - - public Double getPb(String name, String boss) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("pb." + boss + "." + name); - } - return value == null ? null : Double.parseDouble(value); - } - - public void setPb(String name, String boss, double pb) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("pb." + boss + "." + name, (int) EXPIRE.getSeconds(), Double.toString(pb)); - } - } - - public Integer getGc(String name) - { - String value; - try (Jedis jedis = jedisPool.getResource()) - { - value = jedis.get("gc." + name); - } - return value == null ? null : Integer.parseInt(value); - } - - public void setGc(String name, int gc) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("gc." + name, (int) EXPIRE.getSeconds(), Integer.toString(gc)); - } - } - - public Duels getDuels(String name) - { - Map map; - - try (Jedis jedis = jedisPool.getResource()) - { - map = jedis.hgetAll("duels." + name); - } - - if (map.isEmpty()) - { - return null; - } - - Duels duels = new Duels(); - duels.setWins(Integer.parseInt(map.get("wins"))); - duels.setLosses(Integer.parseInt(map.get("losses"))); - duels.setWinningStreak(Integer.parseInt(map.get("winningStreak"))); - duels.setLosingStreak(Integer.parseInt(map.get("losingStreak"))); - return duels; - } - - public void setDuels(String name, Duels duels) - { - Map duelsMap = ImmutableMap.builderWithExpectedSize(4) - .put("wins", Integer.toString(duels.getWins())) - .put("losses", Integer.toString(duels.getLosses())) - .put("winningStreak", Integer.toString(duels.getWinningStreak())) - .put("losingStreak", Integer.toString(duels.getLosingStreak())) - .build(); - - String key = "duels." + name; - - try (Jedis jedis = jedisPool.getResource()) - { - jedis.hmset(key, duelsMap); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } - - public LayoutRoom[] getLayout(String name) - { - String layout; - try (Jedis jedis = jedisPool.getResource()) - { - layout = jedis.get("layout." + name); - } - - if (layout == null) - { - return null; - } - - List roomList = Splitter.on(' ').splitToList(layout); - return roomList.stream() - .map(LayoutRoom::valueOf) - .toArray(LayoutRoom[]::new); - } - - public void setLayout(String name, LayoutRoom[] rooms) - { - try (Jedis jedis = jedisPool.getResource()) - { - jedis.setex("layout." + name, (int) EXPIRE.getSeconds(), Joiner.on(' ').join(rooms)); - } - } - - public int[] getPetList(String name) - { - Set pets; - try (Jedis jedis = jedisPool.getResource()) - { - pets = jedis.smembers("pets." + name); - } - - if (pets.isEmpty()) - { - return null; - } - - return pets.stream() - .mapToInt(Integer::parseInt) - .toArray(); - } - - public void setPetList(String name, int[] petList) - { - String[] pets = Arrays.stream(petList).mapToObj(Integer::toString).toArray(String[]::new); - String key = "pets." + name; - try (Jedis jedis = jedisPool.getResource()) - { - jedis.sadd(key, pets); - jedis.expire(key, (int) EXPIRE.getSeconds()); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java b/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java deleted file mode 100644 index 07ca775dad..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/chat/KillCountKey.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.chat; - -import lombok.Value; - -@Value -class KillCountKey -{ - private String username; - private String boss; -} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java deleted file mode 100644 index c247ecc0bc..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/config/ConfigController.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import java.io.IOException; -import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.config.Configuration; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -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; - -@RestController -@RequestMapping("/config") -public class ConfigController -{ - private final ConfigService configService; - private final AuthFilter authFilter; - - @Autowired - public ConfigController(ConfigService configService, AuthFilter authFilter) - { - this.configService = configService; - this.authFilter = authFilter; - } - - @GetMapping - public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return null; - } - - return configService.get(session.getUser()); - } - - @PatchMapping - public List patch( - HttpServletRequest request, - HttpServletResponse response, - @RequestBody Configuration changes - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - if (session == null) - { - return null; - } - - List failures = configService.patch(session.getUser(), changes); - if (failures.size() != 0) - { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return failures; - } - - return null; - } - - @RequestMapping(path = "/{key:.+}", method = PUT) - public void setKey( - HttpServletRequest request, - HttpServletResponse response, - @PathVariable String key, - @RequestBody(required = false) String value - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - if (!configService.setKey(session.getUser(), key, value)) - { - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } - - @RequestMapping(path = "/{key:.+}", method = DELETE) - public void unsetKey( - HttpServletRequest request, - HttpServletResponse response, - @PathVariable String key - ) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - if (!configService.unsetKey(session.getUser(), key)) - { - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java b/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java deleted file mode 100644 index bb6050ad4b..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/config/ConfigService.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (c) 2017-2019, Adam - * 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.config; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSyntaxException; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import static com.mongodb.client.model.Filters.eq; -import com.mongodb.client.model.IndexOptions; -import com.mongodb.client.model.Indexes; -import com.mongodb.client.model.UpdateOptions; -import static com.mongodb.client.model.Updates.combine; -import static com.mongodb.client.model.Updates.set; -import static com.mongodb.client.model.Updates.unset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.config.ConfigEntry; -import net.runelite.http.api.config.Configuration; -import org.bson.Document; -import org.bson.conversions.Bson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -public class ConfigService -{ - private static final Pattern MAYBE_JSON = Pattern.compile("^[\\-0-9{\\[\"]|true|false"); - private static final int MAX_DEPTH = 8; - private static final int MAX_VALUE_LENGTH = 262144; - - private final Gson GSON = RuneLiteAPI.GSON; - private final UpdateOptions upsertUpdateOptions = new UpdateOptions().upsert(true); - - private final MongoCollection mongoCollection; - - @Autowired - public ConfigService( - MongoClient mongoClient, - @Value("${mongo.database}") String databaseName - ) - { - - MongoDatabase database = mongoClient.getDatabase(databaseName); - MongoCollection collection = database.getCollection("config"); - this.mongoCollection = collection; - - // Create unique index on _userId - IndexOptions indexOptions = new IndexOptions().unique(true); - collection.createIndex(Indexes.ascending("_userId"), indexOptions); - } - - private Document getConfig(int userId) - { - return mongoCollection.find(eq("_userId", userId)).first(); - } - - public Configuration get(int userId) - { - Map configMap = getConfig(userId); - - if (configMap == null || configMap.isEmpty()) - { - return new Configuration(Collections.emptyList()); - } - - List config = new ArrayList<>(); - - for (String group : configMap.keySet()) - { - // Reserved keys - if (group.startsWith("_") || group.startsWith("$")) - { - continue; - } - - Map groupMap = (Map) configMap.get(group); - - for (Map.Entry entry : groupMap.entrySet()) - { - String key = entry.getKey(); - Object value = entry.getValue(); - - if (value instanceof Map || value instanceof Collection) - { - value = GSON.toJson(entry.getValue()); - } - else if (value == null) - { - continue; - } - - ConfigEntry configEntry = new ConfigEntry(); - configEntry.setKey(group + "." + key.replace(':', '.')); - configEntry.setValue(value.toString()); - config.add(configEntry); - } - } - - return new Configuration(config); - } - - public List patch(int userID, Configuration config) - { - List failures = new ArrayList<>(); - List sets = new ArrayList<>(config.getConfig().size()); - for (ConfigEntry entry : config.getConfig()) - { - Bson s = setForKV(entry.getKey(), entry.getValue()); - if (s == null) - { - failures.add(entry.getKey()); - } - else - { - sets.add(s); - } - } - - if (sets.size() > 0) - { - mongoCollection.updateOne( - eq("_userId", userID), - combine(sets), - upsertUpdateOptions - ); - } - - return failures; - } - - @Nullable - private Bson setForKV(String key, @Nullable String value) - { - if (key.startsWith("$") || key.startsWith("_")) - { - return null; - } - - String[] split = key.split("\\.", 2); - if (split.length != 2) - { - return null; - } - - String dbKey = split[0] + "." + split[1].replace('.', ':'); - - if (Strings.isNullOrEmpty(value)) - { - return unset(dbKey); - } - - Object jsonValue; - if (!isMaybeJson(value)) - { - if (!validateStr(value)) - { - return null; - } - - jsonValue = value; - } - else - { - if (!validateJson(value)) - { - return null; - } - - jsonValue = parseJsonString(value); - } - return set(dbKey, jsonValue); - } - - public boolean setKey( - int userId, - String key, - @Nullable String value - ) - { - Bson set = setForKV(key, value); - if (set == null) - { - return false; - } - - mongoCollection.updateOne(eq("_userId", userId), - set, - upsertUpdateOptions); - return true; - } - - public boolean unsetKey( - int userId, - String key - ) - { - Bson set = setForKV(key, null); - if (set == null) - { - return false; - } - - mongoCollection.updateOne(eq("_userId", userId), set); - return true; - } - - @VisibleForTesting - static Object parseJsonString(String value) - { - Object jsonValue; - try - { - jsonValue = RuneLiteAPI.GSON.fromJson(value, Object.class); - if (jsonValue == null) - { - return value; - } - else if (jsonValue instanceof Double || jsonValue instanceof Float) - { - Number number = (Number) jsonValue; - if (Math.floor(number.doubleValue()) == number.doubleValue() && !Double.isInfinite(number.doubleValue())) - { - // value is an int or long. 'number' might be truncated so parse it from 'value' - try - { - jsonValue = Integer.parseInt(value); - } - catch (NumberFormatException ex) - { - try - { - jsonValue = Long.parseLong(value); - } - catch (NumberFormatException ex2) - { - - } - } - } - } - } - catch (JsonSyntaxException ex) - { - jsonValue = value; - } - return jsonValue; - } - - @VisibleForTesting - static boolean isMaybeJson(String value) - { - return MAYBE_JSON.matcher(value).find(); - } - - private static boolean validateStr(String value) - { - return value.length() < MAX_VALUE_LENGTH; - } - - @VisibleForTesting - static boolean validateJson(String value) - { - try - { - // I couldn't figure out a better way to do this than a second json parse - JsonElement jsonElement = RuneLiteAPI.GSON.fromJson(value, JsonElement.class); - if (jsonElement == null) - { - return value.length() < MAX_VALUE_LENGTH; - } - return validateObject(jsonElement, 1); - } - catch (JsonSyntaxException ex) - { - // the client submits the string representation of objects which is not always valid json, - // eg. a value with a ':' in it. We just ignore it now. We can't json encode the values client - // side due to them already being strings, which prevents gson from being able to convert them - // to ints/floats/maps etc. - return value.length() < MAX_VALUE_LENGTH; - } - } - - private static boolean validateObject(JsonElement jsonElement, int depth) - { - if (depth >= MAX_DEPTH) - { - return false; - } - - if (jsonElement.isJsonObject()) - { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - - for (Map.Entry entry : jsonObject.entrySet()) - { - JsonElement element = entry.getValue(); - - if (!validateObject(element, depth + 1)) - { - return false; - } - } - } - else if (jsonElement.isJsonArray()) - { - JsonArray jsonArray = jsonElement.getAsJsonArray(); - - for (int i = 0; i < jsonArray.size(); ++i) - { - JsonElement element = jsonArray.get(i); - - if (!validateObject(element, depth + 1)) - { - return false; - } - } - } - else if (jsonElement.isJsonPrimitive()) - { - JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive(); - String value = jsonPrimitive.getAsString(); - if (value.length() >= MAX_VALUE_LENGTH) - { - return false; - } - } - - return true; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java b/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java deleted file mode 100644 index 9c799d9873..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/FeedController.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed; - -import com.google.common.hash.HashCode; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedResult; -import net.runelite.http.service.feed.blog.BlogService; -import net.runelite.http.service.feed.osrsnews.OSRSNewsService; -import net.runelite.http.service.feed.twitter.TwitterService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/feed") -@Slf4j -public class FeedController -{ - private final BlogService blogService; - private final TwitterService twitterService; - private final OSRSNewsService osrsNewsService; - - private static class MemoizedFeed - { - final FeedResult feedResult; - final String hash; - - MemoizedFeed(FeedResult feedResult) - { - this.feedResult = feedResult; - - Hasher hasher = Hashing.sha256().newHasher(); - for (FeedItem itemPrice : feedResult.getItems()) - { - hasher.putBytes(itemPrice.getTitle().getBytes(StandardCharsets.UTF_8)).putBytes(itemPrice.getContent().getBytes(StandardCharsets.UTF_8)); - } - HashCode code = hasher.hash(); - hash = code.toString(); - } - } - - private MemoizedFeed memoizedFeed; - - @Autowired - public FeedController(BlogService blogService, TwitterService twitterService, OSRSNewsService osrsNewsService) - { - this.blogService = blogService; - this.twitterService = twitterService; - this.osrsNewsService = osrsNewsService; - } - - @Scheduled(fixedDelay = 10 * 60 * 1000) - public void updateFeed() - { - List items = new ArrayList<>(); - - try - { - items.addAll(blogService.getBlogPosts()); - } - catch (Exception e) - { - log.warn("unable to fetch blogs", e); - } - - try - { - items.addAll(twitterService.getTweets()); - } - catch (Exception e) - { - log.warn("unable to fetch tweets", e); - } - - try - { - items.addAll(osrsNewsService.getNews()); - } - catch (Exception e) - { - log.warn("unable to fetch news", e); - } - - memoizedFeed = new MemoizedFeed(new FeedResult(items)); - } - - @GetMapping - public ResponseEntity getFeed() - { - if (memoizedFeed == null) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .eTag(memoizedFeed.hash) - .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) - .body(memoizedFeed.feedResult); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java b/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java deleted file mode 100644 index 72f7938910..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/blog/BlogService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.blog; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -@Service -public class BlogService -{ - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - - private final OkHttpClient okHttpClient; - private final HttpUrl rssUrl; - - @Autowired - public BlogService( - OkHttpClient okHttpClient, - @Value("${runelite.feed.rssUrl}") String rssUrl - ) - { - this.okHttpClient = okHttpClient; - this.rssUrl = HttpUrl.get(rssUrl); - } - - public List getBlogPosts() throws IOException - { - Request request = new Request.Builder() - .url(rssUrl) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error getting blog posts: " + response); - } - - try - { - InputStream in = response.body().byteStream(); - Document document = DocumentBuilderFactory.newInstance() - .newDocumentBuilder() - .parse(in); - - Element documentElement = document.getDocumentElement(); - NodeList documentItems = documentElement.getElementsByTagName("entry"); - - List items = new ArrayList<>(); - - for (int i = 0; i < Math.min(documentItems.getLength(), 3); i++) - { - Node item = documentItems.item(i); - NodeList children = item.getChildNodes(); - - String title = null; - String summary = null; - String link = null; - long timestamp = -1; - - for (int j = 0; j < children.getLength(); j++) - { - Node childItem = children.item(j); - String nodeName = childItem.getNodeName(); - - switch (nodeName) - { - case "title": - title = childItem.getTextContent(); - break; - case "summary": - summary = childItem.getTextContent().replace("\n", "").trim(); - break; - case "link": - link = childItem.getAttributes().getNamedItem("href").getTextContent(); - break; - case "updated": - timestamp = DATE_FORMAT.parse(childItem.getTextContent()).getTime(); - break; - } - } - - if (title == null || summary == null || link == null || timestamp == -1) - { - throw new InternalServerErrorException("Failed to find title, summary, link and/or timestamp in the blog post feed"); - } - - items.add(new FeedItem(FeedItemType.BLOG_POST, title, summary, link, timestamp)); - } - - return items; - } - catch (ParserConfigurationException | SAXException | ParseException e) - { - throw new InternalServerErrorException("Failed to parse blog posts: " + e.getMessage()); - } - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java b/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java deleted file mode 100644 index e53b2d8044..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/osrsnews/OSRSNewsService.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.osrsnews; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -@Service -public class OSRSNewsService -{ - private static final SimpleDateFormat PUB_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy '00:00:00 GMT'", Locale.US); - - private final OkHttpClient okHttpClient; - private final HttpUrl rssUrl; - - @Autowired - public OSRSNewsService( - OkHttpClient okHttpClient, - @Value("${runelite.osrsnews.rssUrl}") String rssUrl - ) - { - this.okHttpClient = okHttpClient; - this.rssUrl = HttpUrl.get(rssUrl); - } - - public List getNews() throws IOException - { - Request request = new Request.Builder() - .url(rssUrl) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error getting OSRS news: " + response); - } - - try - { - InputStream in = response.body().byteStream(); - Document document = DocumentBuilderFactory.newInstance() - .newDocumentBuilder() - .parse(in); - - Element documentElement = document.getDocumentElement(); - NodeList documentItems = documentElement.getElementsByTagName("item"); - - List items = new ArrayList<>(); - - for (int i = 0; i < documentItems.getLength(); i++) - { - Node item = documentItems.item(i); - NodeList children = item.getChildNodes(); - - String title = null; - String description = null; - String link = null; - long timestamp = -1; - - for (int j = 0; j < children.getLength(); j++) - { - Node childItem = children.item(j); - String nodeName = childItem.getNodeName(); - - switch (nodeName) - { - case "title": - title = childItem.getTextContent(); - break; - case "description": - description = childItem.getTextContent().replace("\n", "").trim(); - break; - case "link": - link = childItem.getTextContent(); - break; - case "pubDate": - timestamp = PUB_DATE_FORMAT.parse(childItem.getTextContent()).getTime(); - break; - } - } - - if (title == null || description == null || link == null || timestamp == -1) - { - throw new InternalServerErrorException("Failed to find title, description, link and/or timestamp in the OSRS RSS feed"); - } - - items.add(new FeedItem(FeedItemType.OSRS_NEWS, title, description, link, timestamp)); - } - - return items; - } - catch (ParserConfigurationException | SAXException | ParseException e) - { - throw new InternalServerErrorException("Failed to parse OSRS news: " + e.getMessage()); - } - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java deleted file mode 100644 index 24df0b6cf6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterOAuth2TokenResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.annotations.SerializedName; -import lombok.Data; - -@Data -class TwitterOAuth2TokenResponse -{ - @SerializedName("token_type") - private String tokenType; - - @SerializedName("access_token") - private String token; -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java deleted file mode 100644 index 4b7b026646..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterService.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.reflect.TypeToken; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.feed.FeedItem; -import net.runelite.http.api.feed.FeedItemType; -import net.runelite.http.service.util.exception.InternalServerErrorException; -import okhttp3.FormBody; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; - -@Service -public class TwitterService -{ - private static final HttpUrl AUTH_URL = HttpUrl.parse("https://api.twitter.com/oauth2/token"); - private static final HttpUrl LIST_STATUSES_URL = HttpUrl.parse("https://api.twitter.com/1.1/lists/statuses.json"); - - private final String credentials; - private final String listId; - private final OkHttpClient okHttpClient; - - private String token; - - @Autowired - public TwitterService( - @Value("${runelite.twitter.consumerkey}") String consumerKey, - @Value("${runelite.twitter.secretkey}") String consumerSecret, - @Value("${runelite.twitter.listid}") String listId, - OkHttpClient okHttpClient - ) - { - this.credentials = consumerKey + ":" + consumerSecret; - this.listId = listId; - this.okHttpClient = okHttpClient; - } - - public List getTweets() throws IOException - { - return getTweets(false); - } - - private List getTweets(boolean hasRetried) throws IOException - { - if (token == null) - { - updateToken(); - } - - HttpUrl url = LIST_STATUSES_URL.newBuilder() - .addQueryParameter("list_id", listId) - .addQueryParameter("count", "15") - .addQueryParameter("include_entities", "false") - .build(); - - Request request = new Request.Builder() - .url(url) - .header("Authorization", "Bearer " + token) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - switch (HttpStatus.valueOf(response.code())) - { - case BAD_REQUEST: - case UNAUTHORIZED: - updateToken(); - if (!hasRetried) - { - return getTweets(true); - } - throw new InternalServerErrorException("Could not auth to Twitter after trying once: " + response); - default: - throw new IOException("Error getting Twitter list: " + response); - } - } - - InputStream in = response.body().byteStream(); - Type listType = new TypeToken>() - { - }.getType(); - List statusesResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), listType); - - List items = new ArrayList<>(); - - for (TwitterStatusesResponseItem i : statusesResponse) - { - items.add(new FeedItem(FeedItemType.TWEET, - i.getUser().getProfileImageUrl(), - i.getUser().getScreenName(), - i.getText().replace("\n\n", " ").replaceAll("\n", " "), - "https://twitter.com/" + i.getUser().getScreenName() + "/status/" + i.getId(), - getTimestampFromSnowflake(i.getId()))); - } - - return items; - } - } - - private void updateToken() throws IOException - { - String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); - - Request request = new Request.Builder() - .url(AUTH_URL) - .header("Authorization", "Basic " + encodedCredentials) - .post(new FormBody.Builder().add("grant_type", "client_credentials").build()) - .build(); - - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Error authing to Twitter: " + response); - } - - InputStream in = response.body().byteStream(); - TwitterOAuth2TokenResponse tokenResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), TwitterOAuth2TokenResponse.class); - - if (!tokenResponse.getTokenType().equals("bearer")) - { - throw new InternalServerErrorException("Returned token was not a bearer token"); - } - - if (tokenResponse.getToken() == null) - { - throw new InternalServerErrorException("Returned token was null"); - } - - token = tokenResponse.getToken(); - } - } - - /** - * Extracts the UTC timestamp from a Twitter snowflake as per - * https://github.com/client9/snowflake2time/blob/master/python/snowflake.py#L24 - */ - private long getTimestampFromSnowflake(long snowflake) - { - return (snowflake >> 22) + 1288834974657L; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java deleted file mode 100644 index 90b37c5021..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItem.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import lombok.Data; - -@Data -class TwitterStatusesResponseItem -{ - private long id; - private String text; - private TwitterStatusesResponseItemUser user; -} diff --git a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java b/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java deleted file mode 100644 index 94fe9360f9..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/feed/twitter/TwitterStatusesResponseItemUser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.feed.twitter; - -import com.google.gson.annotations.SerializedName; -import lombok.Data; - -@Data -class TwitterStatusesResponseItemUser -{ - @SerializedName("screen_name") - private String screenName; - - @SerializedName("profile_image_url_https") - private String profileImageUrl; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java deleted file mode 100644 index 509f2bdb70..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import com.google.gson.Gson; -import java.io.IOException; -import java.time.Instant; -import java.util.Collection; -import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.ge.GrandExchangeTrade; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/ge") -public class GrandExchangeController -{ - private static final Gson GSON = RuneLiteAPI.GSON; - - private final GrandExchangeService grandExchangeService; - private final AuthFilter authFilter; - private final RedisPool redisPool; - - @Autowired - public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter, RedisPool redisPool) - { - this.grandExchangeService = grandExchangeService; - this.authFilter = authFilter; - this.redisPool = redisPool; - } - - @PostMapping - public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException - { - SessionEntry session = null; - if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) - { - session = authFilter.handle(request, response); - if (session == null) - { - // error is set here on the response, so we shouldn't continue - return; - } - } - Integer userId = session == null ? null : session.getUser(); - - // We don't keep track of pending trades in the web UI, so only add cancelled or completed trades - if (userId != null && - grandExchangeTrade.getQty() > 0 && - (grandExchangeTrade.isCancel() || grandExchangeTrade.getQty() == grandExchangeTrade.getTotal())) - { - grandExchangeService.add(userId, grandExchangeTrade); - } - - Trade trade = new Trade(); - trade.setBuy(grandExchangeTrade.isBuy()); - trade.setCancel(grandExchangeTrade.isCancel()); - trade.setLogin(grandExchangeTrade.isLogin()); - trade.setItemId(grandExchangeTrade.getItemId()); - trade.setQty(grandExchangeTrade.getQty()); - trade.setDqty(grandExchangeTrade.getDqty()); - trade.setTotal(grandExchangeTrade.getTotal()); - trade.setSpent(grandExchangeTrade.getDspent()); - trade.setOffer(grandExchangeTrade.getOffer()); - trade.setSlot(grandExchangeTrade.getSlot()); - trade.setTime((int) (System.currentTimeMillis() / 1000L)); - trade.setMachineId(request.getHeader(RuneLiteAPI.RUNELITE_MACHINEID)); - trade.setUserId(userId); - trade.setIp(request.getHeader("X-Forwarded-For")); - trade.setUa(request.getHeader("User-Agent")); - trade.setWorldType(grandExchangeTrade.getWorldType()); - trade.setSeq(grandExchangeTrade.getSeq()); - Instant resetTime = grandExchangeTrade.getResetTime(); - trade.setResetTime(resetTime == null ? 0L : resetTime.getEpochSecond()); - - String json = GSON.toJson(trade); - try (Jedis jedis = redisPool.getResource()) - { - jedis.publish("ge", json); - } - } - - @GetMapping - public Collection get(HttpServletRequest request, HttpServletResponse response, - @RequestParam(required = false, defaultValue = "1024") int limit, - @RequestParam(required = false, defaultValue = "0") int offset) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return null; - } - - return grandExchangeService.get(session.getUser(), limit, offset).stream() - .map(GrandExchangeController::convert) - .collect(Collectors.toList()); - } - - private static GrandExchangeTradeHistory convert(TradeEntry tradeEntry) - { - GrandExchangeTradeHistory grandExchangeTrade = new GrandExchangeTradeHistory(); - grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY); - grandExchangeTrade.setItemId(tradeEntry.getItem()); - grandExchangeTrade.setQuantity(tradeEntry.getQuantity()); - grandExchangeTrade.setPrice(tradeEntry.getPrice()); - grandExchangeTrade.setTime(tradeEntry.getTime()); - return grandExchangeTrade; - } - - @DeleteMapping - public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException - { - SessionEntry session = authFilter.handle(request, response); - - if (session == null) - { - return; - } - - grandExchangeService.delete(session.getUser()); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java deleted file mode 100644 index 227d5e1159..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeService.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import java.util.Collection; -import net.runelite.http.api.ge.GrandExchangeTrade; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Sql2o; - -@Service -public class GrandExchangeService -{ - private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" + - " `id` int(11) NOT NULL AUTO_INCREMENT,\n" + - " `user` int(11) NOT NULL,\n" + - " `action` enum('BUY','SELL') NOT NULL,\n" + - " `item` int(11) NOT NULL,\n" + - " `quantity` int(11) NOT NULL,\n" + - " `price` int(11) NOT NULL,\n" + - " `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + - " PRIMARY KEY (`id`),\n" + - " KEY `user_time` (`user`, `time`),\n" + - " KEY `time` (`time`),\n" + - " CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" + - ") ENGINE=InnoDB;"; - - private final Sql2o sql2o; - private final int historyDays; - - @Autowired - public GrandExchangeService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${runelite.ge.history}") int historyDays - ) - { - this.sql2o = sql2o; - this.historyDays = historyDays; - - // Ensure necessary tables exist - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_TABLE).executeUpdate(); - } - } - - public void add(int userId, GrandExchangeTrade grandExchangeTrade) - { - try (Connection con = sql2o.open()) - { - con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," + - " :action, :item, :quantity, :price)") - .addParameter("user", userId) - .addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL") - .addParameter("item", grandExchangeTrade.getItemId()) - .addParameter("quantity", grandExchangeTrade.getQty()) - .addParameter("price", grandExchangeTrade.getSpent() / grandExchangeTrade.getQty()) - .executeUpdate(); - } - } - - public Collection get(int userId, int limit, int offset) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset") - .addParameter("user", userId) - .addParameter("limit", limit) - .addParameter("offset", offset) - .executeAndFetch(TradeEntry.class); - } - } - - public void delete(int userId) - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from ge_trades where user = :user") - .addParameter("user", userId) - .executeUpdate(); - } - } - - @Scheduled(fixedDelay = 60 * 60 * 1000) - public void expire() - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from ge_trades where time < current_timestamp - interval " + historyDays + " day") - .executeUpdate(); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java b/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java deleted file mode 100644 index c45f5acf4f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeTradeHistory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.ge; - -import java.time.Instant; -import lombok.Data; - -@Data -class GrandExchangeTradeHistory -{ - private boolean buy; - private int itemId; - private int quantity; - private int price; - private Instant time; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/Trade.java b/http-service/src/main/java/net/runelite/http/service/ge/Trade.java deleted file mode 100644 index 7ad01f322a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/Trade.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.ge; - -import lombok.Data; -import net.runelite.http.api.worlds.WorldType; - -@Data -class Trade -{ - private boolean buy; - private boolean cancel; - private boolean login; - private int itemId; - private int qty; - private int dqty; - private int total; - private int spent; - private int offer; - private int slot; - private int time; - private String machineId; - private Integer userId; - private String ip; - private String ua; - private WorldType worldType; - private int seq; - private long resetTime; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java deleted file mode 100644 index fcc96d615f..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/TradeAction.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -enum TradeAction -{ - BUY, - SELL; -} diff --git a/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java b/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java deleted file mode 100644 index bca3869811..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/ge/TradeEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.ge; - -import java.time.Instant; -import lombok.Data; - -@Data -class TradeEntry -{ - private int id; - private int user; - private TradeAction action; - private int item; - private int quantity; - private int price; - private Instant time; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemController.java b/http-service/src/main/java/net/runelite/http/service/item/ItemController.java deleted file mode 100644 index e546344d4c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemController.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.item; - -import com.google.common.base.Suppliers; -import com.google.common.hash.HashCode; -import com.google.common.hash.Hasher; -import com.google.common.hash.Hashing; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import net.runelite.http.api.item.ItemPrice; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.CacheControl; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/item") -public class ItemController -{ - private static class MemoizedPrices - { - final ItemPrice[] prices; - final String hash; - - MemoizedPrices(ItemPrice[] prices) - { - this.prices = prices; - - Hasher hasher = Hashing.sha256().newHasher(); - for (ItemPrice itemPrice : prices) - { - hasher.putInt(itemPrice.getId()).putInt(itemPrice.getPrice()); - } - HashCode code = hasher.hash(); - hash = code.toString(); - } - } - - private final ItemService itemService; - private final int priceCache; - - private final Supplier memoizedPrices; - - @Autowired - public ItemController( - ItemService itemService, - @Value("${runelite.price.cache}") int priceCache - ) - { - this.itemService = itemService; - this.priceCache = priceCache; - - memoizedPrices = Suppliers.memoizeWithExpiration(() -> new MemoizedPrices(itemService.fetchPrices().stream() - .map(priceEntry -> - { - ItemPrice itemPrice = new ItemPrice(); - itemPrice.setId(priceEntry.getItem()); - itemPrice.setName(priceEntry.getName()); - itemPrice.setPrice(priceEntry.getPrice()); - itemPrice.setWikiPrice(computeWikiPrice(priceEntry)); - return itemPrice; - }) - .toArray(ItemPrice[]::new)), priceCache, TimeUnit.MINUTES); - } - - private static int computeWikiPrice(PriceEntry priceEntry) - { - if (priceEntry.getLow() > 0 && priceEntry.getHigh() > 0) - { - return (priceEntry.getLow() + priceEntry.getHigh()) / 2; - } - else - { - return Math.max(priceEntry.getLow(), priceEntry.getHigh()); - } - } - - @GetMapping("/prices") - public ResponseEntity prices() - { - MemoizedPrices memorizedPrices = this.memoizedPrices.get(); - return ResponseEntity.ok() - .eTag(memorizedPrices.hash) - .cacheControl(CacheControl.maxAge(priceCache, TimeUnit.MINUTES).cachePublic()) - .body(memorizedPrices.prices); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java b/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java deleted file mode 100644 index 41186b1608..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemEntry.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.time.Instant; -import lombok.Data; -import net.runelite.http.api.item.ItemType; - -@Data -public class ItemEntry -{ - private int id; - private String name; - private String description; - private ItemType type; - private Instant timestamp; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/ItemService.java b/http-service/src/main/java/net/runelite/http/service/item/ItemService.java deleted file mode 100644 index bc3f03e70c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/ItemService.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2017-2018, Adam - * 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.item; - -import com.google.gson.JsonParseException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.Random; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.definitions.ItemDefinition; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.item.ItemType; -import net.runelite.http.service.cache.CacheService; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class ItemService -{ - private static final String CREATE_ITEMS = "CREATE TABLE IF NOT EXISTS `items` (\n" - + " `id` int(11) NOT NULL,\n" - + " `name` tinytext NOT NULL,\n" - + " `description` tinytext NOT NULL,\n" - + " `type` enum('DEFAULT') NOT NULL,\n" - + " `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n" - + " PRIMARY KEY (`id`)\n" - + ") ENGINE=InnoDB"; - - private static final String CREATE_PRICES = "CREATE TABLE IF NOT EXISTS `prices` (\n" - + " `item` int(11) NOT NULL,\n" - + " `price` int(11) NOT NULL,\n" - + " `time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" - + " `fetched_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\n" - + " UNIQUE KEY `item_time` (`item`,`time`),\n" - + " KEY `item_fetched_time` (`item`,`fetched_time`)\n" - + ") ENGINE=InnoDB"; - - private final Sql2o sql2o; - private final CacheService cacheService; - private final OkHttpClient okHttpClient; - private final HttpUrl itemUrl; - private final HttpUrl priceUrl; - - private int[] tradeableItems; - private final Random random = new Random(); - - @Autowired - public ItemService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - CacheService cacheService, - OkHttpClient okHttpClient, - @Value("${runelite.item.itemUrl}") String itemUrl, - @Value("${runelite.item.priceUrl}") String priceUrl - ) - { - this.sql2o = sql2o; - this.cacheService = cacheService; - this.okHttpClient = okHttpClient; - this.itemUrl = HttpUrl.get(itemUrl); - this.priceUrl = HttpUrl.get(priceUrl); - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_ITEMS) - .executeUpdate(); - - con.createQuery(CREATE_PRICES) - .executeUpdate(); - } - } - - public ItemEntry getItem(int itemId) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select id, name, description, type from items where id = :id") - .addParameter("id", itemId) - .executeAndFetchFirst(ItemEntry.class); - } - } - - public ItemEntry fetchItem(int itemId) - { - try - { - RSItem rsItem = fetchRSItem(itemId); - - try (Connection con = sql2o.open()) - { - con.createQuery("insert into items (id, name, description, type) values (:id," - + " :name, :description, :type) ON DUPLICATE KEY UPDATE name = :name," - + " description = :description, type = :type") - .addParameter("id", rsItem.getId()) - .addParameter("name", rsItem.getName()) - .addParameter("description", rsItem.getDescription()) - .addParameter("type", rsItem.getType()) - .executeUpdate(); - } - - ItemEntry item = new ItemEntry(); - item.setId(itemId); - item.setName(rsItem.getName()); - item.setDescription(rsItem.getDescription()); - item.setType(ItemType.of(rsItem.getType())); - return item; - } - catch (IOException ex) - { - log.warn("unable to fetch item {}", itemId, ex); - return null; - } - } - - private void fetchPrice(int itemId) - { - RSPrices rsprice; - try - { - rsprice = fetchRSPrices(itemId); - } - catch (IOException ex) - { - log.warn("unable to fetch price for item {}", itemId, ex); - return; - } - - try (Connection con = sql2o.beginTransaction()) - { - Instant now = Instant.now(); - - Query query = con.createQuery("insert into prices (item, price, time, fetched_time) values (:item, :price, :time, :fetched_time) " - + "ON DUPLICATE KEY UPDATE price = VALUES(price), fetched_time = VALUES(fetched_time)"); - - for (Map.Entry entry : rsprice.getDaily().entrySet()) - { - long ts = entry.getKey(); // ms since epoch - int price = entry.getValue(); // gp - - Instant time = Instant.ofEpochMilli(ts); - - query - .addParameter("item", itemId) - .addParameter("price", price) - .addParameter("time", time) - .addParameter("fetched_time", now) - .addToBatch(); - } - - query.executeBatch(); - con.commit(false); - } - } - - public List fetchPrices() - { - try (Connection con = sql2o.beginTransaction()) - { - Query query = con.createQuery("select t2.item, t3.name, t2.time, prices.price, prices.fetched_time, t4.high, t4.low" + - " from (select t1.item as item, max(t1.time) as time from prices t1 group by item) t2" + - " join prices on t2.item=prices.item and t2.time=prices.time" + - " join items t3 on t2.item=t3.id" + - " join wiki_prices t4 on t2.item=t4.item_id"); - return query.executeAndFetch(PriceEntry.class); - } - } - - private RSItem fetchRSItem(int itemId) throws IOException - { - HttpUrl itemUrl = this.itemUrl - .newBuilder() - .addQueryParameter("item", "" + itemId) - .build(); - - Request request = new Request.Builder() - .url(itemUrl) - .build(); - - RSItemResponse itemResponse = fetchJson(request, RSItemResponse.class); - return itemResponse.getItem(); - - } - - private RSPrices fetchRSPrices(int itemId) throws IOException - { - HttpUrl priceUrl = this.priceUrl - .newBuilder() - .addPathSegment(itemId + ".json") - .build(); - - Request request = new Request.Builder() - .url(priceUrl) - .build(); - - return fetchJson(request, RSPrices.class); - } - - private T fetchJson(Request request, Class clazz) throws IOException - { - try (Response response = okHttpClient.newCall(request).execute()) - { - if (!response.isSuccessful()) - { - throw new IOException("Unsuccessful http response: " + response); - } - - InputStream in = response.body().byteStream(); - return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), clazz); - } - catch (JsonParseException ex) - { - throw new IOException(ex); - } - } - - @Scheduled(fixedDelay = 20_000) - public void crawlPrices() - { - if (tradeableItems == null || tradeableItems.length == 0) - { - return; - } - - int idx = random.nextInt(tradeableItems.length); - int id = tradeableItems[idx]; - - log.debug("Fetching price for {}", id); - - // check if the item name or description has changed - fetchItem(id); - fetchPrice(id); - } - - @Scheduled(fixedDelay = 1_800_000) // 30 minutes - public void reloadItems() throws IOException - { - List items = cacheService.getItems(); - if (items.isEmpty()) - { - log.warn("Failed to load any items from cache, item price updating will be disabled"); - } - - tradeableItems = items.stream() - .filter(ItemDefinition::isTradeable) - .mapToInt(ItemDefinition::getId) - .toArray(); - - log.debug("Loaded {} tradeable items", tradeableItems.length); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java b/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java deleted file mode 100644 index 4d29d7e98d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/PriceEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.time.Instant; -import lombok.Data; - -@Data -class PriceEntry -{ - private int item; - private String name; - private int price; - private Instant time; - private Instant fetched_time; - private int high; - private int low; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItem.java b/http-service/src/main/java/net/runelite/http/service/item/RSItem.java deleted file mode 100644 index 17e3352f6d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSItem.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import lombok.Data; - -@Data -class RSItem -{ - private int id; - private String name; - private String description; - private String type; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java b/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java deleted file mode 100644 index c0305cd552..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSItemResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import lombok.Data; - -@Data -class RSItemResponse -{ - private RSItem item; -} diff --git a/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java b/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java deleted file mode 100644 index 04331d753e..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/item/RSPrices.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.item; - -import java.util.Map; -import lombok.Data; - -@Data -public class RSPrices -{ - /** - * unix time in ms to price in gp - */ - private Map daily; -} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java deleted file mode 100644 index 4cb3375154..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootResult.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.loottracker; - -import java.time.Instant; -import lombok.Data; -import net.runelite.http.api.loottracker.LootRecordType; - -@Data -class LootResult -{ - private int killId; - private Instant first_time; - private Instant last_time; - private LootRecordType type; - private String eventId; - private int amount; - private int itemId; - private int itemQuantity; -} diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java deleted file mode 100644 index ef39ac0d50..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerController.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * Copyright (c) 2018, Adam - * 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.loottracker; - -import com.google.api.client.http.HttpStatusCodes; -import com.google.gson.Gson; -import java.io.IOException; -import java.util.Collection; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.api.RuneLiteAPI; -import net.runelite.http.api.loottracker.LootAggregate; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/loottracker") -public class LootTrackerController -{ - private static final Gson GSON = RuneLiteAPI.GSON; - - @Autowired - private LootTrackerService service; - - @Autowired - private RedisPool redisPool; - - @Autowired - private AuthFilter auth; - - @RequestMapping(method = RequestMethod.POST) - public void storeLootRecord(HttpServletRequest request, HttpServletResponse response, @RequestBody Collection records) throws IOException - { - SessionEntry session = null; - if (request.getHeader(RuneLiteAPI.RUNELITE_AUTH) != null) - { - session = auth.handle(request, response); - if (session == null) - { - // error is set here on the response, so we shouldn't continue - return; - } - } - Integer userId = session == null ? null : session.getUser(); - - if (userId != null) - { - service.store(records, userId); - } - response.setStatus(HttpStatusCodes.STATUS_CODE_OK); - - try (Jedis jedis = redisPool.getResource()) - { - jedis.publish("drops", GSON.toJson(records)); - } - } - - @GetMapping - public Collection getLootAggregate(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException - { - SessionEntry e = auth.handle(request, response); - if (e == null) - { - response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); - return null; - } - - return service.get(e.getUser(), count, start); - } - - @DeleteMapping - public void deleteLoot(HttpServletRequest request, HttpServletResponse response, - @RequestParam(required = false) String eventId) throws IOException - { - SessionEntry e = auth.handle(request, response); - if (e == null) - { - response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED); - return; - } - - service.delete(e.getUser(), eventId); - } -} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java b/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java deleted file mode 100644 index 4836afd97d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/loottracker/LootTrackerService.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2018, TheStonedTurtle - * Copyright (c) 2018, Adam - * 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.loottracker; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.runelite.http.api.loottracker.GameItem; -import net.runelite.http.api.loottracker.LootAggregate; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.api.loottracker.LootRecordType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -public class LootTrackerService -{ - private static final String CREATE_KILLS = "CREATE TABLE IF NOT EXISTS `loottracker_kills` (\n" + - " `id` bigint NOT NULL AUTO_INCREMENT,\n" + - " `first_time` timestamp NOT NULL DEFAULT current_timestamp(),\n" + - " `last_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n" + - " `accountId` int(11) NOT NULL,\n" + - " `type` enum('NPC','PLAYER','EVENT','PICKPOCKET','UNKNOWN') NOT NULL,\n" + - " `eventId` varchar(255) NOT NULL,\n" + - " `amount` int(11) NOT NULL,\n" + - " PRIMARY KEY (`id`),\n" + - " FOREIGN KEY (accountId) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,\n" + - " INDEX idx_acc_lasttime (`accountId` ,`last_time`),\n" + - " UNIQUE INDEX idx_acc_type_event (`accountId`, `type`, `eventId`),\n" + - " INDEX idx_time (last_time)" + - ") ENGINE=InnoDB;"; - - private static final String CREATE_DROPS = "CREATE TABLE IF NOT EXISTS `loottracker_drops` (\n" + - " `killId` bigint NOT NULL,\n" + - " `itemId` int(11) NOT NULL,\n" + - " `itemQuantity` int(11) NOT NULL,\n" + - " UNIQUE INDEX idx_kill_item (`killId`, `itemId`),\n" + - " FOREIGN KEY (killId) REFERENCES loottracker_kills(id) ON DELETE CASCADE\n" + - ") ENGINE=InnoDB;\n"; - - // Queries for inserting kills - private static final String INSERT_KILL_QUERY = "INSERT INTO loottracker_kills (accountId, type, eventId, amount) VALUES (:accountId, :type, :eventId, :kills) ON DUPLICATE KEY UPDATE amount = amount + :kills"; - private static final String INSERT_DROP_QUERY = "INSERT INTO loottracker_drops (killId, itemId, itemQuantity) VALUES (:killId, :itemId, :itemQuantity) ON DUPLICATE KEY UPDATE itemQuantity = itemQuantity + :itemQuantity"; - - private static final String SELECT_LOOT_QUERY = "SELECT killId,first_time,last_time,type,eventId,amount,itemId,itemQuantity FROM loottracker_kills JOIN loottracker_drops ON loottracker_drops.killId = loottracker_kills.id WHERE accountId = :accountId ORDER BY last_time DESC LIMIT :limit OFFSET :offset"; - - private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM loottracker_kills WHERE accountId = :accountId"; - private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM loottracker_kills WHERE accountId = :accountId AND eventId = :eventId"; - - private final Sql2o sql2o; - private final int historyDays; - - @Autowired - public LootTrackerService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - @Value("${runelite.loottracker.history}") int historyDays - ) - { - this.sql2o = sql2o; - this.historyDays = historyDays; - - // Ensure necessary tables exist - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE_KILLS).executeUpdate(); - con.createQuery(CREATE_DROPS).executeUpdate(); - } - } - - @RequiredArgsConstructor - @EqualsAndHashCode(exclude = {"kills", "drops"}) - @Getter - private static class AggregateLootRecord - { - final LootRecordType type; - final String eventId; - int kills = 0; - Map drops = new HashMap<>(); - } - - @RequiredArgsConstructor - @EqualsAndHashCode(exclude = "qty") - @Getter - private static class AggregateDrop - { - final int id; - int qty = 0; - } - - private static Collection aggregate(Collection records) - { - Map combinedRecords = new HashMap<>(); - for (LootRecord record : records) - { - AggregateLootRecord r = new AggregateLootRecord(record.getType(), record.getEventId()); - r = combinedRecords.computeIfAbsent(r, (k) -> k); - ++r.kills; - - // Combine drops - for (GameItem gameItem : record.getDrops()) - { - AggregateDrop cd = new AggregateDrop(gameItem.getId()); - cd = r.drops.computeIfAbsent(cd, (k) -> k); - cd.qty += gameItem.getQty(); - } - } - return combinedRecords.values(); - } - - /** - * Store LootRecord - * - * @param records LootRecords to store - * @param accountId runelite account id to tie data too - */ - public void store(Collection records, int accountId) - { - Collection combinedRecords = aggregate(records); - - try (Connection con = sql2o.beginTransaction()) - { - Query killQuery = con.createQuery(INSERT_KILL_QUERY, true); - Query insertDrop = con.createQuery(INSERT_DROP_QUERY); - - for (AggregateLootRecord record : combinedRecords) - { - killQuery - .addParameter("accountId", accountId) - .addParameter("type", record.getType()) - .addParameter("eventId", record.getEventId()) - .addParameter("kills", record.getKills()) - .executeUpdate(); - Object[] keys = con.getKeys(); - - for (AggregateDrop drop : record.getDrops().values()) - { - insertDrop - .addParameter("killId", keys[0]) - .addParameter("itemId", drop.getId()) - .addParameter("itemQuantity", drop.getQty()) - .addToBatch(); - } - - insertDrop.executeBatch(); - } - - con.commit(false); - } - } - - public Collection get(int accountId, int limit, int offset) - { - List lootResults; - - try (Connection con = sql2o.open()) - { - lootResults = con.createQuery(SELECT_LOOT_QUERY) - .addParameter("accountId", accountId) - .addParameter("limit", limit) - .addParameter("offset", offset) - .executeAndFetch(LootResult.class); - } - - LootResult current = null; - List lootRecords = new ArrayList<>(); - List gameItems = new ArrayList<>(); - - for (LootResult lootResult : lootResults) - { - if (current == null || current.getKillId() != lootResult.getKillId()) - { - if (!gameItems.isEmpty()) - { - LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); - lootRecords.add(lootRecord); - - gameItems = new ArrayList<>(); - } - - current = lootResult; - } - - GameItem gameItem = new GameItem(lootResult.getItemId(), lootResult.getItemQuantity()); - gameItems.add(gameItem); - } - - if (!gameItems.isEmpty()) - { - LootAggregate lootRecord = new LootAggregate(current.getEventId(), current.getType(), gameItems, current.getFirst_time(), current.getLast_time(), current.getAmount()); - lootRecords.add(lootRecord); - } - - return lootRecords; - } - - public void delete(int accountId, String eventId) - { - try (Connection con = sql2o.open()) - { - if (eventId == null) - { - con.createQuery(DELETE_LOOT_ACCOUNT) - .addParameter("accountId", accountId) - .executeUpdate(); - } - else - { - con.createQuery(DELETE_LOOT_ACCOUNT_EVENTID) - .addParameter("accountId", accountId) - .addParameter("eventId", eventId) - .executeUpdate(); - } - } - } - - @Scheduled(fixedDelay = 60 * 60 * 1000) - public void expire() - { - try (Connection con = sql2o.open()) - { - con.createQuery("delete from loottracker_kills where last_time < current_timestamp() - interval " + historyDays + " day") - .executeUpdate(); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java b/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java deleted file mode 100644 index f9f424dca7..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/pluginhub/PluginHubController.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2020, Adam - * 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.pluginhub; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; -import javax.servlet.http.HttpServletRequest; -import net.runelite.http.service.util.redis.RedisPool; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import redis.clients.jedis.Jedis; - -@RestController -@RequestMapping("/pluginhub") -public class PluginHubController -{ - @Value("${pluginhub.stats.days:7}") - private int days; - - @Value("${pluginhub.stats.expire:90}") - private int expireDays; - - @Autowired - private RedisPool redisPool; - - private final Cache pluginCache = CacheBuilder.newBuilder() - .maximumSize(512L) - .build(); - - private Map pluginCounts = Collections.emptyMap(); - - @GetMapping - public ResponseEntity> get() - { - if (pluginCounts.isEmpty()) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES).cachePublic()) - .body(pluginCounts); - } - - @PostMapping - public void submit(HttpServletRequest request, @RequestBody String[] plugins) - { - final String date = Instant.now().atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE); - final String ip = request.getHeader("X-Forwarded-For"); - try (Jedis jedis = redisPool.getResource()) - { - for (String plugin : plugins) - { - if (!plugin.matches("[a-z0-9-]+")) - { - continue; - } - - jedis.pfadd("pluginhub." + plugin + "." + date, ip); - - if (pluginCache.getIfPresent(plugin) == null) - { - jedis.sadd("pluginhub.plugins", plugin); - // additionally set the ttl on the hyperloglog since it might be a new key - jedis.expire("pluginhub." + plugin + "." + date, (int) (Duration.ofDays(expireDays).toMillis() / 1000L)); - - pluginCache.put(plugin, plugin); - } - } - } - } - - @Scheduled(fixedDelay = 1_800_000, initialDelay = 30_000) // 30 minutes with 30 second initial delay - public void rebuildCounts() - { - Map counts = new HashMap<>(); - try (Jedis jedis = redisPool.getResource()) - { - Set plugins = jedis.smembers("pluginhub.plugins"); - ZonedDateTime time = Instant.now().atZone(ZoneOffset.UTC); - - for (String plugin : plugins) - { - // When called with multiple keys, pfcount returns the approximated - // cardinality of the union of the HyperLogLogs. We use this to determine - // the number of users in the last N days. - String[] keys = IntStream.range(0, days - 1) - .mapToObj(time::minusDays) - .map(zdt -> "pluginhub." + plugin + "." + zdt.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .toArray(String[]::new); - long cnt = jedis.pfcount(keys); - if (cnt > 0) - { - counts.put(plugin, cnt); - } - } - } - pluginCounts = counts; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java b/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java deleted file mode 100644 index 785ad00266..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/InstantConverter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util; - -import java.sql.Timestamp; -import java.time.Instant; -import org.sql2o.converters.Converter; -import org.sql2o.converters.ConverterException; - -public class InstantConverter implements Converter -{ - @Override - public Instant convert(Object val) throws ConverterException - { - Timestamp ts = (Timestamp) val; - return ts.toInstant(); - } - - @Override - public Object toDatabaseParam(Instant val) - { - return Timestamp.from(val); - } - -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java deleted file mode 100644 index 62adc5b6fc..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/exception/InternalServerErrorException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) -public class InternalServerErrorException extends RuntimeException -{ - public InternalServerErrorException(String message) - { - super(message); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java b/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java deleted file mode 100644 index 83e04ceca6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/util/exception/NotFoundException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.util.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not found") -public class NotFoundException extends RuntimeException -{ - -} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java b/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java deleted file mode 100644 index 0723063b02..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/wiki/PriceResult.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.wiki; - -import java.util.Map; -import lombok.Data; - -@Data -class PriceResult -{ - @Data - static class Item - { - private int high; - private int highTime; - private int low; - private int lowTime; - } - - private Map data; -} diff --git a/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java b/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java deleted file mode 100644 index 2e32fc1808..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/wiki/WikiPriceService.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2021, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 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 HOLDER 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.wiki; - -import com.google.gson.JsonSyntaxException; -import java.io.IOException; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.sql2o.Connection; -import org.sql2o.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class WikiPriceService -{ - private static final String CREATE = "CREATE TABLE IF NOT EXISTS `wiki_prices` (\n" + - " `item_id` int(11) NOT NULL,\n" + - " `high` int(11) NOT NULL,\n" + - " `highTime` int(11) NOT NULL,\n" + - " `low` int(11) NOT NULL,\n" + - " `lowTime` int(11) NOT NULL,\n" + - " `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" + - " PRIMARY KEY (`item_id`)\n" + - ") ENGINE=InnoDB;"; - - private final Sql2o sql2o; - private final OkHttpClient okHttpClient; - private final HttpUrl wikiUrl; - - @Autowired - public WikiPriceService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - OkHttpClient okHttpClient, - @Value("${runelite.wiki.url}") String url - ) - { - this.sql2o = sql2o; - this.okHttpClient = okHttpClient; - this.wikiUrl = HttpUrl.get(url); - - try (Connection con = sql2o.open()) - { - con.createQuery(CREATE).executeUpdate(); - } - } - - @Scheduled(initialDelay = 1000 * 5, fixedDelayString = "${runelite.wiki.poll.ms}") - private void updateDatabase() - { - try - { - PriceResult summary = getPrices(); - - try (Connection con = sql2o.beginTransaction()) - { - Query query = con.createQuery("INSERT INTO wiki_prices (item_id, high, highTime, low, lowTime)" - + " VALUES (:itemId, :high, :highTime, :low, :lowTime)" - + " ON DUPLICATE KEY UPDATE high = VALUES(high), highTime = VALUES(highTime)," - + " low = VALUES(low), lowTime = VALUES(lowTime)"); - - for (Map.Entry entry : summary.getData().entrySet()) - { - Integer itemId = entry.getKey(); - PriceResult.Item item = entry.getValue(); - - query - .addParameter("itemId", itemId) - .addParameter("high", item.getHigh()) - .addParameter("highTime", item.getHighTime()) - .addParameter("low", item.getLow()) - .addParameter("lowTime", item.getLowTime()) - .addToBatch(); - } - - query.executeBatch(); - con.commit(false); - } - } - catch (IOException e) - { - log.warn("Error while updating wiki prices", e); - } - } - - private PriceResult getPrices() throws IOException - { - Request request = new Request.Builder() - .url(wikiUrl) - .header("User-Agent", "RuneLite") - .build(); - - try (Response responseOk = okHttpClient.newCall(request).execute()) - { - if (!responseOk.isSuccessful()) - { - throw new IOException("Error retrieving prices: " + responseOk.message()); - } - - return RuneLiteAPI.GSON.fromJson(responseOk.body().string(), PriceResult.class); - } - catch (JsonSyntaxException ex) - { - throw new IOException(ex); - } - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java b/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java deleted file mode 100644 index 642cd0440a..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/ServiceWorldType.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.worlds; - -import net.runelite.http.api.worlds.WorldType; - -enum ServiceWorldType -{ - MEMBERS(WorldType.MEMBERS, 1), - PVP(WorldType.PVP, 1 << 2), - BOUNTY(WorldType.BOUNTY, 1 << 5), - SKILL_TOTAL(WorldType.SKILL_TOTAL, 1 << 7), - HIGH_RISK(WorldType.HIGH_RISK, 1 << 10), - LAST_MAN_STANDING(WorldType.LAST_MAN_STANDING, 1 << 14), - NOSAVE_MODE(WorldType.NOSAVE_MODE, 1 << 25), - TOURNAMENT(WorldType.TOURNAMENT, 1 << 26), - DEADMAN(WorldType.DEADMAN, 1 << 29), - SEASONAL(WorldType.SEASONAL, 1 << 30); - - private final WorldType apiType; - private final int mask; - - ServiceWorldType(WorldType apiType, int mask) - { - this.apiType = apiType; - this.mask = mask; - } - - public WorldType getApiType() - { - return apiType; - } - - public int getMask() - { - return mask; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java deleted file mode 100644 index a0c71af52c..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/WorldController.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.worlds; - -import java.io.IOException; -import java.util.concurrent.TimeUnit; -import net.runelite.http.api.worlds.WorldResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.CacheControl; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/worlds") -public class WorldController -{ - @Autowired - private WorldsService worldsService; - - private WorldResult worldResult; - - @GetMapping - public ResponseEntity listWorlds() - { - if (worldResult == null) - { - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE) - .cacheControl(CacheControl.noCache()) - .build(); - } - - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) - .body(worldResult); - } - - @Scheduled(fixedDelay = 60_000L) - public void refreshWorlds() throws IOException - { - worldResult = worldsService.getWorlds(); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java b/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java deleted file mode 100644 index 1f8debe7eb..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/worlds/WorldsService.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.worlds; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldResult; -import net.runelite.http.api.worlds.WorldType; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Service -public class WorldsService -{ - private final OkHttpClient okHttpClient; - private final HttpUrl url; - - @Autowired - public WorldsService( - OkHttpClient okHttpClient, - @Value("${runelite.worlds.url}") String url - ) - { - this.okHttpClient = okHttpClient; - this.url = HttpUrl.get(url); - } - - public WorldResult getWorlds() throws IOException - { - Request okrequest = new Request.Builder() - .url(url) - .build(); - - byte[] b; - - try (Response okresponse = okHttpClient.newCall(okrequest).execute()) - { - b = okresponse.body().bytes(); - } - - List worlds = new ArrayList<>(); - ByteBuffer buf = ByteBuffer.wrap(b); - - int length = buf.getInt(); - buf.limit(length + 4); - - int num = buf.getShort() & 0xFFFF; - - for (int i = 0; i < num; ++i) - { - final World.WorldBuilder worldBuilder = World.builder() - .id(buf.getShort() & 0xFFFF) - .types(getTypes(buf.getInt())) - .address(readString(buf)) - .activity(readString(buf)) - .location(buf.get() & 0xFF) - .players(buf.getShort()); - - worlds.add(worldBuilder.build()); - } - - WorldResult result = new WorldResult(); - result.setWorlds(worlds); - return result; - } - - private static EnumSet getTypes(int mask) - { - EnumSet types = EnumSet.noneOf(WorldType.class); - - for (ServiceWorldType type : ServiceWorldType.values()) - { - if ((mask & type.getMask()) != 0) - { - types.add(type.getApiType()); - } - } - - return types; - } - - private static String readString(ByteBuffer buf) - { - byte b; - StringBuilder sb = new StringBuilder(); - - for (;;) - { - b = buf.get(); - - if (b == 0) - { - break; - } - - sb.append((char) b); - } - - return sb.toString(); - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java deleted file mode 100644 index 7c5f2bb5b0..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaCache.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.xtea; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -class XteaCache -{ - private int region; - private int key1; - private int key2; - private int key3; - private int key4; -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java deleted file mode 100644 index 3868acb8c6..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaController.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2018, Adam - * 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.xtea; - -import java.util.List; -import java.util.stream.Collectors; -import net.runelite.http.api.xtea.XteaKey; -import net.runelite.http.api.xtea.XteaRequest; -import net.runelite.http.service.util.exception.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -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; - -@RestController -@RequestMapping("/xtea") -public class XteaController -{ - @Autowired - private XteaService xteaService; - - @RequestMapping(method = POST) - public void submit(@RequestBody XteaRequest xteaRequest) - { - xteaService.submit(xteaRequest); - } - - @GetMapping - public List get() - { - return xteaService.get().stream() - .map(XteaController::entryToKey) - .collect(Collectors.toList()); - } - - @GetMapping("/{region}") - public XteaKey getRegion(@PathVariable int region) - { - XteaEntry xteaRegion = xteaService.getRegion(region); - if (xteaRegion == null) - { - throw new NotFoundException(); - } - - return entryToKey(xteaRegion); - } - - private static XteaKey entryToKey(XteaEntry xe) - { - XteaKey xteaKey = new XteaKey(); - xteaKey.setRegion(xe.getRegion()); - xteaKey.setKeys(new int[] - { - xe.getKey1(), - xe.getKey2(), - xe.getKey3(), - xe.getKey4() - }); - return xteaKey; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java deleted file mode 100644 index c5e60b1119..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.xtea; - -import java.time.Instant; -import lombok.Data; - -@Data -class XteaEntry -{ - private int region; - private Instant time; - private int rev; - private int key1; - private int key2; - private int key3; - private int key4; -} diff --git a/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java b/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java deleted file mode 100644 index 8a5d651b05..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/xtea/XteaService.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.xtea; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import java.io.IOException; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import net.runelite.cache.IndexType; -import net.runelite.cache.fs.Container; -import net.runelite.cache.util.Djb2; -import net.runelite.http.api.xtea.XteaKey; -import net.runelite.http.api.xtea.XteaRequest; -import net.runelite.http.service.cache.CacheService; -import net.runelite.http.service.cache.beans.ArchiveEntry; -import net.runelite.http.service.cache.beans.CacheEntry; -import net.runelite.http.service.util.exception.InternalServerErrorException; -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.Query; -import org.sql2o.Sql2o; - -@Service -@Slf4j -public class XteaService -{ - private static final String CREATE_SQL = "CREATE TABLE IF NOT EXISTS `xtea` (\n" - + " `id` int(11) NOT NULL AUTO_INCREMENT,\n" - + " `region` int(11) NOT NULL,\n" - + " `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" - + " `rev` int(11) NOT NULL,\n" - + " `key1` int(11) NOT NULL,\n" - + " `key2` int(11) NOT NULL,\n" - + " `key3` int(11) NOT NULL,\n" - + " `key4` int(11) NOT NULL,\n" - + " PRIMARY KEY (`id`),\n" - + " KEY `region` (`region`,`time`)\n" - + ") ENGINE=InnoDB"; - - private final Sql2o sql2o; - private final CacheService cacheService; - - private final Cache keyCache = CacheBuilder.newBuilder() - .maximumSize(1024) - .build(); - - @Autowired - public XteaService( - @Qualifier("Runelite SQL2O") Sql2o sql2o, - CacheService cacheService - ) - { - this.sql2o = sql2o; - this.cacheService = cacheService; - - try (Connection con = sql2o.beginTransaction()) - { - con.createQuery(CREATE_SQL) - .executeUpdate(); - } - } - - private XteaEntry findLatestXtea(Connection con, int region) - { - return con.createQuery("select region, time, key1, key2, key3, key4 from xtea " - + "where region = :region " - + "order by time desc " - + "limit 1") - .addParameter("region", region) - .executeAndFetchFirst(XteaEntry.class); - } - - public void submit(XteaRequest xteaRequest) - { - boolean cached = true; - for (XteaKey key : xteaRequest.getKeys()) - { - int region = key.getRegion(); - int[] keys = key.getKeys(); - - if (keys.length != 4) - { - throw new IllegalArgumentException("Key length must be 4"); - } - - XteaCache xteaCache = keyCache.getIfPresent(region); - if (xteaCache == null - || xteaCache.getKey1() != keys[0] - || xteaCache.getKey2() != keys[1] - || xteaCache.getKey3() != keys[2] - || xteaCache.getKey4() != keys[3]) - { - cached = false; - keyCache.put(region, new XteaCache(region, keys[0], keys[1], keys[2], keys[3])); - } - } - - if (cached) - { - return; - } - - try (Connection con = sql2o.beginTransaction()) - { - CacheEntry cache = cacheService.findMostRecent(); - - if (cache == null) - { - throw new InternalServerErrorException("No most recent cache"); - } - - Query query = null; - - for (XteaKey key : xteaRequest.getKeys()) - { - int region = key.getRegion(); - int[] keys = key.getKeys(); - - XteaEntry xteaEntry = findLatestXtea(con, region); - - // already have these? - if (xteaEntry != null - && xteaEntry.getKey1() == keys[0] - && xteaEntry.getKey2() == keys[1] - && xteaEntry.getKey3() == keys[2] - && xteaEntry.getKey4() == keys[3]) - { - continue; - } - - ArchiveEntry archiveEntry = archiveForRegion(cache, region); - if (archiveEntry == null) - { - // the client sends 0,0,0,0 for non-existent regions, just ignore them - continue; - } - - if (!checkKeys(archiveEntry, keys)) - { - continue; - } - - if (query == null) - { - query = con.createQuery("insert into xtea (region, rev, key1, key2, key3, key4) " - + "values (:region, :rev, :key1, :key2, :key3, :key4)"); - } - - query.addParameter("region", region) - .addParameter("rev", xteaRequest.getRevision()) - .addParameter("key1", keys[0]) - .addParameter("key2", keys[1]) - .addParameter("key3", keys[2]) - .addParameter("key4", keys[3]) - .addToBatch(); - - log.debug("Inserted keys for {}: {}, {}, {}, {}", region, keys[0], keys[1], keys[2], keys[3]); - } - - if (query != null) - { - query.executeBatch(); - con.commit(false); - } - } - } - - public List get() - { - try (Connection con = sql2o.open()) - { - return con.createQuery( - "select t1.region, t2.time, t2.rev, t2.key1, t2.key2, t2.key3, t2.key4 from " + - "(select region,max(id) as id from xtea group by region) t1 " + - "join xtea t2 on t1.id = t2.id") - .executeAndFetch(XteaEntry.class); - } - } - - public XteaEntry getRegion(int region) - { - try (Connection con = sql2o.open()) - { - return con.createQuery("select region, time, rev, key1, key2, key3, key4 from xtea " - + "where region = :region order by time desc limit 1") - .addParameter("region", region) - .executeAndFetchFirst(XteaEntry.class); - } - } - - private ArchiveEntry archiveForRegion(CacheEntry cache, int regionId) - { - int x = regionId >>> 8; - int y = regionId & 0xFF; - - String archiveName = new StringBuilder() - .append('l') - .append(x) - .append('_') - .append(y) - .toString(); - int archiveNameHash = Djb2.hash(archiveName); - - return cacheService.findArchiveForTypeAndName(cache, IndexType.MAPS, archiveNameHash); - } - - private boolean checkKeys(ArchiveEntry archiveEntry, int[] keys) - { - byte[] data = cacheService.getArchive(archiveEntry); - if (data == null) - { - throw new InternalServerErrorException("Unable to get archive data for archive " + archiveEntry.getArchiveId()); - } - - try - { - Container.decompress(data, keys); - return true; - } - catch (IOException ex) - { - return false; - } - } -} diff --git a/http-service/src/main/resources/application-dev.yaml b/http-service/src/main/resources/application-dev.yaml deleted file mode 100644 index 2b24790c51..0000000000 --- a/http-service/src/main/resources/application-dev.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Enable debug logging -debug: true -logging.level.net.runelite: DEBUG - -# Development data sources -datasource: - runelite: - jndiName: - driverClassName: org.mariadb.jdbc.Driver - type: org.mariadb.jdbc.MariaDbDataSource - url: jdbc:mariadb://localhost:3306/runelite - username: runelite - password: runelite - runelite-cache: - jndiName: - driverClassName: org.mariadb.jdbc.Driver - type: org.mariadb.jdbc.MariaDbDataSource - url: jdbc:mariadb://localhost:3306/cache - username: runelite - password: runelite - -# Development mongo -mongo: - jndiName: - host: mongodb://localhost:27017 - -# Development oauth callback (without proxy) -oauth: - callback: http://localhost:8080/account/callback diff --git a/http-service/src/main/resources/application.yaml b/http-service/src/main/resources/application.yaml deleted file mode 100644 index 7431545cbb..0000000000 --- a/http-service/src/main/resources/application.yaml +++ /dev/null @@ -1,61 +0,0 @@ -datasource: - runelite: - jndiName: java:comp/env/jdbc/runelite - runelite-cache: - jndiName: java:comp/env/jdbc/runelite-cache2 - -# By default Spring tries to register the datasource as an MXBean, -# so if multiple apis are deployed on one web container with -# shared datasource it tries to register it multiples times and -# fails when starting the 2nd api -spring.jmx.enabled: false - -# Google OAuth client -oauth: - client-id: - client-secret: - callback: https://api.runelite.net/oauth/ - -# Minio client storage for cache -minio: - endpoint: http://localhost:9000 - accesskey: AM54M27O4WZK65N6F8IP - secretkey: /PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP - bucket: runelite - -# Redis client -redis: - pool.size: 10 - host: tcp://localhost:6379 - -mongo: - jndiName: java:comp/env/mongodb/runelite - database: runelite - -runelite: - version: @project.version@ - commit: @git.commit.id.abbrev@ - dirty: @git.dirty@ - # Twitter client for feed - twitter: - consumerkey: - secretkey: - listid: 1185897074786742273 - ge: - history: 90 # days - loottracker: - history: 90 # days - wiki: - poll.ms: 300000 # 5 minutes - url: https://prices.runescape.wiki/api/v1/osrs/latest - price: - cache: 30 # minutes - feed: - rssUrl: https://runelite.net/atom.xml - worlds: - url: http://www.runescape.com/g=oldscape/slr.ws?order=LPWM - osrsnews: - rssUrl: https://services.runescape.com/m=news/latest_news.rss?oldschool=true - item: - itemUrl: https://services.runescape.com/m=itemdb_oldschool/api/catalogue/detail.json - priceUrl: https://services.runescape.com/m=itemdb_oldschool/api/graph \ No newline at end of file diff --git a/http-service/src/main/templates/markdown.hbs b/http-service/src/main/templates/markdown.hbs deleted file mode 100644 index 1beacd052a..0000000000 --- a/http-service/src/main/templates/markdown.hbs +++ /dev/null @@ -1,110 +0,0 @@ -{{#info}} -# {{title}} -{{join schemes " | "}}://{{host}}{{basePath}} - -{{description}} - -{{#contact}} -[**Contact the developer**](mailto:{{email}}) -{{/contact}} - -**Version** {{version}} - -{{#if termsOfService}} -[**Terms of Service**]({{termsOfService}}) -{{/if}} - -{{/info}} - -{{#if consumes}}__Consumes:__ {{join consumes ", "}}{{/if}} - -{{#if produces}}__Produces:__ {{join produces ", "}}{{/if}} - -{{#if securityDefinitions}} -# Security Definitions -{{> security}} -{{/if}} - -
-Table Of Contents -[toc] -
- -# APIs - -{{#each paths}} -## {{@key}} -{{#this}} -{{#get}} -### GET -{{> operation}} -{{/get}} - -{{#put}} -### PUT -{{> operation}} -{{/put}} - -{{#post}} -### POST - -{{> operation}} - -{{/post}} - -{{#delete}} -### DELETE -{{> operation}} -{{/delete}} - -{{#option}} -### OPTION -{{> operation}} -{{/option}} - -{{#patch}} -### PATCH -{{> operation}} -{{/patch}} - -{{#head}} -### HEAD -{{> operation}} -{{/head}} - -{{/this}} -{{/each}} - -# Definitions -{{#each definitions}} -## {{@key}} - - - - - - - - - - {{#each this.properties}} - - - - - - - - {{/each}} -
nametyperequireddescriptionexample
{{@key}} - {{#ifeq type "array"}} - {{#items.$ref}} - {{type}}[{{basename items.$ref}}] - {{/items.$ref}} - {{^items.$ref}}{{type}}[{{items.type}}]{{/items.$ref}} - {{else}} - {{#$ref}}{{basename $ref}}{{/$ref}} - {{^$ref}}{{type}}{{#format}} ({{format}}){{/format}}{{/$ref}} - {{/ifeq}} - {{#required}}required{{/required}}{{^required}}optional{{/required}}{{#description}}{{{description}}}{{/description}}{{^description}}-{{/description}}{{example}}
-{{/each}} diff --git a/http-service/src/main/templates/operation.hbs b/http-service/src/main/templates/operation.hbs deleted file mode 100644 index f7015850b8..0000000000 --- a/http-service/src/main/templates/operation.hbs +++ /dev/null @@ -1,71 +0,0 @@ -{{#deprecated}}-deprecated-{{/deprecated}} -{{summary}} - -{{description}} - -{{#if externalDocs.url}}{{externalDocs.description}}. [See external documents for more details]({{externalDocs.url}}) -{{/if}} - -{{#if security}} -#### Security -{{/if}} - -{{#security}} -{{#each this}} -* {{@key}} -{{#this}} * {{this}} -{{/this}} -{{/each}} -{{/security}} - -#### Request - -{{#if consumes}}__Content-Type:__ {{join consumes ", "}}{{/if}} - -##### Parameters -{{#if parameters}} - - - - - - - - - -{{/if}} - -{{#parameters}} - - - - - - -{{#ifeq in "body"}} - -{{else}} - {{#ifeq type "array"}} - - {{else}} - - {{/ifeq}} -{{/ifeq}} - -{{/parameters}} -{{#if parameters}} -
NameLocated inRequiredDescriptionDefaultSchema
{{name}}{{in}}{{#if required}}yes{{else}}no{{/if}}{{description}}{{#if pattern}} (**Pattern**: `{{pattern}}`){{/if}} - - {{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}} - {{#schema.$ref}}{{basename schema.$ref}} {{/schema.$ref}} - Array[{{items.type}}] ({{collectionFormat}}){{type}} {{#format}}({{format}}){{/format}}
-{{/if}} - - -#### Response - -{{#if produces}}__Content-Type:__ {{join produces ", "}}{{/if}} - -| Status Code | Reason | Response Model | -|-------------|-------------|----------------| -{{#each responses}}| {{@key}} | {{description}} | {{#schema.$ref}}{{basename schema.$ref}}{{/schema.$ref}}{{#ifeq schema.type "array"}}Array[{{basename schema.items.$ref}}]{{/ifeq}}{{^schema}} - {{/schema}}| -{{/each}} diff --git a/http-service/src/main/templates/security.hbs b/http-service/src/main/templates/security.hbs deleted file mode 100644 index 04f86e8380..0000000000 --- a/http-service/src/main/templates/security.hbs +++ /dev/null @@ -1,88 +0,0 @@ -{{#each securityDefinitions}} -### {{@key}} -{{#this}} -{{#ifeq type "oauth2"}} - - - - - -{{#if description}} - - - - -{{/if}} -{{#if authorizationUrl}} - - - - -{{/if}} -{{#if flow}} - - - - -{{/if}} -{{#if tokenUrl}} - - - - -{{/if}} -{{#if scopes}} - - -{{#each scopes}} - - - - -{{/each}} - -{{/if}} -
type{{type}}
description{{description}}
authorizationUrl{{authorizationUrl}}
flow{{flow}}
tokenUrl{{tokenUrl}}
scopes{{@key}}{{this}}
-{{/ifeq}} -{{#ifeq type "apiKey"}} - - - - - -{{#if description}} - - - - -{{/if}} -{{#if name}} - - - - -{{/if}} -{{#if in}} - - - - -{{/if}} -
type{{type}}
description{{description}}
name{{name}}
in{{in}}
-{{/ifeq}} -{{#ifeq type "basic"}} - - - - - -{{#if description}} - - - - -{{/if}} -
type{{type}}
description{{description}}
-{{/ifeq}} -{{/this}} -{{/each}} \ No newline at end of file diff --git a/http-service/src/main/templates/template.html.hbs b/http-service/src/main/templates/template.html.hbs deleted file mode 100644 index da587c2cc4..0000000000 --- a/http-service/src/main/templates/template.html.hbs +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - {{info.title}} {{info.version}} - - - - - \ No newline at end of file diff --git a/http-service/src/main/webapp/WEB-INF/web.xml b/http-service/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 0b07dbb973..0000000000 --- a/http-service/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - RuneLite API - \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java deleted file mode 100644 index 27320f3f72..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/config/ConfigControllerTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@WebMvcTest(ConfigController.class) -@ActiveProfiles("test") -public class ConfigControllerTest -{ - @Autowired - private MockMvc mockMvc; - - @MockBean - private ConfigService configService; - - @MockBean - private AuthFilter authFilter; - - @Before - public void before() throws IOException - { - when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) - .thenReturn(mock(SessionEntry.class)); - - when(configService.setKey(anyInt(), anyString(), anyString())).thenReturn(true); - } - - @Test - public void testSetKey() throws Exception - { - mockMvc.perform(put("/config/key") - .content("value") - .contentType(MediaType.TEXT_PLAIN)) - .andExpect(status().isOk()); - - verify(configService).setKey(anyInt(), eq("key"), eq("value")); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java b/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java deleted file mode 100644 index a08a9a7160..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.config; - -import com.google.common.collect.ImmutableMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import org.junit.Test; - -public class ConfigServiceTest -{ - @Test - public void testParseJsonString() - { - assertEquals(1, ConfigService.parseJsonString("1")); - assertEquals(3.14, ConfigService.parseJsonString("3.14")); - assertEquals(1L << 32, ConfigService.parseJsonString("4294967296")); - assertEquals("test", ConfigService.parseJsonString("test")); - assertEquals("test", ConfigService.parseJsonString("\"test\"")); - assertEquals(ImmutableMap.of("key", "value"), ConfigService.parseJsonString("{\"key\": \"value\"}")); - } - - @Test - public void testValidateJson() - { - assertTrue(ConfigService.validateJson("1")); - assertTrue(ConfigService.validateJson("3.14")); - assertTrue(ConfigService.validateJson("test")); - assertTrue(ConfigService.validateJson("\"test\"")); - assertTrue(ConfigService.validateJson("key:value")); - assertTrue(ConfigService.validateJson("{\"key\": \"value\"}")); - assertTrue(ConfigService.validateJson("\n")); - } - - @Test - public void testMaybeJson() - { - assertFalse(ConfigService.isMaybeJson("string")); - assertFalse(ConfigService.isMaybeJson("string with spaces")); - - assertTrue(ConfigService.isMaybeJson("true")); - assertTrue(ConfigService.isMaybeJson("false")); - assertTrue(ConfigService.isMaybeJson("1")); - assertTrue(ConfigService.isMaybeJson("1.2")); - assertTrue(ConfigService.isMaybeJson("\"quote\"")); - assertTrue(ConfigService.isMaybeJson("{\"key\": \"value\"}")); - assertTrue(ConfigService.isMaybeJson("[42]")); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java b/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java deleted file mode 100644 index 68e64270d6..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/loottracker/LootTrackerControllerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019, Adam - * 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.loottracker; - -import java.io.IOException; -import java.time.Instant; -import java.time.temporal.ChronoField; -import java.util.Collections; -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.loottracker.GameItem; -import net.runelite.http.api.loottracker.LootRecord; -import net.runelite.http.api.loottracker.LootRecordType; -import net.runelite.http.service.account.AuthFilter; -import net.runelite.http.service.account.beans.SessionEntry; -import net.runelite.http.service.util.redis.RedisPool; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import redis.clients.jedis.Jedis; - -@RunWith(SpringRunner.class) -@WebMvcTest(LootTrackerController.class) -@ActiveProfiles("test") -public class LootTrackerControllerTest -{ - @Autowired - private MockMvc mockMvc; - - @MockBean - private LootTrackerService lootTrackerService; - - @MockBean - private AuthFilter authFilter; - - @MockBean - private RedisPool redisPool; - - @Before - public void before() throws IOException - { - when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class))) - .thenReturn(mock(SessionEntry.class)); - - when(redisPool.getResource()).thenReturn(mock(Jedis.class)); - } - - @Test - public void storeLootRecord() throws Exception - { - LootRecord lootRecord = new LootRecord(); - lootRecord.setType(LootRecordType.NPC); - lootRecord.setTime(Instant.now().with(ChronoField.NANO_OF_SECOND, 0)); - lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1))); - - String data = RuneLiteAPI.GSON.toJson(Collections.singletonList(lootRecord)); - mockMvc.perform(post("/loottracker") - .header(RuneLiteAPI.RUNELITE_AUTH, UUID.nameUUIDFromBytes("test".getBytes())) - .content(data) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - - verify(lootTrackerService).store(eq(Collections.singletonList(lootRecord)), anyInt()); - } -} \ No newline at end of file diff --git a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java deleted file mode 100644 index b6275d7c48..0000000000 --- a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * 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.worlds; - -import java.io.IOException; -import java.io.InputStream; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldResult; -import net.runelite.http.api.worlds.WorldType; -import okhttp3.OkHttpClient; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okio.Buffer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sql2o.tools.IOUtils; - -public class WorldsServiceTest -{ - @Rule - public final MockWebServer server = new MockWebServer(); - - @Before - public void before() throws IOException - { - InputStream in = WorldsServiceTest.class.getResourceAsStream("worldlist"); - byte[] worldData = IOUtils.toByteArray(in); - - Buffer buffer = new Buffer(); - buffer.write(worldData); - - server.enqueue(new MockResponse().setBody(buffer)); - } - - @Test - public void testListWorlds() throws Exception - { - WorldsService worlds = new WorldsService(new OkHttpClient(), server.url("/").toString()); - - WorldResult worldResult = worlds.getWorlds(); - assertEquals(82, worldResult.getWorlds().size()); - - World world = worldResult.findWorld(385); - assertNotNull(world); - assertTrue(world.getTypes().contains(WorldType.SKILL_TOTAL)); - - for (World testWorld : worldResult.getWorlds()) - { - assertNotNull("Missing a region in WorldRegion enum", testWorld.getRegion()); - } - } - -} diff --git a/http-service/src/test/resources/application-test.yaml b/http-service/src/test/resources/application-test.yaml deleted file mode 100644 index 3a8e416a54..0000000000 --- a/http-service/src/test/resources/application-test.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Use in-memory database for tests -datasource: - runelite: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:runelite - runelite-cache: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:cache - runelite-tracker: - jndiName: - driverClassName: org.h2.Driver - type: org.h2.jdbcx.JdbcDataSource - url: jdbc:h2:mem:xptracker - -mongo: - jndiName: - host: mongodb://localhost:27017 \ No newline at end of file diff --git a/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist b/http-service/src/test/resources/net/runelite/http/service/worlds/worldlist deleted file mode 100644 index 1d1360e5795d066b068e095cf2a033a504405ad6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5000 zcmeHKOK%%h6uu{Nt&HNnr;&XfUL@?A&0Xv2`>KbrNjykW>2xs2%({goUE2ojRl+UsP2YF3kRF>f)3pl!mq&wAvxSj*vi<` zL+jfJeGeWY1bdoC8M!GddJqr^AHcJOR^c?>rfy383=~o`EgbG-%g){BFW?y(jytE( z4^`J~%Z8WuXg~ztgnJ0Z;z}$8;g*g%lgkR9g4r$CbK^cTzJkXHugooe2$gZDT;KJ# z5d9785>A!3$~+oBz{>`Iajg@H&p1F21Jocycp5{fJHd`3fGmV+CeBADvbNG8Q=gAg+81nq!QO^DM%tc zH84YRq~rOT1m2nR1XRk~LWtMl z2?8qTYY^fMxR-z|?j4iUn{bAJO8M>y@ir_|5ZBq9v=3&$j#M`;+($4^Kz81CLVOIX z1XRx3&dih&0dYfNN^lGwCz$dW(8M2bzu9)u-NWLb!G;%fdpdSwciSv#@4%DfT!$yP zy1S%QDC@Z54Bq;|-nLCR)x1LhZ{@=TRN|n~^~Azc4`7oJ9Bu?UG(mg|W^`uNI=ou5 zV}1u~1XSjxXa=61?0Kqh-a8QA!y^>W{gDj_Pwfn+1K_|vg{*8_w7Fr@Z4pEK3@ao= zi5q7TSJ7xN?r_2eTlg3smkZiQ>aTDSse5UI%lt;=mP-)7LxqI1c!!s9`_+D14&VOS z7COW1M