implemented Server Sent events and Heartbeat
This commit is contained in:
@@ -157,5 +157,9 @@ window.onload = function () {
|
||||
$('.menu .addtile .list svg').click(enableAdding);
|
||||
$('.menu .move .list div').click(enableMove);
|
||||
$('.menu .actions .list > div').click(runAction);
|
||||
$(BODY).click(bodyClick);
|
||||
$(BODY).click(bodyClick);
|
||||
var stream = new EventSource("stream");
|
||||
stream.onmessage = function(ev){
|
||||
console.log(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
@@ -38,6 +39,7 @@ public class Application {
|
||||
server.createContext("/plan", client -> sendPlan(client));
|
||||
server.createContext("/css" , client -> sendFile(client));
|
||||
server.createContext("/js" , client -> sendFile(client));
|
||||
server.createContext("/stream", client -> stream(client));
|
||||
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
|
||||
server.start();
|
||||
try {
|
||||
@@ -47,6 +49,48 @@ public class Application {
|
||||
}
|
||||
Desktop.getDesktop().browse(URI.create("http://localhost:"+config.getInt(PORT)+"/plan"));
|
||||
}
|
||||
|
||||
private static HashMap<String, String> inflate(String data) {
|
||||
LOG.debug("inflate({})",data);
|
||||
HashMap<String, String> params = new HashMap<String, String>();
|
||||
if (data == null || data.trim().isEmpty()) return params;
|
||||
String[] parts = data.split("&");
|
||||
|
||||
for (String part : parts) {
|
||||
String[] entry = part.split("=", 2);
|
||||
params.put(URLDecoder.decode(entry[0],UTF8),URLDecoder.decode(entry[1], UTF8));
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private static HashMap<String, String> inflate(byte[] data) {
|
||||
return inflate(new String(data,UTF8));
|
||||
}
|
||||
|
||||
private static void send(HttpExchange client, Object response) throws IOException {
|
||||
byte[] html;
|
||||
if (response instanceof Page) {
|
||||
html = ((Page)response).html().toString().getBytes(UTF8);
|
||||
client.getResponseHeaders().add("content-type", "text/html");
|
||||
} else {
|
||||
html = (response == null ? "" : response.toString()).getBytes(UTF8);
|
||||
client.getResponseHeaders().add("content-type", "text/plain");
|
||||
}
|
||||
|
||||
client.sendResponseHeaders(200, html.length);
|
||||
OutputStream os = client.getResponseBody();
|
||||
os.write(html);
|
||||
os.close();
|
||||
}
|
||||
|
||||
private static void sendError(HttpExchange client, int code, String msg) throws IOException {
|
||||
client.sendResponseHeaders(code, msg.length());
|
||||
LOG.error(msg);
|
||||
OutputStream out = client.getResponseBody();
|
||||
out.write(msg.getBytes(UTF8));
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static void sendFile(HttpExchange client) throws IOException {
|
||||
URI uri = client.getRequestURI();
|
||||
@@ -64,48 +108,6 @@ public class Application {
|
||||
}
|
||||
sendError(client,404,t("Could not find \"{}\"",uri));
|
||||
}
|
||||
|
||||
private static void sendError(HttpExchange client, int code, String msg) throws IOException {
|
||||
client.sendResponseHeaders(code, msg.length());
|
||||
LOG.error(msg);
|
||||
OutputStream out = client.getResponseBody();
|
||||
out.write(msg.getBytes(UTF8));
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static HashMap<String, String> inflate(byte[] data) {
|
||||
return inflate(new String(data,UTF8));
|
||||
}
|
||||
|
||||
private static HashMap<String, String> inflate(String data) {
|
||||
LOG.debug("inflate({})",data);
|
||||
HashMap<String, String> params = new HashMap<String, String>();
|
||||
if (data == null || data.trim().isEmpty()) return params;
|
||||
String[] parts = data.split("&");
|
||||
|
||||
for (String part : parts) {
|
||||
String[] entry = part.split("=", 2);
|
||||
params.put(URLDecoder.decode(entry[0],UTF8),URLDecoder.decode(entry[1], UTF8));
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private static void send(HttpExchange client, Object response) throws IOException {
|
||||
byte[] html;
|
||||
if (response instanceof Page) {
|
||||
html = ((Page)response).html().toString().getBytes(UTF8);
|
||||
client.getResponseHeaders().add("content-type", "text/html");
|
||||
} else {
|
||||
html = (response == null ? "" : response.toString()).getBytes(UTF8);
|
||||
client.getResponseHeaders().add("content-type", "text/plain");
|
||||
}
|
||||
|
||||
client.sendResponseHeaders(200, html.length);
|
||||
OutputStream os = client.getResponseBody();
|
||||
os.write(html);
|
||||
os.close();
|
||||
}
|
||||
|
||||
private static void sendPlan(HttpExchange client) throws IOException {
|
||||
try {
|
||||
@@ -117,6 +119,13 @@ public class Application {
|
||||
}
|
||||
}
|
||||
|
||||
private static void stream(HttpExchange client) throws IOException {
|
||||
client.getResponseHeaders().set("content-type", "text/event-stream");
|
||||
client.sendResponseHeaders(200, 0);
|
||||
OutputStreamWriter sseWriter = new OutputStreamWriter(client.getResponseBody());
|
||||
plan.addClient(sseWriter);
|
||||
}
|
||||
|
||||
private static String t(String text, Object...fills) {
|
||||
return Translation.get(Application.class, text, fills);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -62,6 +64,21 @@ public class Plan {
|
||||
public enum Direction{
|
||||
NORTH, SOUTH, EAST, WEST
|
||||
}
|
||||
|
||||
private class Heartbeat extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
sleep(10000);
|
||||
heatbeat();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String ACTION = "action";
|
||||
private static final String ACTION_ADD = "add";
|
||||
private static final String ACTION_ANALYZE = "analyze";
|
||||
@@ -78,11 +95,47 @@ public class Plan {
|
||||
private static final String ACTION_ROUTE = "openRoute";
|
||||
private static final String ID = "id";
|
||||
private static final String ROUTE = "route";
|
||||
private static final HashMap<OutputStreamWriter,Integer> clients = new HashMap<OutputStreamWriter, Integer>();
|
||||
|
||||
private HashMap<Integer,HashMap<Integer,Tile>> tiles = new HashMap<Integer,HashMap<Integer,Tile>>();
|
||||
private HashSet<Block> blocks = new HashSet<Block>();
|
||||
private HashMap<String, Route> routes = new HashMap<String, Route>();
|
||||
|
||||
public Plan() {
|
||||
new Heartbeat().start();
|
||||
}
|
||||
|
||||
public void heatbeat() {
|
||||
stream("hearbeat @ "+new Date().getTime());
|
||||
}
|
||||
|
||||
private void stream(String data) {
|
||||
LOG.debug("streaming {}",data);
|
||||
Vector<OutputStreamWriter> badClients = null;
|
||||
for (Entry<OutputStreamWriter, Integer> entry : clients.entrySet()) {
|
||||
OutputStreamWriter client = entry.getKey();
|
||||
try {
|
||||
client.write("data: "+data+"\n\n");
|
||||
client.flush();
|
||||
clients.put(client,0);
|
||||
} catch (IOException e) {
|
||||
int errorCount = entry.getValue()+1;
|
||||
LOG.info("Error #{} on client: {}",errorCount,e.getMessage());
|
||||
if (errorCount > 4) {
|
||||
if (badClients == null) badClients = new Vector<OutputStreamWriter>();
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException e1) {}
|
||||
badClients.add(client);
|
||||
} else clients.put(client,errorCount);
|
||||
}
|
||||
}
|
||||
if (badClients != null) for (OutputStreamWriter client: badClients) {
|
||||
LOG.info("Disconnecting client.");
|
||||
clients.remove(client);
|
||||
}
|
||||
}
|
||||
|
||||
private Tag actionMenu() throws IOException {
|
||||
Tag tileMenu = new Tag("div").clazz("actions").content(t("Actions"));
|
||||
StringBuffer tiles = new StringBuffer();
|
||||
@@ -91,6 +144,11 @@ public class Plan {
|
||||
return new Tag("div").clazz("list").content(tiles.toString()).addTo(tileMenu);
|
||||
}
|
||||
|
||||
public void addClient(OutputStreamWriter client) {
|
||||
LOG.debug("Client connected.");
|
||||
clients.put(client, 0);
|
||||
}
|
||||
|
||||
public static void addLink(Tile tile,String content,Tag list) {
|
||||
new Tag("li").clazz("link").attr("onclick", "return clickTile("+tile.x+","+tile.y+");").content(content).addTo(list);
|
||||
}
|
||||
@@ -187,7 +245,7 @@ public class Plan {
|
||||
String line = br.readLine().trim();
|
||||
String[] parts = line.split("=",2);
|
||||
try {
|
||||
String id = parts[0];
|
||||
//String id = parts[0];
|
||||
JSONObject json = new JSONObject(parts[1]);
|
||||
Route route = new Route();
|
||||
json.getJSONArray(Route.PATH).forEach(entry -> {
|
||||
|
||||
Reference in New Issue
Block a user