diff --git a/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java b/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java index f5aa844..d2dc6d2 100644 --- a/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java +++ b/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java @@ -9,11 +9,13 @@ import io.github.chronosx88.JGUN.storageBackends.StorageBackend; import org.java_websocket.client.WebSocketClient; import org.json.JSONObject; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Dispatcher { private final Map> pendingFutures = new ConcurrentHashMap<>(); + private final Map changeListeners = new HashMap<>(); private final Peer peer; private final StorageBackend graphStorage; private final Dup dup; @@ -40,6 +42,7 @@ public class Dispatcher { if(message.has("@")) { handleIncomingAck(message); } + peer.emit(message.toString()); } private JSONObject handleGet(JSONObject getData) { @@ -52,7 +55,14 @@ public class Dispatcher { } private JSONObject handlePut(JSONObject message) { - HAM.mix(new InMemoryGraph(message.getJSONObject("put")), graphStorage); + InMemoryGraph diff = HAM.mix(new InMemoryGraph(message.getJSONObject("put")), graphStorage); + if(diff != null) { + for(Map.Entry entry : diff.entries()) { + if(changeListeners.containsKey(entry.getKey())) { + changeListeners.get(entry.getKey()).onChange(entry.getValue().toUserJSONObject()); + } + } + } return new JSONObject() // Acknowledgment .put( "#", dup.track(Dup.random()) ) .put( "@", message.getString("#") ) @@ -64,7 +74,7 @@ public class Dispatcher { if(pendingFutures.containsKey(ack.getString("@"))) { BaseCompletableFuture future = pendingFutures.get(ack.getString("@")); if(future instanceof FutureGet) { - ((FutureGet) future).complete(ack.getJSONObject("put")); + ((FutureGet) future).complete(new InMemoryGraph(ack.getJSONObject("put")).toUserJSONObject()); } } } @@ -91,4 +101,8 @@ public class Dispatcher { peer.emit(jsonGet.toString()); }).start(); } + + public void addChangeListener(String soul, NodeChangeListener listener) { + changeListeners.put(soul, listener); + } } diff --git a/src/main/java/io/github/chronosx88/JGUN/Node.java b/src/main/java/io/github/chronosx88/JGUN/Node.java index 43e44fe..46b1634 100644 --- a/src/main/java/io/github/chronosx88/JGUN/Node.java +++ b/src/main/java/io/github/chronosx88/JGUN/Node.java @@ -73,4 +73,8 @@ public class Node implements Comparable { soul = metadata.getJSONObject("_").getString("#"); states = metadata.getJSONObject("_").getJSONObject(">"); } + + public JSONObject toUserJSONObject() { + return values; + } } \ No newline at end of file diff --git a/src/main/java/io/github/chronosx88/JGUN/NodeChangeListener.java b/src/main/java/io/github/chronosx88/JGUN/NodeChangeListener.java new file mode 100644 index 0000000..dba0523 --- /dev/null +++ b/src/main/java/io/github/chronosx88/JGUN/NodeChangeListener.java @@ -0,0 +1,8 @@ +package io.github.chronosx88.JGUN; + +import org.json.JSONObject; + +@FunctionalInterface +public interface NodeChangeListener { + void onChange(JSONObject node); +} diff --git a/src/main/java/io/github/chronosx88/JGUN/PathRef.java b/src/main/java/io/github/chronosx88/JGUN/PathRef.java index 27b5f68..9e5981e 100644 --- a/src/main/java/io/github/chronosx88/JGUN/PathRef.java +++ b/src/main/java/io/github/chronosx88/JGUN/PathRef.java @@ -95,4 +95,8 @@ public class PathRef { dispatcher.sendPutRequest(futurePut.getFutureID(), temp); return futurePut; } + + public void on(NodeChangeListener changeListener) { + dispatcher.addChangeListener(String.join("/", path), changeListener); + } } diff --git a/src/main/java/io/github/chronosx88/JGUN/examples/MainClientServer.java b/src/main/java/io/github/chronosx88/JGUN/examples/MainClientServer.java index 8800ca8..903ea15 100644 --- a/src/main/java/io/github/chronosx88/JGUN/examples/MainClientServer.java +++ b/src/main/java/io/github/chronosx88/JGUN/examples/MainClientServer.java @@ -21,25 +21,27 @@ public class MainClientServer { } catch (UnknownHostException e) { e.printStackTrace(); } + gun.get("random").on(data -> { + if(data != null) { + System.out.println("New change in \"random\"! " + data.toString(2)); + } + }); + gun.get("random").get("dVFtzE9CL").on(data -> { + if(data != null) { + System.out.println("New change in \"random/dVFtzE9CL\"! " + data.toString(2)); + } else { + System.out.println("Now random/dVFtzE9CL is null!"); + } + + }); FuturePut futurePut = gun.get("random").get("dVFtzE9CL").put(new JSONObject().put("hello", "world")); boolean success = futurePut.await(); System.out.println("[FuturePut] Success: " + success); - FutureGet futureGet = gun.get("random").get("dVFtzE9CL").getData(); - JSONObject result = futureGet.await(); - System.out.println("[FutureGet] Result of get: " + result.toString(2)); FuturePut futurePut1 = gun.get("random").get("dVFtzE9CL").put(new JSONObject().put("hello", "123")); System.out.println("[FuturePut1] Putting an item again: " + futurePut1.await()); - FutureGet futureGet1 = gun.get("random").get("dVFtzE9CL").getData(); - JSONObject result1 = futureGet1.await(); - System.out.println("[FutureGet] Result of get: " + result1.toString(2)); System.out.println("Deleting an item random/dVFtzE9CL"); gun.get("random").get("dVFtzE9CL").put(null).await(); - JSONObject resultNull = gun.get("random").get("dVFtzE9CL").getData().await(); - if(resultNull == null) { - System.out.println("Now random/dVFtzE9CL is null!"); - } gun.get("random").put(new JSONObject().put("hello", "world")).await(); - System.out.println(gun.get("random").getData().await().toString(2)); }).start(); } diff --git a/src/main/java/io/github/chronosx88/JGUN/storageBackends/InMemoryGraph.java b/src/main/java/io/github/chronosx88/JGUN/storageBackends/InMemoryGraph.java index 87f4e2e..5f781d2 100644 --- a/src/main/java/io/github/chronosx88/JGUN/storageBackends/InMemoryGraph.java +++ b/src/main/java/io/github/chronosx88/JGUN/storageBackends/InMemoryGraph.java @@ -63,6 +63,14 @@ public class InMemoryGraph implements StorageBackend { return jsonObject; } + public JSONObject toUserJSONObject() { + JSONObject jsonObject = new JSONObject(); + for(Map.Entry entry : nodes.entrySet()) { + jsonObject.put(entry.getKey(), entry.getValue().toUserJSONObject()); + } + return jsonObject; + } + public boolean isEmpty() { return nodes.isEmpty(); }