Building a websocket based multi-user map

Websockets are the next big thing for full-duplex communication on the web. At least that is what they are saying for a while now. Actual implementations are hard to find and documentation is a bit sparse. However, the idea of full-duplex communication is intriguing, the most used example is a webchat client. No more polling, long-polling, keep-a-lives and other tricks. Since there are already an over abundance of webchat clients it is not really a strong use-case. We figured that an interesting use-case would to have a multi-user GIS where you can actually see where the other guy is, what he is seeing and together edit the map; think google-docs for map editing.

Websockets are really easy to start with, especially if you use node.js, on the client it is:

var url = ws://host/
var ws = new WebSocket(url, 'connect');
ws.onopen = onOpen;
ws.onmessage = onMessage;
ws.onclose = onClose;
ws.onerror = onError;

On the server I used this; basically you start a websocket server and define what it has to do when people connect, send messages and disconnect again. This worked like a charm. In no time we were sending view-extents, features and the like around on the local network.

The problem however is that websockets are really really new. There is not that much information about them and hardly any tools to work with them. Most of the hardware of the internet does not know how to deal with it. We already had a problem when the node.js server was moved onto a different network within the company. The gateway didn’t understand the websocket packages and dropped them. There is a nice article explaining what is happening and what you should do. Basically the way forward is not using websockets (ws://) but secure websockets (wss://). So while websockets are new and not too well documented, secure websockets are a complete disaster in that respect.

Setting up a secure websocket with node.js is also very easy; just use wss:// on the client side and on the serverside use:

var http = require('https');

var options = {
      key: fs.readFileSync( 'ssl/socket-key.pem'),
      cert: fs.readFileSync('ssl/socket-cert.pem')
};
var server = http.createServer(options, function(request, response) {
      response.writeHead(200);
      response.end();
});
....etc

Since I am using self-signed certificates I needed to get the user sign the certificate, otherwise the wss:// connection fails silently. So I added an empty HTTP 200 response so the browser would show an unsecure certificate warning. This worked nicely through the company gateways. However, it was still impossible to access the server from the outside, because non of the proxy server we use understand websocket or secure websocket. So while I made a little progress within the different networks of the company I still couldn’t access the socket server from outside the network.

It took me a while, but with the help of this article I figured out the trick. He uses stunnel to unencrypt the secure websocket, but I prefer a one stop shop so: You need to setup a proxy facing the internet using the latest haproxy (with SSL support). Configure it as such:

global
        log 127.0.0.1   local0 info
        maxconn 4096
        user haproxy
        group haproxy
        daemon
        #debug
        #quiet

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option redispatch
        option http-server-close
        maxconn 2000
        contimeout      5000
        clitimeout      50000
        srvtimeout      50000

backend ws
        balance roundrobin
        option forwardfor # This sets X-Forwarded-For
        timeout connect 86400000s
        timeout server 86400000s
        server ws1 localhost:8080 weight 1 maxconn 1024 check

backend ww
        balance roundrobin
        option forwardfor # This sets X-Forwarded-For
        timeout connect 10s
        timeout server 30s
        server ww1 localhost

frontend https_proxy
        bind *:443 ssl crt /etc/ssl/cert.key_pem
        mode http
        acl is_websocket hdr(Upgrade) -i WebSocket
        acl is_websocket hdr_beg(Host) -i ws
        use_backend ws if is_websocket
        timeout client 86400000s
        default_backend ww

What this does is providing an https ‘server’ on the internet and filtering the wss requests out, unencrypt them and send them to the node.js instance. http://afitnerd.com really did a great job explaining their setup, only two things weren’t that clear. The first is that the client is using the wss:// protocol, so your config looks like this:

var url = wss://host/
var ws = new WebSocket(url, 'connect'); 
ws.onopen = onOpen; 
ws.onmessage = onMessage; 
ws.onclose = onClose; 
ws.onerror = onError;

The second is that the server still provides a non secure websocket service. So you need to use var http = require('http'); and not var https = require('https');. Now we have secure websockets working through all proxies, gateways and routers between you and the ws server, so without further ado:

Please accept the self-signed certificate, use a websocket enabled browser and click here.

OpenJDK7 vs. Oracle JDK7 with Geoserver

Introduction:

After installing a new server with ubuntu 64 I noticed that only openjdk packages are available nowadays. A quick search learned me that, though it is still possible, installing Oracle’s JDK wasn’t advisable. It is hard to keep up to date and people even claim that Oracle’s JDK is a security risk in itself. However the Geoserver developers recommend Oracle (Sun) JDK over OpenJDK. This is a test they did in september 2010 with Sun JDK 1.6 and OpenJDK 6.

Test setup:

Development has continued since then and now Java 7 is available, both in Oracle and OpenJDK flavour. I asked on twitter whether or not it still mattered which version you use. Apparently it is not entirely clear, so I did a quick test with two virtual machines on an ESX-cluster[*] I had handy. One I installed the standard OpenJDK that comes with ubuntu (7u9-2.3.3-0ubuntu1~12.04.1), the other I installed the latest Oracle JDK and JRE (jdk7u9).

On the database server the dutch top10 topographic map was loaded and styled with the SLD from NLextract. I used geoserver’s preview layer function to get an idea how fast the two JDKs are and how the results look. I’ve first zoomed in step by step from the entire Netherlands to village level (8steps) and changed the mapsize to 1280×1024 and zoomed back up. Obviously I had atop running on all three servers to prevent accidentally starting a request before the server were ready.

Results:

This produced the following graph:

Interestingly oracle’s render time tops around 48seconds and openjdk gets a DNF at the lower zoomlevels.In general you can say that Oracle is faster in parsing the millions of features from the database. On more detailed zoom levels the differences disappear:

z0 z1 z2 z3 z4 z5 z6 z7 z8
openjdk 60 41.3 11.97 3.65 1.44 0.552 0.294 0.183
openjdk-2 60 41.35 11.98 3.92 1.35 0.598 0.272 0.213
oracle 48.49 48.32 26.06 8 2.49 0.9 0.363 0.228 0.197
oracle-2 48.32 48.44 27.25 7.99 2.44 0.701 0.384 0.484 0.197
openjdk-large 60 28.47 9.3 3.53 1.62 0.802
openjdk-large-2 28.59 9.22 3.18 1.4 0.784
oracle-large 48.25 48.53 48.84 31.58 11.81 3.75 1.83 1.01 0.721
oracle-large-2 48.48 48.13 48.83 31.43 12.21 3.78 1.85 1.1 0.76

The render quality was on par though, this is with openjdk:

and this with oracle:

On zoom level 2, openjdk:

and oracle:

Conclusion:

This quick and dirty test shows that a reasonably configured openjdk-based geoserver instance is slower than a oracle-jdk based one when rendering a lot of features out of a database. Since the image quality seems to be the same (no labels here) it shouldn’t be too much of a problem though if you use geoserver as a backend of a tiling server. The millions of tiles of the deep-zoomlevels contain less features.

[*] test machine specs, all run Ubuntu 12.04 64bit:
Database server ‘cumulus’:
16GB RAM, 4CPU 2.67GHZ XEON X5650, postgresql 9.1 postgis 2.0, 2GB shared_buffers

Geoserver machines:
8GB RAM, 4CPU 2.67GHZ XEON X5650, tomcat 7, geoserver 2.2.1

 

 

OpenLayers and XKCD

Today Randall of XKCD created a most astonishing comic, which is a giant side view of a world with stuff in the air and underground. Looking at the comic I realised that it was a tiled map, though with a slightly odd tilescheme, in stead of a simple x/y it used a more complex, n/s,e/w starting from the middle, so the centre tile is 1n1e one to the left is 1n2e and one to the right is 1n1w, similar with going up or down.

OpenLayers to the rescue: being open source it is very easy to extend and modify their tiling-schema to work with the slightly weird XKCD system, see it in action here: http://research.geodan.nl/sites/xkcd

The slightly horrible code:

OpenLayers.Layer.XKCD = OpenLayers.Class(OpenLayers.Layer.XYZ, {
	getXYZ: function(bounds) {
		var res = this.getServerResolution();
		var x = Math.round((bounds.left - this.maxExtent.left) /
			(res * this.tileSize.w));
		if(x >= 50)  x = (x - 49)+'e';
		else if (x <50) x = (50 - x)  + 'w';
		var y = Math.round((this.maxExtent.top - bounds.top) /
			(res * this.tileSize.h));
		if(y > 50) y = (y -50)+'s';
		else if (y <=50) y = (51 -y )+ 'n';
	        var z = this.getServerZoom();
		return {'x': x, 'y': y, 'z': z};
	}
})


 

Web mapping with SVG

Scalable Vector Graphics – the concept has been around for a while (since 2001), but it did not become a popular web format because of lack of browser support. Now that web browsers are getting ready for supporting the host of new features that come along with HTML 5 and CSS 3 we see an increase in support for SVG. Perhaps SVG is now usable enough for geographical vector data? We have done a bit of testing, resulting in two self contained HTML files that a modern web browser can turn in to interactive maps. At the time of writing the examples only work properly in Google Chrome. Here are the files:

An interactive map of Africa: Shows country labels when the mouse pointer hovers over a country and blows up a country after a mouse click.

An interactive map of the World: Shows some country attributes when mouse pointer hovers over a country and allows for zooming and panning.

Both samples have a few things in common:

  • The map is always fitted into the available space of the browser window.
  • The web page is self contained. It does not make use of external data sources, scripts or libraries. Operating the map does not generate any network traffic.
  • CSS is used for styling geometries and for alternative styles when the mouse pointer hovers over a geometry.
  • SVG transformations (like scaling and translations) are handled with javascript. You can see the javascript functions in the HTML code of the page. Handling SVG with javascript is easy because all SVG objects are part of the DOM.

I have the feeling that these samples only scratch the surface of what is possible with SVG and CSS. It does seem that the old SVG format, in combination with new web standards like CSS 3 and HTML 5, could very well be used for web mapping. With more and more vector data becoming available on the web, SVG could yet play an important role.

Toys as tools

Several of our research topic involve expensive and large equipment. With the FireFly project integrate live video from UAVs into command&control systems. Another project involves a communication truck of the fire department and we also look at other sensor enabled vehicles. A big problem then is of course testing and demonstrating our solutions.

Luckily there are some great toys around! Instead of the “real” UAV which costs around 100K Euro we purchased a few AR Drones for a few hundred Euros. And Lego Mindstorms is a great tool to test and  demonstrate sensor enabled vehicles! These toys also come with Open Source SDKs to integrate them easily into our professional innovations.

YouTube Preview Image

The only issue is that our research office is starting to look like a play-yard with stuff like AR.Drones, Playmobil, Lego Mindstorms, XBox and WII.

FireFly

One of the Research project carried out by Geodan Research is the FireFly project. This project aims to integrate aerial images from unmanned aerial vehicles (UAVs) into command&control systems.

The aerial images come in either as live video streams or as geo-referenced images. These images can easily be shared with the Eagle system. Eagle has been selected as new National Crisis Management System (LCMS 2.0).

The video as well as the helicopter location and direction are also visualised live on the Microsoft Surface and integrated in relevant maps. This resuls in an enhanced situational awareness and better decision making abilities.

YouTube Preview Image

History of Amsterdam through BAG

De Dutch government is compiling a large database with all buildings and addresses of the Netherlands. One of the attributes of this database is the year of construction of the building. Using this information of the buildings of Amsterdam we’ve created an animation of the growth of Amsterdam over time. Unfortunately there are no accurate dates pre-1850 as such the animation starts at 1850. So the Canal-district and the Jordaan are already finished.

YouTube Preview Image

Cyclorama’s on the Surface

We created a control on the surface which allows the user to view 360° photos on the secondary screen. You place the control object on the map and it will load the nearest photo onto the secondary screen. When you rotate the object the view will rotate with it.

Cyclorama viewer op de surface

Cyclorama viewer op de surface

We created a short movie to show how it works:

httpvhd://www.youtube.com/watch?v=CdLcTaJzTmI