summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/dnbd3
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openslx/dnbd3')
-rw-r--r--src/main/java/org/openslx/dnbd3/status/App.java14
-rw-r--r--src/main/java/org/openslx/dnbd3/status/StatisticsGenerator.java146
-rw-r--r--src/main/java/org/openslx/dnbd3/status/WebServer.java100
-rw-r--r--src/main/java/org/openslx/dnbd3/status/output/EdgeSerializer.java25
-rw-r--r--src/main/java/org/openslx/dnbd3/status/output/OutputMain.java19
-rw-r--r--src/main/java/org/openslx/dnbd3/status/output/ServerStats.java19
-rw-r--r--src/main/java/org/openslx/dnbd3/status/poller/ServerPoller.java70
-rw-r--r--src/main/java/org/openslx/dnbd3/status/rpc/Client.java31
-rw-r--r--src/main/java/org/openslx/dnbd3/status/rpc/Image.java37
-rw-r--r--src/main/java/org/openslx/dnbd3/status/rpc/Status.java73
10 files changed, 534 insertions, 0 deletions
diff --git a/src/main/java/org/openslx/dnbd3/status/App.java b/src/main/java/org/openslx/dnbd3/status/App.java
new file mode 100644
index 0000000..9f7ef5f
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/App.java
@@ -0,0 +1,14 @@
+package org.openslx.dnbd3.status;
+
+import java.io.IOException;
+
+public class App
+{
+
+ public static void main( String[] args ) throws IOException
+ {
+ WebServer ws = new WebServer( 8888 );
+ ws.run();
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/StatisticsGenerator.java b/src/main/java/org/openslx/dnbd3/status/StatisticsGenerator.java
new file mode 100644
index 0000000..777ce7a
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/StatisticsGenerator.java
@@ -0,0 +1,146 @@
+package org.openslx.dnbd3.status;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.openslx.dnbd3.status.output.EdgeSerializer;
+import org.openslx.dnbd3.status.output.OutputMain;
+import org.openslx.dnbd3.status.output.ServerStats;
+import org.openslx.dnbd3.status.poller.ServerPoller;
+import org.openslx.dnbd3.status.rpc.Client;
+import org.openslx.dnbd3.status.rpc.Status;
+import org.openslx.graph.ClientNode;
+import org.openslx.graph.Edge;
+import org.openslx.graph.Graph;
+import org.openslx.graph.Node;
+import org.openslx.graph.ServerNode;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class StatisticsGenerator
+{
+ private final List<ServerPoller> pollers;
+ private volatile long lastUpdate = 0;
+ private ExecutorService threadPool = new ThreadPoolExecutor( 1, 6, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>( 100 ) );
+ private List<Future<Status>> futureStatusList = new ArrayList<>();
+ private List<Status> statusList = new ArrayList<>();
+ private final Gson jsonBuilder;
+
+ private final Graph graph = new Graph( "DNBD 3 Status" );
+ private byte[] imgData = null;
+ private final OutputMain output = new OutputMain();
+
+ public StatisticsGenerator( List<ServerPoller> pollers )
+ {
+ this.pollers = pollers;
+ for ( ServerPoller poller : pollers ) {
+ Node server = new ServerNode( poller.getAddress() );
+ server.activate();
+ graph.addNode( server );
+ }
+ // Prepare json serializer for graph
+ final GsonBuilder gsonBuilder = new GsonBuilder();
+ gsonBuilder.excludeFieldsWithoutExposeAnnotation();
+ gsonBuilder.registerTypeHierarchyAdapter( Edge.class, new EdgeSerializer() );
+ jsonBuilder = gsonBuilder.create();
+ output.graph = graph;
+ output.servers = new ArrayList<>();
+ output.timestamp = 0;
+ }
+
+ private synchronized void updateAll()
+ {
+ futureStatusList.clear();
+ for ( final ServerPoller p : pollers ) {
+ Future<Status> ret = threadPool.submit( new Callable<Status>() {
+ @Override
+ public Status call() throws Exception
+ {
+ return p.update();
+ }
+ } );
+ futureStatusList.add( ret );
+ }
+ statusList.clear();
+ output.servers.clear();
+ for ( Future<Status> future : futureStatusList ) {
+ Status status;
+ try {
+ status = future.get();
+ } catch ( Exception e ) {
+ continue;
+ }
+ if ( status == null )
+ continue;
+ statusList.add( status );
+ ServerStats srv = new ServerStats();
+ srv.address = status.getAddress();
+ srv.bytesReceived = status.getBytesReceived();
+ srv.bytesSent = status.getBytesSent();
+ for ( Client c : status.getClients() ) {
+ srv.bytesSent += c.getBytesSent();
+ }
+ srv.clientCount = status.getClients().size();
+ srv.uptime = status.getUptime();
+ output.servers.add( srv );
+ }
+ output.timestamp = System.currentTimeMillis();
+ synchronized ( graph ) {
+ graph.decay();
+ for ( Status status : statusList ) {
+ String serverIp = status.getAddress();
+ Node server = graph.getNode( serverIp );
+ if ( server == null )
+ server = new ServerNode( serverIp );
+ server.activate();
+ for ( Client client : status.getClients() ) {
+ if ( client.getAddress() == null )
+ continue;
+ String ip = client.getAddress().replaceFirst( "\\:\\d+$", "" );
+ Node n = graph.getNode( ip );
+ if ( n == null )
+ n = new ClientNode( ip );
+ n.activate();
+ graph.setEdge( server, n, ( client.getBytesSent() >> 12 ) + 1 );
+ }
+ }
+ imgData = null;
+ }
+ }
+
+ private synchronized void ensureUpToDate()
+ {
+ final long now = System.currentTimeMillis();
+ if ( now - lastUpdate > 1900 ) {
+ lastUpdate = now;
+ updateAll();
+ }
+ }
+
+ public byte[] getImagePng()
+ {
+ ensureUpToDate();
+ synchronized ( graph ) {
+ if ( imgData == null ) {
+ imgData = graph.makeNextImage();
+ }
+ }
+ return imgData;
+ }
+
+ public String getJson()
+ {
+ ensureUpToDate();
+ synchronized ( graph ) {
+ return jsonBuilder.toJson( output );
+ }
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/WebServer.java b/src/main/java/org/openslx/dnbd3/status/WebServer.java
new file mode 100644
index 0000000..14d9a09
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/WebServer.java
@@ -0,0 +1,100 @@
+package org.openslx.dnbd3.status;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openslx.dnbd3.status.poller.ServerPoller;
+
+import fi.iki.elonen.NanoHTTPD;
+
+public class WebServer extends NanoHTTPD
+{
+
+ private final StatisticsGenerator imageGenerator;
+
+ public WebServer( int port )
+ {
+ super( port );
+ List<ServerPoller> pollers = new ArrayList<>();
+ pollers.add( new ServerPoller( "132.230.8.113", 5003 ) );
+ pollers.add( new ServerPoller( "132.230.4.60", 5003 ) );
+ pollers.add( new ServerPoller( "132.230.4.1", 5003 ) );
+ imageGenerator = new StatisticsGenerator( pollers );
+ }
+
+ @Override
+ public Response serve( IHTTPSession session )
+ {
+ String uri = session.getUri();
+
+ // Special/dynamic
+ if ( uri.equals( "/image.png" ) )
+ return serveImage();
+ if ( uri.equals( "/data.json" ) )
+ return serveJson();
+
+ // Static files
+ if ( uri.equals( "/" ) )
+ uri = "/index.html";
+
+ File f = new File( "./static/" + uri.replace( "/", "" ) );
+ if ( f.isFile() ) {
+ InputStream is = null;
+ try {
+ is = new FileInputStream( f );
+ /*
+ // TODO: Shit doesn't work
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.OK,
+ URLConnection.guessContentTypeFromName( f.getName() ), is );
+ */
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[ 10000 ];
+ for ( ;; ) {
+ int ret = is.read( buffer );
+ if ( ret <= 0 )
+ break;
+ baos.write( buffer, 0, ret );
+ }
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.OK,
+ URLConnection.guessContentTypeFromName( f.getName() ), baos.toString( "UTF-8" ) );
+ } catch ( Exception e ) {
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.INTERNAL_ERROR,
+ "text/plain", "Internal Server Error" );
+ } finally {
+ safeClose( is );
+ }
+ }
+
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.NOT_FOUND, "text/plain", "Nicht gefunden!" );
+ }
+
+ private NanoHTTPD.Response serveImage()
+ {
+ InputStream is = null;
+ byte[] imgData = imageGenerator.getImagePng();
+ if ( imgData != null )
+ is = new ByteArrayInputStream( imgData );
+ if ( is == null ) {
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.INTERNAL_ERROR, "text/plain", "Internal Server Error" );
+ } else {
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.OK, "image/png", is );
+ }
+ }
+
+ private NanoHTTPD.Response serveJson()
+ {
+ String data = imageGenerator.getJson();
+ if ( data == null ) {
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.INTERNAL_ERROR, "text/plain", "Internal Server Error" );
+ } else {
+ return new NanoHTTPD.Response( NanoHTTPD.Response.Status.OK, "application/json", data );
+ }
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/output/EdgeSerializer.java b/src/main/java/org/openslx/dnbd3/status/output/EdgeSerializer.java
new file mode 100644
index 0000000..e014bb3
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/output/EdgeSerializer.java
@@ -0,0 +1,25 @@
+package org.openslx.dnbd3.status.output;
+
+import java.lang.reflect.Type;
+
+import org.openslx.graph.Edge;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public class EdgeSerializer implements JsonSerializer<Edge>
+{
+
+ @Override
+ public JsonElement serialize( Edge src, Type typeOfSrc, JsonSerializationContext context )
+ {
+ final JsonObject out = new JsonObject();
+ out.addProperty( "source", src.getSource().getId() );
+ out.addProperty( "target", src.getTarget().getId() );
+ out.addProperty( "width", src.getWeight() );
+ return out;
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/output/OutputMain.java b/src/main/java/org/openslx/dnbd3/status/output/OutputMain.java
new file mode 100644
index 0000000..c3204e7
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/output/OutputMain.java
@@ -0,0 +1,19 @@
+package org.openslx.dnbd3.status.output;
+
+import java.util.List;
+
+import org.openslx.graph.Graph;
+
+import com.google.gson.annotations.Expose;
+
+public class OutputMain
+{
+
+ @Expose
+ public Graph graph;
+ @Expose
+ public List<ServerStats> servers;
+ @Expose
+ public long timestamp;
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/output/ServerStats.java b/src/main/java/org/openslx/dnbd3/status/output/ServerStats.java
new file mode 100644
index 0000000..c58abb3
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/output/ServerStats.java
@@ -0,0 +1,19 @@
+package org.openslx.dnbd3.status.output;
+
+import com.google.gson.annotations.Expose;
+
+public class ServerStats
+{
+
+ @Expose
+ public String address;
+ @Expose
+ public int clientCount;
+ @Expose
+ public long uptime;
+ @Expose
+ public long bytesSent;
+ @Expose
+ public long bytesReceived;
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/poller/ServerPoller.java b/src/main/java/org/openslx/dnbd3/status/poller/ServerPoller.java
new file mode 100644
index 0000000..bfa70fb
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/poller/ServerPoller.java
@@ -0,0 +1,70 @@
+package org.openslx.dnbd3.status.poller;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.openslx.dnbd3.status.rpc.Status;
+
+import com.google.gson.Gson;
+
+/**
+ * Polling a dnbd3 server for its status.
+ *
+ */
+public class ServerPoller
+{
+
+ private final String address;
+ private final String server;
+ private final Gson parseGson = new Gson();
+
+ public ServerPoller( String host, int port )
+ {
+ this.address = host;
+ this.server = "http://" + host + ":" + port + "/";
+ }
+
+ public Status update()
+ {
+ HttpURLConnection con = null;
+ InputStream is;
+ try {
+ con = (HttpURLConnection)new URL( this.server ).openConnection();
+ con.setRequestMethod( "GET" );
+
+ con.setConnectTimeout( 1000 );
+ con.setReadTimeout( 3000 );
+
+ if ( con.getResponseCode() != HttpURLConnection.HTTP_OK ) {
+ return null;
+ }
+
+ is = con.getInputStream();
+ } catch ( java.net.SocketTimeoutException e ) {
+ return null;
+ } catch ( java.io.IOException e ) {
+ return null;
+ }
+ // Now read data
+ Status status;
+ try {
+ status = parseGson.fromJson( new InputStreamReader( is ), Status.class );
+ status.setAddress( address );
+ status.setTimestamp( System.currentTimeMillis() );
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ status = null;
+ }
+ // TODO: http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
+ // once dnbd3 server supports keep-alive connections
+ return status;
+ }
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/rpc/Client.java b/src/main/java/org/openslx/dnbd3/status/rpc/Client.java
new file mode 100644
index 0000000..fcb8e3e
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/rpc/Client.java
@@ -0,0 +1,31 @@
+package org.openslx.dnbd3.status.rpc;
+
+public class Client
+{
+
+ private String address = null;
+ private int imageId = -1;
+ private long bytesSent = -1;
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+ public int getImageId()
+ {
+ return imageId;
+ }
+
+ public long getBytesSent()
+ {
+ return bytesSent;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "[Addr: " + address + ", image: " + imageId + "]";
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/rpc/Image.java b/src/main/java/org/openslx/dnbd3/status/rpc/Image.java
new file mode 100644
index 0000000..910db82
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/rpc/Image.java
@@ -0,0 +1,37 @@
+package org.openslx.dnbd3.status.rpc;
+
+public class Image
+{
+
+ private String name = null;
+ private int rid = -1;
+ private int complete = -1;
+ private int users = -1;
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public int getRid()
+ {
+ return rid;
+ }
+
+ public int getComplete()
+ {
+ return complete;
+ }
+
+ public int getUsers()
+ {
+ return users;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "[" + name + " (users: " + users + ")]";
+ }
+
+}
diff --git a/src/main/java/org/openslx/dnbd3/status/rpc/Status.java b/src/main/java/org/openslx/dnbd3/status/rpc/Status.java
new file mode 100644
index 0000000..07fc782
--- /dev/null
+++ b/src/main/java/org/openslx/dnbd3/status/rpc/Status.java
@@ -0,0 +1,73 @@
+package org.openslx.dnbd3.status.rpc;
+
+import java.util.List;
+
+public class Status
+{
+
+ private long bytesReceived = -1;
+ private long bytesSent = -1;
+ private int uptime = -1;
+ private List<Image> images = null;
+ private List<Client> clients = null;
+ private String address = null;
+ private long timeStamp = -1;
+
+ public long getBytesReceived()
+ {
+ return bytesReceived;
+ }
+
+ public long getBytesSent()
+ {
+ return bytesSent;
+ }
+
+ public int getUptime()
+ {
+ return uptime;
+ }
+
+ public List<Image> getImages()
+ {
+ return images;
+ }
+
+ public List<Client> getClients()
+ {
+ return clients;
+ }
+
+ public String getAddress()
+ {
+ return address;
+ }
+
+ public void setAddress( String address )
+ {
+ this.address = address;
+ }
+
+ @Override
+ public String toString()
+ {
+ String ret = "(in: " + bytesReceived + ", out: " + bytesSent;
+ if ( clients != null )
+ ret += ", clients: (" + clients.toString() + ")";
+ if ( images != null )
+ ret += ", images: (" + images.toString() + ")";
+ ret += ")";
+ return ret;
+ }
+
+ public void setTimestamp( long currentTimeMillis )
+ {
+ this.timeStamp = currentTimeMillis;
+ }
+
+ public long getTimestamp()
+ {
+ return this.timeStamp;
+ }
+
+}