diff --git a/pom.xml b/pom.xml index ba4ac22..53f75ed 100644 --- a/pom.xml +++ b/pom.xml @@ -9,9 +9,9 @@ - org.json - json - 20190722 + com.google.code.gson + gson + 2.8.6 com.kohlschutter.junixsocket diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 9e4b291..ae0d1b2 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -16,7 +16,7 @@ public void onReady(IPCClient client) { RichPresence.Builder builder = new RichPresence.Builder(); builder.setState("Testing RPC Data...") .setDetails("$DETAILS_HERE") - .setStartTimestamp(OffsetDateTime.now()) + .setStartTimestamp(OffsetDateTime.now().toEpochSecond()) .setLargeImage("success", "Test Successful"); client.sendRichPresence(builder.build()); } diff --git a/src/main/java/com/jagrosh/discordipc/IPCClient.java b/src/main/java/com/jagrosh/discordipc/IPCClient.java index c576d2b..0fc35bf 100644 --- a/src/main/java/com/jagrosh/discordipc/IPCClient.java +++ b/src/main/java/com/jagrosh/discordipc/IPCClient.java @@ -15,13 +15,13 @@ */ package com.jagrosh.discordipc; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.jagrosh.discordipc.entities.*; import com.jagrosh.discordipc.entities.Packet.OpCode; import com.jagrosh.discordipc.entities.pipe.Pipe; import com.jagrosh.discordipc.entities.pipe.PipeStatus; import com.jagrosh.discordipc.exceptions.NoDiscordClientException; -import org.json.JSONException; -import org.json.JSONObject; import java.io.Closeable; import java.io.IOException; @@ -222,11 +222,17 @@ public void sendRichPresence(RichPresence presence, Callback callback) { System.out.println("Sending RichPresence to discord: " + (presence == null ? null : presence.toJson().toString())); } - pipe.send(OpCode.FRAME, new JSONObject() - .put("cmd", "SET_ACTIVITY") - .put("args", new JSONObject() - .put("pid", getPID()) - .put("activity", presence == null ? null : presence.toJson())), callback); + // Setup and Send JsonObject Data Representing an RPC Update + JsonObject finalObject = new JsonObject(), + args = new JsonObject(); + + finalObject.addProperty("cmd", "SET_ACTIVITY"); + + args.addProperty("pid", getPID()); + args.add("activity", presence == null ? new JsonObject() : presence.toJson()); + + finalObject.add("args", args); + pipe.send(OpCode.FRAME, finalObject, callback); } /** @@ -267,9 +273,11 @@ public void subscribe(Event sub, Callback callback) { System.out.println(String.format("Subscribing to Event: %s", sub.name())); } - pipe.send(OpCode.FRAME, new JSONObject() - .put("cmd", "SUBSCRIBE") - .put("evt", sub.name()), callback); + JsonObject pipeData = new JsonObject(); + pipeData.addProperty("cmd", "SUBSCRIBE"); + pipeData.addProperty("evt", sub.name()); + + pipe.send(OpCode.FRAME, pipeData, callback); } public void respondToJoinRequest(User user, ApprovalMode approvalMode, Callback callback) { @@ -280,10 +288,15 @@ public void respondToJoinRequest(User user, ApprovalMode approvalMode, Callback System.out.println(String.format("Sending response to %s as %s", user.getName(), approvalMode.name())); } - pipe.send(OpCode.FRAME, new JSONObject() - .put("cmd", approvalMode == ApprovalMode.ACCEPT ? "SEND_ACTIVITY_JOIN_INVITE" : "CLOSE_ACTIVITY_REQUEST") - .put("args", new JSONObject() - .put("user_id", user.getId())), callback); + JsonObject pipeData = new JsonObject(); + pipeData.addProperty("cmd", approvalMode == ApprovalMode.ACCEPT ? "SEND_ACTIVITY_JOIN_INVITE" : "CLOSE_ACTIVITY_REQUEST"); + + JsonObject args = new JsonObject(); + args.addProperty("user_id", user.getId()); + + pipeData.add("args", args); + + pipe.send(OpCode.FRAME, pipeData, callback); } } @@ -383,77 +396,82 @@ private void startReading() { try { Packet p; while ((p = pipe.read()).getOp() != OpCode.CLOSE) { - JSONObject json = p.getJson(); - Event event = Event.of(json.optString("evt", null)); - String nonce = json.optString("nonce", null); - switch (event) { - case NULL: - if (nonce != null && callbacks.containsKey(nonce)) - callbacks.remove(nonce).succeed(p); - break; - - case ERROR: - if (nonce != null && callbacks.containsKey(nonce)) - callbacks.remove(nonce).fail(json.getJSONObject("data").optString("message", null)); - break; - - case ACTIVITY_JOIN: - if (debugMode) { - System.out.println("Reading thread received a 'join' event."); - } - break; - - case ACTIVITY_SPECTATE: - if (debugMode) { - System.out.println("Reading thread received a 'spectate' event."); - } - break; - - case ACTIVITY_JOIN_REQUEST: - if (debugMode) { - System.out.println("Reading thread received a 'join request' event."); - } - break; + JsonObject json = p.getJson(); + + if (json != null) { + Event event = Event.of(json.has("evt") && !json.get("evt").isJsonNull() ? json.getAsJsonPrimitive("evt").getAsString() : null); + String nonce = json.has("nonce") && !json.get("nonce").isJsonNull() ? json.getAsJsonPrimitive("nonce").getAsString() : null; + + switch (event) { + case NULL: + if (nonce != null && callbacks.containsKey(nonce)) + callbacks.remove(nonce).succeed(p); + break; + + case ERROR: + if (nonce != null && callbacks.containsKey(nonce)) + callbacks.remove(nonce).fail(json.has("data") && json.getAsJsonObject("data").has("message") ? json.getAsJsonObject("data").getAsJsonObject("message").getAsString() : null); + break; + + case ACTIVITY_JOIN: + if (debugMode) { + System.out.println("Reading thread received a 'join' event."); + } + break; + + case ACTIVITY_SPECTATE: + if (debugMode) { + System.out.println("Reading thread received a 'spectate' event."); + } + break; + + case ACTIVITY_JOIN_REQUEST: + if (debugMode) { + System.out.println("Reading thread received a 'join request' event."); + } + break; + + case UNKNOWN: + if (debugMode) { + System.out.println("Reading thread encountered an event with an unknown type: " + + json.getAsJsonPrimitive("evt").getAsString()); + } + break; + } - case UNKNOWN: - if (debugMode) { - System.out.println("Reading thread encountered an event with an unknown type: " + - json.getString("evt")); - } - break; - } - if (listener != null && json.has("cmd") && json.getString("cmd").equals("DISPATCH")) { - try { - JSONObject data = json.getJSONObject("data"); - switch (Event.of(json.getString("evt"))) { - case ACTIVITY_JOIN: - listener.onActivityJoin(localInstance, data.getString("secret")); - break; - - case ACTIVITY_SPECTATE: - listener.onActivitySpectate(localInstance, data.getString("secret")); - break; - - case ACTIVITY_JOIN_REQUEST: - JSONObject u = data.getJSONObject("user"); - User user = new User( - u.getString("username"), - u.getString("discriminator"), - Long.parseLong(u.getString("id")), - u.optString("avatar", null) - ); - listener.onActivityJoinRequest(localInstance, data.optString("secret", null), user); - break; + if (listener != null && json.has("cmd") && json.getAsJsonPrimitive("cmd").getAsString().equals("DISPATCH")) { + try { + JsonObject data = json.getAsJsonObject("data"); + switch (Event.of(json.getAsJsonPrimitive("evt").getAsString())) { + case ACTIVITY_JOIN: + listener.onActivityJoin(localInstance, data.getAsJsonObject("secret").getAsString()); + break; + + case ACTIVITY_SPECTATE: + listener.onActivitySpectate(localInstance, data.getAsJsonObject("secret").getAsString()); + break; + + case ACTIVITY_JOIN_REQUEST: + final JsonObject u = data.getAsJsonObject("user"); + final User user = new User( + u.getAsJsonPrimitive("username").getAsString(), + u.getAsJsonPrimitive("discriminator").getAsString(), + Long.parseLong(u.getAsJsonPrimitive("id").getAsString()), + u.has("avatar") ? u.getAsJsonPrimitive("avatar").getAsString() : null + ); + listener.onActivityJoinRequest(localInstance, data.has("secret") ? data.getAsJsonObject("secret").getAsString() : null, user); + break; + } + } catch (Exception e) { + System.out.println(String.format("Exception when handling event: %s", e)); } - } catch (Exception e) { - System.out.println(String.format("Exception when handling event: %s", e)); } } } pipe.setStatus(PipeStatus.DISCONNECTED); if (listener != null) listener.onClose(localInstance, p.getJson()); - } catch (IOException | JSONException ex) { + } catch (IOException | JsonParseException ex) { if (ex instanceof IOException) System.out.println(String.format("Reading thread encountered an IOException: %s", ex)); else diff --git a/src/main/java/com/jagrosh/discordipc/IPCListener.java b/src/main/java/com/jagrosh/discordipc/IPCListener.java index 4c92bd1..bfacf4b 100644 --- a/src/main/java/com/jagrosh/discordipc/IPCListener.java +++ b/src/main/java/com/jagrosh/discordipc/IPCListener.java @@ -15,9 +15,9 @@ */ package com.jagrosh.discordipc; +import com.google.gson.JsonObject; import com.jagrosh.discordipc.entities.Packet; import com.jagrosh.discordipc.entities.User; -import org.json.JSONObject; /** * An implementable listener used to handle events caught by an {@link IPCClient}.

@@ -91,9 +91,9 @@ default void onReady(IPCClient client) { * Fired whenever an {@link IPCClient} has closed. * * @param client The now closed IPCClient. - * @param json A {@link JSONObject} with close data. + * @param json A {@link JsonObject} with close data. */ - default void onClose(IPCClient client, JSONObject json) { + default void onClose(IPCClient client, JsonObject json) { } /** diff --git a/src/main/java/com/jagrosh/discordipc/entities/Packet.java b/src/main/java/com/jagrosh/discordipc/entities/Packet.java index 29d73ac..8fe3e33 100644 --- a/src/main/java/com/jagrosh/discordipc/entities/Packet.java +++ b/src/main/java/com/jagrosh/discordipc/entities/Packet.java @@ -15,7 +15,7 @@ */ package com.jagrosh.discordipc.entities; -import org.json.JSONObject; +import com.google.gson.JsonObject; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; @@ -28,30 +28,30 @@ */ public class Packet { private final OpCode op; - private final JSONObject data; + private final JsonObject data; private final String encoding; /** - * Constructs a new Packet using an {@link OpCode} and {@link JSONObject}. + * Constructs a new Packet using an {@link OpCode} and {@link JsonObject}. * * @param op The OpCode value of this new Packet. * @param data The JSONObject payload of this new Packet. * @param encoding encoding to send packets as */ - public Packet(OpCode op, JSONObject data, String encoding) { + public Packet(OpCode op, JsonObject data, String encoding) { this.op = op; this.data = data; this.encoding = encoding; } /** - * Constructs a new Packet using an {@link OpCode} and {@link JSONObject}. + * Constructs a new Packet using an {@link OpCode} and {@link JsonObject}. * * @param op The OpCode value of this new Packet. * @param data The JSONObject payload of this new Packet. */ @Deprecated - public Packet(OpCode op, JSONObject data) { + public Packet(OpCode op, JsonObject data) { this(op, data, "UTF-8"); } @@ -87,11 +87,11 @@ public OpCode getOp() { } /** - * Gets the {@link JSONObject} value as a part of this {@link Packet}. + * Gets the {@link JsonObject} value as a part of this {@link Packet}. * * @return The JSONObject value of this Packet. */ - public JSONObject getJson() { + public JsonObject getJson() { return data; } diff --git a/src/main/java/com/jagrosh/discordipc/entities/RichPresence.java b/src/main/java/com/jagrosh/discordipc/entities/RichPresence.java index 45dcfeb..0e23b26 100644 --- a/src/main/java/com/jagrosh/discordipc/entities/RichPresence.java +++ b/src/main/java/com/jagrosh/discordipc/entities/RichPresence.java @@ -15,10 +15,9 @@ */ package com.jagrosh.discordipc.entities; -import org.json.JSONArray; -import org.json.JSONObject; - -import java.time.OffsetDateTime; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; /** * An encapsulation of all data needed to properly construct a JSON RichPresence payload. @@ -30,8 +29,8 @@ public class RichPresence { private final String state; private final String details; - private final OffsetDateTime startTimestamp; - private final OffsetDateTime endTimestamp; + private final long startTimestamp; + private final long endTimestamp; private final String largeImageKey; private final String largeImageText; private final String smallImageKey; @@ -44,7 +43,7 @@ public class RichPresence { private final String spectateSecret; private final boolean instance; - public RichPresence(String state, String details, OffsetDateTime startTimestamp, OffsetDateTime endTimestamp, + public RichPresence(String state, String details, long startTimestamp, long endTimestamp, String largeImageKey, String largeImageText, String smallImageKey, String smallImageText, String partyId, int partySize, int partyMax, String matchSecret, String joinSecret, String spectateSecret, boolean instance) { @@ -66,7 +65,7 @@ public RichPresence(String state, String details, OffsetDateTime startTimestamp, } /** - * Constructs a {@link JSONObject} representing a payload to send to discord + * Constructs a {@link JsonObject} representing a payload to send to discord * to update a user's Rich Presence. * *

This is purely internal, and should not ever need to be called outside of @@ -74,26 +73,83 @@ public RichPresence(String state, String details, OffsetDateTime startTimestamp, * * @return A JSONObject payload for updating a user's Rich Presence. */ - public JSONObject toJson() { - return new JSONObject() - .put("state", state) - .put("details", details) - .put("timestamps", new JSONObject() - .put("start", startTimestamp == null ? null : startTimestamp.toEpochSecond()) - .put("end", endTimestamp == null ? null : endTimestamp.toEpochSecond())) - .put("assets", new JSONObject() - .put("large_image", largeImageKey) - .put("large_text", largeImageText) - .put("small_image", smallImageKey) - .put("small_text", smallImageText)) - .put("party", partyId == null ? null : new JSONObject() - .put("id", partyId) - .put("size", new JSONArray().put(partySize).put(partyMax))) - .put("secrets", new JSONObject() - .put("join", joinSecret) - .put("spectate", spectateSecret) - .put("match", matchSecret)) - .put("instance", instance); + public JsonObject toJson() { + JsonObject timestamps = new JsonObject(), + assets = new JsonObject(), + party = new JsonObject(), + secrets = new JsonObject(), + finalObject = new JsonObject(); + + if (startTimestamp > 0) { + timestamps.addProperty("start", startTimestamp); + + if (endTimestamp > startTimestamp) { + timestamps.addProperty("end", endTimestamp); + } + } + + if (largeImageKey != null && !largeImageKey.isEmpty()) { + assets.addProperty("large_image", largeImageKey); + + if (largeImageText != null && !largeImageText.isEmpty()) { + assets.addProperty("large_text", largeImageText); + } + } + + if (smallImageKey != null && !smallImageKey.isEmpty()) { + assets.addProperty("small_image", smallImageKey); + + if (smallImageText != null && !smallImageText.isEmpty()) { + assets.addProperty("small_text", smallImageText); + } + } + + if (partyId != null) { + party.addProperty("id", partyId); + + JsonArray partyData = new JsonArray(); + + if (partySize > 0) { + partyData.add(new JsonPrimitive(partySize)); + + if (partyMax >= partySize) { + partyData.add(new JsonPrimitive(partyMax)); + } + } + party.add("size", partyData); + } + + if (joinSecret != null && !joinSecret.isEmpty()) { + secrets.addProperty("join", joinSecret); + } + if (spectateSecret != null && !spectateSecret.isEmpty()) { + secrets.addProperty("spectate", spectateSecret); + } + if (matchSecret != null && !matchSecret.isEmpty()) { + secrets.addProperty("match", matchSecret); + } + + if (state != null && !state.isEmpty()) { + finalObject.addProperty("state", state); + } + if (details != null && !details.isEmpty()) { + finalObject.addProperty("details", details); + } + if (timestamps.has("start")) { + finalObject.add("timestamps", timestamps); + } + if (assets.has("large_image")) { + finalObject.add("assets", assets); + } + if (party.has("id")) { + finalObject.add("party", party); + } + if (secrets.has("join") || secrets.has("spectate") || secrets.has("match")) { + finalObject.add("secrets", secrets); + } + finalObject.addProperty("instance", instance); + + return finalObject; } /** @@ -105,8 +161,8 @@ public JSONObject toJson() { public static class Builder { private String state; private String details; - private OffsetDateTime startTimestamp; - private OffsetDateTime endTimestamp; + private long startTimestamp; + private long endTimestamp; private String largeImageKey; private String largeImageText; private String smallImageKey; @@ -159,7 +215,7 @@ public Builder setDetails(String details) { * @param startTimestamp The time the player started a match or activity. * @return This Builder. */ - public Builder setStartTimestamp(OffsetDateTime startTimestamp) { + public Builder setStartTimestamp(long startTimestamp) { this.startTimestamp = startTimestamp; return this; } @@ -170,7 +226,7 @@ public Builder setStartTimestamp(OffsetDateTime startTimestamp) { * @param endTimestamp The time the player's activity will end. * @return This Builder. */ - public Builder setEndTimestamp(OffsetDateTime endTimestamp) { + public Builder setEndTimestamp(long endTimestamp) { this.endTimestamp = endTimestamp; return this; } diff --git a/src/main/java/com/jagrosh/discordipc/entities/pipe/Pipe.java b/src/main/java/com/jagrosh/discordipc/entities/pipe/Pipe.java index b053bf9..0075a5e 100644 --- a/src/main/java/com/jagrosh/discordipc/entities/pipe/Pipe.java +++ b/src/main/java/com/jagrosh/discordipc/entities/pipe/Pipe.java @@ -16,6 +16,9 @@ package com.jagrosh.discordipc.entities.pipe; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; import com.jagrosh.discordipc.IPCClient; import com.jagrosh.discordipc.IPCListener; import com.jagrosh.discordipc.entities.Callback; @@ -23,8 +26,6 @@ import com.jagrosh.discordipc.entities.Packet; import com.jagrosh.discordipc.entities.User; import com.jagrosh.discordipc.exceptions.NoDiscordClientException; -import org.json.JSONException; -import org.json.JSONObject; import java.io.IOException; import java.util.HashMap; @@ -65,22 +66,28 @@ public static Pipe openPipe(IPCClient ipcClient, long clientId, HashMap