Sending Data via WebSockets

Hi all,

I've been working on a project for my company these last couple weeks trying to see if we can switch over our mapping system to Cesium. I'm only on an internship, (this is my first experience using javascript), so please forgive any gaps in knowledge.

The problem I've been stuck on the last couple days has been figuring out a way to use WebSockets to send position data/czmls to node.js server that is running Cesium. I've found a lot of tutorials and documentation on setting up a socket in java, but I'm struggling to figure out where to put the corresponding listener in the Cesium code.

https://groups.google.com/forum/#!searchin/cesium-dev/web$20socket/cesium-dev/3QPoAVijMq0/9i7fN1TI6i0J

I found this thread, and the example code given makes sense for handling reading-in/processing the czml file. The part I don't understand is where the call for the onMessage function would go? Would I want to add it into the "CesiumViewer.js" for example, or into the "server.js" that gets run by node.js to start the server?

Best,
Chris

You put the onMessage function in your client-side app. It can go anywhere. Once a websocket message comes in, you just have to get a reference to your Cesium viewer and add the datasource accordingly.

For example, I have an index.html web page that has a script called init.js. My onMessage function is in init.js, but I could have put it in index.html or anywhere else. In the onMessage function, I have this code:
var dataSource = new Cesium.GeoJsonDataSource();
viewer.dataSources.add(dataSource);
dataSource.load(jsonResponse.schedules[0].geoJson);

``

The variable ‘viewer’ is my Cesium viewer, defined higher up, outside the onMessage function. jsonResponse.schedules[0].geoJson is a geoJson-formatted list of polygons and lines.

Bart

Thanks for the help! I'm definitely much closer to what I'd like, but its not quite there yet. What I've done now is basically set up a second server in the server.js class that listens on a separate port. This does connect to the java method. For example, if I send a czml file through the socket it gets written to the directory where server.js is, but I can't figure out how to then send this data to a Viewer instance. I know this probably isn't the right way to do it, along with just being bad form.

I'm trying to implement the way you explained, but whenever I try to make a socket listen inside a javascript file that gets called by the index.html my java method errors out because it can't connect to the port. I feel like I am probably just using the wrong syntax somewhere, but I'm not sure. Also what npm package do you use for setting up your sockets?

Chris

Hi,

Don't know if I understood correctly what you are trying to accomplish. What I understood is you have a server in node.js that is serving the Cesium page, you want to connect a websocket to this server in order to exchange data between the server and different clients that connect to them?

A library that I use for websockets in node.js is Socket.io ( http://socket.io/ ), another module I usually use is Express.js (for the webserver part). You can create a socket.io instance and listen to the same port as the normal webserver:

var app = require('express')();
var http = require('http').Server(app); // Normal HTTP server
var io = require('socket.io')(http); // Attach Socket.io to the HTTP server in order to listen to the same port

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(80, function(){
  console.log('listening on *:80');
});

On the client you could have something like:

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io(); // here you can set a custom IP / Port. The default is to connect to the server that serves the page
</script>

With this you have all Clients connected to the socket.io server, and you can exchange information by triggering events either on the server or on the client.
So lets imagine you want to listen for events containing CZML objects from the server. On the client you would add a listener:

socket.on('czmlObject', function(msg){
    // Msg comes in JSON format and contains the data sent by the server
});

The server can then trigger this event when needed. You can send to a specific socket (by keeping track of the connections to the server) or send to every connected socket. So lets imagine a client sends data to the server and the server sends to all clients connected except the sender:

// Client
socket.emit('data', {...}); // send some JSON object to the server

// Server
io.on('connection', function(socket){
  console.log('a user connected');
  
  socket.on('data', function(msg) {
    socket.broadcast.emit('czmlObject', msg);
  });
});

Hope this helps you in some way. If what understood of your issue is wrong, then try to clarify and maybe I can help you.

Terça-feira, 16 de Setembro de 2014 15:51:26 UTC+1, Chris M. escreveu:

Hi,
Thanks for the advice, socket.io looks promising! I haven’t finished trying to add it in to my work yet, but I wanted to clarify what I’m trying to accomplish. For reference, I am using the Cesium Viewer application that is already built as my base.
Overview: MatLab Data --> Java Method –(through socket)–> Node.js Cesium Server --> Viewer/czmlDataSource --> Drawn

So basically I’m starting with a matrix of positions/velocities in MatLab (don’t worry about formatting them to czml, I’m going to take care of all this). In order to send this data to Cesium I am using a java method since java has well developed tools for sockets and you can use java classes in MatLab. Finally I want this java method to send this data to CesiumViewer.js to represent this data in the viewer.

The main pain point for me right now is that I am basically tacking on a second server at the end of the “server.js” file that goes like this:

var javaServer = require(‘net’).createServer();
var fs = require(‘fs’);

javaServer.on('connection', function (javaSocket) {
    var clientAddress = javaSocket.address().address + ':' + javaSocket.address().port;
    console.log('Java ' + clientAddress + ' connected');

    javaSocket.on('data', function(data) {
        fs.writeFile('test.czml', data);
    });

    javaSocket.on('close', function() {
        console.log('Java ' + clientAddress + ' disconnected');
    });
});

javaServer.listen(80);

process.on('SIGINT', function() {
    server.close(function() {
        process.exit(0);
    });
    javaServer.close();
});

``

From this I am not able to figure out a way to push the czml file to the CesiumViewer.js script so that it is able to draw it. This could be the wrong approach entirely. If I try adding the fs.write into the existing server.on(‘connection’, …) that is pre-built nothing happens.

Hopefully that makes a bit more sense, let me know if it needs further clarification.

Chris

Ok, so your server.js will act as "proxy" between the Java application and the CesiumViewer. For simplicity you could try to connect your Client side to your Java server through Websockets, there must be some libraries for that (theres a socket.io implementation).

From what I can see you are missing the connection between the server.js and the CesiumViewer, which could be built with socket.io or another websocket implementation for node.js. If you don't need to distinguish connections, you can just set the library on the server side like you did for the Java socket (but on another port or on the same port of the http server), you import the library on the client side, connect to the server and set the listener for the 'data' event, the server when receives 'data' from the javaSocket sends it to the client through the socket.io (or another).
As long as you have a listener in your Javascript code on the client you can simply trigger it. This listener can be anywhere as long as you have access to the Cesium objects that you need for displaying the data:

So: MatLab Data --> Java Method --(through socket)--> Node.js Cesium Server <- socket.io -> Viewer/czmlDataSource --> Drawn

// Client code
<script src="/socket.io/socket.io.js"></script>
<script>
var viewer = Cesium(...);

var socket = io();

socket.on('data', function(msg){
// Do all the Cesium magic here
});
</script>

// Server code
var io = require('socket.io')(server);

io.on('connection', function(socket){
console.log('a user connected');
});

javaServer.on('connection', function (javaSocket) {
javaSocket.on('data', function(data) {
fs.writeFile('test.czml', data);

    io\.emit\(&#39;data&#39;, data\);
\}\);

});

With io.emit('data', data); you can send the data to every client connected to the server.
Even if you don't use socket.io and try another library, the way they work will be similar, as long as you have a socket connected to the client you can send a message to it (by triggering some event), you just have to make sure about the scope of your variables.

In terms of drawing the data, I'm new to Cesium and haven't really tried the CZML functionality, so if there are issues there I can't help you.

Sexta-feira, 19 de Setembro de 2014 14:55:56 UTC+1, Chris M. escreveu:

I’ve managed to finally get socket.io running this morning, thanks again! That’s an awesome bit of software. I know you mentioned you don’t have much experience with czmls yet, but I’m having a problem getting the data passed through the websocket drawn.

When I pass the data through from the java method, I get a Developer Error “uncaught exception: RuntimeError: The first CZML packet is required to be the document object.” in the browser console. The error throw is very long, but the rest of it is just references to different built in javascript functions for Cesium. Going through where the error points, I believe the problem is that the viewer is trying to render the czml file before its completely sent causing a major error. I wasn’t able to find anything related to this with a bit of googling, and I was wondering if you had any thoughts on getting the websocket client to wait for the whole file to be received before trying to do anything with it? Or if my interpretation of this error is incorrect and something else is not working as intended?

Chris

Actually I was wrong, the problem is that the websocket is being sent as a buffer array. I’m not sure how to convert this back into the original czml data? I tried the buf.toString() and buf.toJSON() from the node.js documentation, but it didn’t do anything.

Hello Chris, so you managed to make Cesium work with socket.io? I am really struggling with it at the moment (I am not really a coder..), do you think maybe you could post your source code? That would be really great!