Implemented key-lookup

This commit is contained in:
ChronosX88 2019-05-03 20:52:05 +04:00
parent 33574c69a5
commit 791f29a177
8 changed files with 182 additions and 38 deletions

View File

@ -10,6 +10,7 @@ import java.net.URISyntaxException;
public class Client extends WebSocketClient { public class Client extends WebSocketClient {
private Dup dup = new Dup(); private Dup dup = new Dup();
private Graph graph = new Graph();
public Client(InetAddress address, int port) throws URISyntaxException { public Client(InetAddress address, int port) throws URISyntaxException {
super(new URI("ws://" + address.getHostAddress() + ":" + port)); super(new URI("ws://" + address.getHostAddress() + ":" + port));
@ -20,23 +21,33 @@ public class Client extends WebSocketClient {
System.out.println("Connection open. Status: " + handshakeData.getHttpStatus()); System.out.println("Connection open. Status: " + handshakeData.getHttpStatus());
Utils.setTimeout(() -> { Utils.setTimeout(() -> {
JSONObject msg = new JSONObject(); JSONObject msg = new JSONObject();
msg.put("#", dup.track(Dup.random(3))); msg
.put("#", dup.track(Dup.random()))
.put("get", new JSONObject()
.put("#", "FDSA")
.put(".", "species"));
this.send(msg.toString());
}, 2000);
Utils.setTimeout(() -> {
JSONObject msg = new JSONObject();
msg.put("#", dup.track(Dup.random()));
msg.put("put", new JSONObject() msg.put("put", new JSONObject()
.put("ASDF", Utils.newNode("ASDF", new JSONObject() .put("ASDF", Utils.newNode("ASDF", new JSONObject()
.put("name", "Mark Nadal") .put("name", "Mark Nadal")
.put("boss", new JSONObject().put("#", "FDSA"))).toJSONObject()) .put("boss", new JSONObject().put("#", "FDSA"))).toJSONObject())
.put("FDSA", Utils.newNode("FDSA", new JSONObject().put("name", "Fluffy").put("species", "a kitty").put("slave", new JSONObject().put("#", "ASDF"))).toJSONObject())); .put("FDSA", Utils.newNode("FDSA", new JSONObject().put("name", "Fluffy").put("species", "a kitty").put("slave", new JSONObject().put("#", "ASDF"))).toJSONObject()));
this.send(msg.toString()); this.send(msg.toString());
}, 1000); }, (int) (1000 * Math.random()));
Utils.setTimeout(() -> { Utils.setTimeout(() -> {
JSONObject msg = new JSONObject(); JSONObject msg = new JSONObject();
msg.put("#", dup.track(Dup.random(3))); msg.put("#", dup.track(Dup.random()));
msg.put("put", new JSONObject() msg.put("put", new JSONObject()
.put("ASDF", Utils.newNode("ASDF", new JSONObject() .put("ASDF", Utils.newNode("ASDF", new JSONObject()
.put("name", "Mark")).toJSONObject()) .put("name", "Mark")).toJSONObject())
.put("FDSA", Utils.newNode("FDSA", new JSONObject().put("species", "felis silvestris").put("color", "ginger")).toJSONObject())); .put("FDSA", Utils.newNode("FDSA", new JSONObject().put("species", "felis silvestris").put("color", "ginger")).toJSONObject()));
this.send(msg.toString()); this.send(msg.toString());
}, 2000); }, (int) (1000 * Math.random()));
} }
@Override @Override
@ -44,7 +55,19 @@ public class Client extends WebSocketClient {
JSONObject msg = new JSONObject(message); JSONObject msg = new JSONObject(message);
if(dup.check(msg.getString("#"))){ return; } if(dup.check(msg.getString("#"))){ return; }
dup.track(msg.getString("#")); dup.track(msg.getString("#"));
System.out.println(msg.toString()); if(msg.opt("put") != null) {
HAM.mix(new Graph(msg.getJSONObject("put")), graph);
}
if(msg.opt("get") != null) {
Graph getResults = Utils.getRequest(msg.getJSONObject("get"), graph);
JSONObject ack = new JSONObject()
.put("#", dup.track(Dup.random()))
.put("@", msg.getString("#"))
.put("put", getResults.toJSONObject());
this.send(ack.toString());
}
System.out.println("---------------");
System.out.println(msg.toString(2));
this.send(message); this.send(message);
} }

View File

@ -2,10 +2,11 @@ package io.github.chronosx88.GunJava;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class Dup { public class Dup {
private static char[] randomPack = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private static char[] randomSeed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static Random random = new Random(System.currentTimeMillis()); private static Random random = new Random(System.currentTimeMillis());
private Map<String, Long> s = new ConcurrentHashMap<>(); private Map<String, Long> s = new ConcurrentHashMap<>();
private DupOpt opt = new DupOpt(); private DupOpt opt = new DupOpt();
@ -40,11 +41,7 @@ public class Dup {
} }
} }
public static String random(int len) { public static String random() {
StringBuilder sb = new StringBuilder(); return UUID.randomUUID().toString();
for (int i = 0; i < len; i++) {
sb.append(randomPack[random.nextInt(randomPack.length)]);
}
return sb.toString();
} }
} }

View File

@ -35,6 +35,8 @@ public class Graph {
return nodes.entrySet(); return nodes.entrySet();
} }
public Collection<Node> nodes() { return nodes.values(); }
@Override @Override
public String toString() { public String toString() {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
@ -59,4 +61,8 @@ public class Graph {
} }
return jsonObject; return jsonObject;
} }
public boolean isEmpty() {
return nodes.isEmpty();
}
} }

View File

@ -2,10 +2,11 @@ package io.github.chronosx88.GunJava;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
public class HAM { public class HAM {
private static long defer = Long.MAX_VALUE;
static class HAMResult { static class HAMResult {
public boolean defer = false; public boolean defer = false;
public boolean historical = false; public boolean historical = false;
@ -52,7 +53,7 @@ public class HAM {
return result; return result;
} }
public static Graph mix(Graph change, Graph graph) { public static Graph mix(Graph change, Graph data) {
long machine = System.currentTimeMillis(); long machine = System.currentTimeMillis();
Graph diff = null; Graph diff = null;
for(Map.Entry<String, Node> entry : change.entries()) { for(Map.Entry<String, Node> entry : change.entries()) {
@ -63,21 +64,23 @@ public class HAM {
long state = node.states.getLong(key); long state = node.states.getLong(key);
long was = -1; long was = -1;
Object known = null; Object known = null;
if(graph == null) { if(data == null) {
graph = new Graph(); data = new Graph();
} }
if(graph.hasNode(node.soul)) { if(data.hasNode(node.soul)) {
if(graph.getNode(node.soul).states.opt(key) != null) { if(data.getNode(node.soul).states.opt(key) != null) {
was = graph.getNode(node.soul).states.getLong(key); was = data.getNode(node.soul).states.getLong(key);
} }
known = graph.getNode(node.soul).values.opt(key) == null ? 0 : graph.getNode(node.soul).values.opt(key); known = data.getNode(node.soul).values.opt(key) == null ? 0 : data.getNode(node.soul).values.opt(key);
} }
HAMResult ham = ham(machine, state, was, value, known); HAMResult ham = ham(machine, state, was, value, known);
if(!ham.incoming) { if(!ham.incoming) {
if(ham.defer) { if(ham.defer) {
System.out.println("DEFER: " + key + " " + value); System.out.println("DEFER: " + key + " " + value);
// FIXME // Hack for accessing value in lambda without making the variable final
Graph[] graph = new Graph[] {data};
Utils.setTimeout(() -> mix(node, graph[0]), (int) (state - System.currentTimeMillis()));
} }
continue; continue;
} }
@ -90,18 +93,70 @@ public class HAM {
diff.addNode(node.soul, Utils.newNode(node.soul, new JSONObject())); diff.addNode(node.soul, Utils.newNode(node.soul, new JSONObject()));
} }
if(!graph.hasNode(node.soul)) { if(!data.hasNode(node.soul)) {
graph.addNode(node.soul, Utils.newNode(node.soul, new JSONObject())); data.addNode(node.soul, Utils.newNode(node.soul, new JSONObject()));
} }
graph.getNode(node.soul).values.put(key, value); data.getNode(node.soul).values.put(key, value);
diff.getNode(node.soul).values.put(key, value); diff.getNode(node.soul).values.put(key, value);
diff.getNode(node.soul).states.put(key, state); diff.getNode(node.soul).states.put(key, state);
graph.getNode(node.soul).states.put(key, state); data.getNode(node.soul).states.put(key, state);
} }
} }
return diff; return diff;
} }
public static Graph mix(Node incomingNode, Graph data) {
long machine = System.currentTimeMillis();
Graph diff = null;
for(String key : incomingNode.values.keySet()) {
Object value = incomingNode.values.get(key);
if ("_".equals(key)) { continue; }
long state = incomingNode.states.getLong(key);
long was = -1;
Object known = null;
if(data == null) {
data = new Graph();
}
if(data.hasNode(incomingNode.soul)) {
if(data.getNode(incomingNode.soul).states.opt(key) != null) {
was = data.getNode(incomingNode.soul).states.getLong(key);
}
known = data.getNode(incomingNode.soul).values.opt(key) == null ? 0 : data.getNode(incomingNode.soul).values.opt(key);
}
HAMResult ham = ham(machine, state, was, value, known);
if(!ham.incoming) {
if(ham.defer) {
System.out.println("DEFER: " + key + " " + value);
// Hack for accessing value in lambda without making the variable final
Graph[] graph = new Graph[] {data};
Utils.setTimeout(() -> mix(incomingNode, graph[0]), (int) (state - System.currentTimeMillis()));
}
continue;
}
if(diff == null) {
diff = new Graph();
}
if(!diff.hasNode(incomingNode.soul)) {
diff.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject()));
}
if(!data.hasNode(incomingNode.soul)) {
data.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject()));
}
data.getNode(incomingNode.soul).values.put(key, value);
diff.getNode(incomingNode.soul).values.put(key, value);
diff.getNode(incomingNode.soul).states.put(key, state);
data.getNode(incomingNode.soul).states.put(key, state);
}
return diff;
}
} }

View File

@ -0,0 +1,15 @@
package io.github.chronosx88.GunJava;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
public class MainClientServer {
public static void main(String[] args) throws URISyntaxException, UnknownHostException {
Server server = new Server(21334);
server.start();
Client client = new Client(Inet4Address.getByAddress(new byte[]{127, 0, 0, 1}), 21334);
client.connect();
}
}

View File

@ -4,8 +4,8 @@ import org.json.JSONObject;
public class Node implements Comparable<Node> { public class Node implements Comparable<Node> {
public JSONObject values; // Data public JSONObject values; // Data
public final JSONObject states; // Metadata for diff public JSONObject states; // Metadata for diff
public final String soul; // i.e. ID of node public String soul; // i.e. ID of node
/** /**
* Create a Node from a JSON object. * Create a Node from a JSON object.
@ -13,7 +13,7 @@ public class Node implements Comparable<Node> {
* @param rawData JSON object, which contains the data * @param rawData JSON object, which contains the data
*/ */
public Node(JSONObject rawData) { public Node(JSONObject rawData) {
this.values = rawData; this.values = new JSONObject(rawData.toString());
this.states = values.getJSONObject("_").getJSONObject(">"); this.states = values.getJSONObject("_").getJSONObject(">");
this.soul = values.getJSONObject("_").getString("#"); this.soul = values.getJSONObject("_").getString("#");
values.remove("_"); values.remove("_");
@ -61,4 +61,15 @@ public class Node implements Comparable<Node> {
jsonObject.put("_", new JSONObject().put("#", soul).put(">", states)); jsonObject.put("_", new JSONObject().put("#", soul).put(">", states));
return jsonObject; return jsonObject;
} }
public JSONObject getMetadata() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("_", new JSONObject().put("#", soul).put(">", states));
return jsonObject;
}
public void setMetadata(JSONObject metadata) {
soul = metadata.getJSONObject("_").getString("#");
states = metadata.getJSONObject("_").getJSONObject(">");
}
} }

View File

@ -6,27 +6,26 @@ import org.java_websocket.server.WebSocketServer;
import org.json.JSONObject; import org.json.JSONObject;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Timer; import java.util.Timer;
public class Server extends WebSocketServer { public class Server extends WebSocketServer {
private Timer timer = new Timer(true); private Timer timer = new Timer(true);
private Dup dup = new Dup(); private Dup dup = new Dup();
private ArrayList<WebSocket> peers = new ArrayList<>();
private Graph graph = new Graph(); private Graph graph = new Graph();
public Server(int port) { public Server(int port) {
super(new InetSocketAddress(port)); super(new InetSocketAddress(port));
setReuseAddr(true);
} }
@Override @Override
public void onOpen(WebSocket conn, ClientHandshake handshake) { public void onOpen(WebSocket conn, ClientHandshake handshake) {
peers.add(conn); System.out.println("Connected new peer: " + conn.getRemoteSocketAddress().toString());
} }
@Override @Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) { public void onClose(WebSocket conn, int code, String reason, boolean remote) {
// System.out.println("Peer " + conn.getRemoteSocketAddress().toString() + " closed the connection for reason (code): " + reason + " (" + code + ")");
} }
@Override @Override
@ -36,13 +35,20 @@ public class Server extends WebSocketServer {
dup.track(msg.getString("#")); dup.track(msg.getString("#"));
if(msg.opt("put") != null) { if(msg.opt("put") != null) {
HAM.mix(new Graph(msg.getJSONObject("put")), graph); HAM.mix(new Graph(msg.getJSONObject("put")), graph);
System.out.println("----------------");
System.out.println(graph.toPrettyString());
} }
for (WebSocket peer : peers) { if(msg.opt("get") != null) {
peer.send(message); Graph result = Utils.getRequest(msg.optJSONObject("get"), graph);
if(!result.isEmpty()) {
JSONObject ack = new JSONObject();
emit(ack
.put("#", dup.track(Dup.random()))
.put("@", msg.getString("#"))
.put("put", result.toJSONObject())
.toString());
} }
} }
emit(message);
}
@Override @Override
public void onError(WebSocket conn, Exception ex) { public void onError(WebSocket conn, Exception ex) {
@ -51,6 +57,12 @@ public class Server extends WebSocketServer {
@Override @Override
public void onStart() { public void onStart() {
// System.out.println("Server started on port: " + getPort());
}
public void emit(String data) {
for(WebSocket conn : this.getConnections()) {
conn.send(data);
}
} }
} }

View File

@ -25,4 +25,29 @@ public class Utils {
data.put("_", new JSONObject().put("#", soul).put(">", states)); data.put("_", new JSONObject().put("#", soul).put(">", states));
return new Node(data); return new Node(data);
} }
public static Graph getRequest(JSONObject lex, Graph graph) {
String soul = lex.getString("#");
String key = lex.optString(".", null);
Node node = graph.getNode(soul);
Object tmp;
if(node == null) {
return new Graph();
}
if(key != null) {
tmp = node.values.opt(key);
if(tmp == null) {
return new Graph();
}
Node node1 = new Node(node.toJSONObject());
node = Utils.newNode(node.soul, new JSONObject());
node.setMetadata(node1.getMetadata());
node.values.put(key, tmp);
JSONObject tmpStates = node1.states;
node.states.put(key, tmpStates.get(key));
}
Graph ack = new Graph();
ack.addNode(soul, node);
return ack;
}
} }