aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/kr/syeyoung/dungeonsguide/stomp
diff options
context:
space:
mode:
authorsyeyoung <cyong06@naver.com>2021-03-01 21:37:28 +0900
committersyeyoung <cyong06@naver.com>2021-03-01 21:37:28 +0900
commitca37e92e857b8de791f9ddea16743c4139fe9880 (patch)
treefc086d9027ae2cbe46f6504bb98629cb55396bea /src/main/java/kr/syeyoung/dungeonsguide/stomp
parent497512bd3b0f7c2d161b4cc5b7512eeaa07ebdd9 (diff)
downloadSkyblock-Dungeons-Guide-ca37e92e857b8de791f9ddea16743c4139fe9880.tar.gz
Skyblock-Dungeons-Guide-ca37e92e857b8de791f9ddea16743c4139fe9880.tar.bz2
Skyblock-Dungeons-Guide-ca37e92e857b8de791f9ddea16743c4139fe9880.zip
stomp.
Diffstat (limited to 'src/main/java/kr/syeyoung/dungeonsguide/stomp')
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/CloseListener.java5
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClient.java136
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClientStatus.java5
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompHeader.java9
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompInterface.java8
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompMessageHandler.java5
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java69
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/stomp/StompSubscription.java23
8 files changed, 260 insertions, 0 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/CloseListener.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/CloseListener.java
new file mode 100644
index 00000000..a9b21cb7
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/CloseListener.java
@@ -0,0 +1,5 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+public interface CloseListener {
+ void onClose(int code, String reason, boolean remote);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClient.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClient.java
new file mode 100644
index 00000000..248bf04b
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClient.java
@@ -0,0 +1,136 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+import lombok.Getter;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
+import sun.security.ssl.SSLSocketFactoryImpl;
+
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+public class StompClient extends WebSocketClient implements StompInterface {
+ public StompClient(URI serverUri, final String token, CloseListener closeListener) throws Exception {
+ super(serverUri);
+ this.closeListener = closeListener;
+ addHeader("Authorization", token);
+
+ connectBlocking();
+ while(this.stompClientStatus == StompClientStatus.CONNECTING);
+ }
+ private CloseListener closeListener;
+
+ @Getter
+ private volatile StompClientStatus stompClientStatus = StompClientStatus.CONNECTING;
+
+ @Getter
+ private StompPayload errorPayload;
+
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ send(new StompPayload().method(StompHeader.CONNECT)
+ .header("accept-version","1.2")
+ .header("host",uri.getHost()).getBuilt()
+ );
+ }
+
+ @Override
+ public void onMessage(String message) {
+ try {
+ StompPayload payload = StompPayload.parse(message);
+ if (payload.method() == StompHeader.CONNECTED) {
+ stompClientStatus = StompClientStatus.CONNECTED;
+ } else if (payload.method() == StompHeader.ERROR) {
+ errorPayload = payload;
+ stompClientStatus = StompClientStatus.ERROR;
+ this.close();
+ } else if (payload.method() == StompHeader.MESSAGE) {
+ // mesage
+ StompSubscription stompSubscription = stompSubscriptionMap.get(Integer.parseInt(payload.headers().get("subscription")));
+ try {
+ stompSubscription.getStompMessageHandler().handle(this, payload);
+ if (stompSubscription.getAckMode() != StompSubscription.AckMode.AUTO) {
+ send(new StompPayload().method(StompHeader.ACK)
+ .header("id",payload.headers().get("ack")).getBuilt()
+ );
+ }
+ } catch (Exception e) {
+ send(new StompPayload().method(StompHeader.NACK)
+ .header("id",payload.headers().get("ack")).getBuilt()
+ );
+ e.printStackTrace();
+ }
+ } else if (payload.method() == StompHeader.RECEIPT) {
+ String receipt_id = payload.headers().get("receipt-id");
+ StompPayload payload1 = receiptMap.remove(Integer.parseInt(receipt_id));
+ if (payload1.method() == StompHeader.DISCONNECT) {
+ stompClientStatus = StompClientStatus.DISCONNECTED;
+ close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ closeListener.onClose(code, reason, remote);
+ }
+
+ @Override
+ public void onError(Exception ex) {
+
+ }
+
+ private Map<Integer, StompSubscription> stompSubscriptionMap = new HashMap<Integer, StompSubscription>();
+ private Map<Integer, StompPayload> receiptMap = new HashMap<Integer, StompPayload>();
+
+ private int idIncrement = 0;
+
+ @Override
+ public void send(StompPayload payload) {
+ if (stompClientStatus != StompClientStatus.CONNECTED) throw new IllegalStateException("not connected");
+ payload.method(StompHeader.SEND);
+ if (payload.headers().get("receipt") != null)
+ receiptMap.put(Integer.parseInt(payload.headers().get("receipt")), payload);
+ send(payload);
+ }
+
+ @Override
+ public void subscribe(StompSubscription stompSubscription) {
+ if (stompClientStatus != StompClientStatus.CONNECTED) throw new IllegalStateException("not connected");
+ stompSubscription.setId(++idIncrement);
+
+ send(new StompPayload().method(StompHeader.SUBSCRIBE)
+ .header("id",String.valueOf(stompSubscription.getId()))
+ .header("destination", stompSubscription.getDestination())
+ .header("ack", stompSubscription.getAckMode().getValue()).getBuilt()
+ );
+
+ stompSubscriptionMap.put(stompSubscription.getId(), stompSubscription);
+ }
+
+ @Override
+ public void unsubscribe(StompSubscription stompSubscription) {
+ if (stompClientStatus != StompClientStatus.CONNECTED) throw new IllegalStateException("not connected");
+ send(new StompPayload().method(StompHeader.UNSUBSCRIBE)
+ .header("id",String.valueOf(stompSubscription.getId())).getBuilt()
+ );
+ stompSubscriptionMap.remove(stompSubscription.getId());
+ }
+
+ @Override
+ public void disconnect() {
+ if (stompClientStatus != StompClientStatus.CONNECTED) throw new IllegalStateException("not connected");
+ StompPayload stompPayload;
+ stompClientStatus =StompClientStatus.DISCONNECTING;
+ send((stompPayload = new StompPayload().method(StompHeader.DISCONNECT)
+ .header("receipt", String.valueOf(++idIncrement)))
+ .getBuilt()
+ );
+ receiptMap.put(idIncrement, stompPayload);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClientStatus.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClientStatus.java
new file mode 100644
index 00000000..b3f5cbc2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompClientStatus.java
@@ -0,0 +1,5 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+public enum StompClientStatus {
+ CONNECTING, CONNECTED, ERROR, DISCONNECTING, DISCONNECTED;
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompHeader.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompHeader.java
new file mode 100644
index 00000000..0e9c4311
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompHeader.java
@@ -0,0 +1,9 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+
+public enum StompHeader {
+ SEND, SUBSCRIBE, UNSUBSCRIBE, BEGIN, COMMIT, ABORT, ACK, NACK, DISCONNECT, CONNECT, STOMP, CONNECTED, MESSAGE, RECEIPT, ERROR
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompInterface.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompInterface.java
new file mode 100644
index 00000000..e78f8ceb
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompInterface.java
@@ -0,0 +1,8 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+public interface StompInterface {
+ void send(StompPayload payload);
+ void subscribe(StompSubscription stompSubscription);
+ void unsubscribe(StompSubscription stompSubscription);
+ void disconnect();
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompMessageHandler.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompMessageHandler.java
new file mode 100644
index 00000000..7b13c1fd
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompMessageHandler.java
@@ -0,0 +1,5 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+public interface StompMessageHandler {
+ void handle(StompInterface stompInterface, StompPayload stompPayload);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java
new file mode 100644
index 00000000..9476241c
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java
@@ -0,0 +1,69 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+import lombok.Data;
+import lombok.Singular;
+import lombok.experimental.Accessors;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+@Data
+@Accessors(chain = true, fluent = true)
+public class StompPayload {
+ private StompHeader method;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String payload;
+
+ public StompPayload header(String key, String value) {
+ headers.put(key, value);
+ return this;
+ }
+
+ public String getBuilt() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(method.name());
+ sb.append("\n");
+ for (Map.Entry<String, String> stringStringEntry : headers.entrySet()) {
+ sb.append(stringStringEntry.getKey());
+ sb.append(":");
+ sb.append(stringStringEntry.getValue());
+ sb.append("\n");
+ if (stringStringEntry.getKey().contains(":")) throw new IllegalStateException("Illegal Character : inside headers");
+ if (stringStringEntry.getValue().contains(":")) throw new IllegalStateException("Illegal Character : inside headers");
+ }
+ sb.append("\n");
+ if (payload != null)
+ sb.append(payload);
+ sb.append((char) 0);
+ System.out.println("Probably sending "+sb.toString());
+ return sb.toString();
+ }
+
+ public static StompPayload parse(String payload) {
+ System.out.println("Parsing "+payload);
+ Scanner scanner = new Scanner(payload);
+ StompPayload stompPayload = new StompPayload();
+ stompPayload.method = StompHeader.valueOf(scanner.nextLine());
+ String line = "";
+ while (!(line = scanner.nextLine()).isEmpty()) {
+ int index = line.indexOf(":");
+ if (index == -1) throw new IllegalArgumentException("No : found in headers section");
+ String name = line.substring(0, index);
+ String value;
+ if (index == line.length() - 1)
+ value = "";
+ else
+ value = line.substring(index+1);
+ stompPayload.headers.put(name, value);
+ }
+
+ StringBuilder payloadBuilder = new StringBuilder();
+ while (scanner.hasNextLine() && !(line = scanner.nextLine()).equals("\0")) {
+ payloadBuilder.append(line);
+ payloadBuilder.append("\n");
+ }
+ stompPayload.payload = payloadBuilder.toString();
+ return stompPayload;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompSubscription.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompSubscription.java
new file mode 100644
index 00000000..5ecbeb06
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompSubscription.java
@@ -0,0 +1,23 @@
+package kr.syeyoung.dungeonsguide.stomp;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+
+@Data
+@Builder
+public class StompSubscription {
+ private int id;
+ private String destination;
+ private StompMessageHandler stompMessageHandler;
+ private AckMode ackMode;
+
+ @AllArgsConstructor
+ public static enum AckMode {
+ AUTO("auto"), CLIENT("client"), CLIENT_INDIVIDUAL("client-individual");
+
+ @Getter
+ private String value;
+ }
+}