Skip to content

3: Control the logger from the server

Kristian Saksvik Munkvold edited this page Feb 17, 2016 · 6 revisions

In this assignment we'll use our socket-connection to tell the logger to run speedtests at regular intervals, and send the results back to the server, who'll pass it along to the client. In addition the server will ask the logger for the speedtest history when a new client connects, and pass this history along to the client. The image below illustrates how the client, server and logger events will be sent between the applications

client server


Setup

Navigate to the 'every-bit-matters' folder. Type:

    $ git checkout -f stage-3

Nice. You have now checked out the code required to start. Let's begin.

Making the server run speedtests at regular intervals

Let's start by making our logger run speedtests when it receives a logger:run event from the server. We can do this by adding a socket.on('logger:run', .... handler, and move our speedtest code into the callback function of this handler.

This should make logger.js look something like this:

logger/logger.js

var speedtest = require('speedtest-net');
var fileSystem = require('fs');
var test = speedtest();
var fileName = __dirname + '/history.json';
var history = JSON.parse(fileSystem.readFileSync(fileName));
var socket = require('socket.io-client')('http://localhost:3000/');

socket.on('connect', function () {
    console.log('Logger is connected'); // Or 'Looksies! We got ourselves a user!'
});

socket.on('logger:run', function () {
    console.log('Starting speedtest...');

    test.on('data', function (data) {
        var result = {
            download: data.speeds.download,
            upload: data.speeds.upload,
            ping: data.server.ping,
            date: Date.now()
        };

        history.push(result);

        var jsonResult = JSON.stringify(history);
        fileSystem.writeFile(fileName, jsonResult, function (err) {
            if (err) {
                console.log('Something went wrong: ' + err);
            } else {
                console.log('Speedtest finished');
            }
        });
    });

    test.on('error', function (err) {
        console.error(err);
    });
});

Now we have to update server.js so a logger:run event is emitted at regular intervals. One way of doing this, is by using a setInterval() function. setInterval takes two arguments, the first is a callback function, specifying what to do, and the second is a number, representing the interval time in milliseconds.

Update server.js to include the following:

server.js

...
setInterval(function () {
    io.emit('logger:run');
}, 30000);

app.use('/', express.static('client'));
...

We also want the logger to send the result of the speedtest back to the server, so let's emit a server:results event when the speedtest is done, and pass the results and history along with it.

logger/logger.js:

...
        history.push(result);
        socket.emit('server:results', history);

        var jsonResult = JSON.stringify(history);
...

Now we need to handle the server:results event on the server. Extend the 'connect' callback function to include a handler for server:results, and emit a new client:display event that the client can use to receive the data and display them.

server.js

io.on('connect', function (socket) {
    console.log("Someone connected.");

    socket.on('server:results', function (data) {
        io.emit('client:display', data);
    });
});

Displaying the results in the client

Now we just need to update client.js to handle 'client:display' and print the results to the console.

client/client.js:

var socket = io();

socket.on('connect', function (data) {
    console.log("I am connected");
});

socket.on('client:display', function (data) {
    console.log(data);
});

Requesting speedtest history when a client connects to the server

It's tedious to wait until the next speedtest is finished, before data is shown in the client, so we want to send the history from the logger when a client connects.

To do this, we have to add an additional logger:history handler to logger.js.

logger/logger.js:

...
socket.on('logger:history', function () {
    socket.emit('server:results', history);
});
...

We'll reuse the server:results event, in order to pass the data to the server and client.

In addition, we'll have to extend the 'connect' callback function in server.js to emit logger:history.

server/server.js:

...
io.on('connect', function (socket) {
    console.log('Looksies! We got ourselves a user!');
    io.emit('logger:history');
...

Testing it all out

You should now have a server.js file looking something like this...

server/server.js:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;

io.on('connect', function (socket) {
    console.log('Looksies! We got ourselves a user!');
    io.emit('logger:history');

    socket.on('server:results', function (data) {
        console.log("server:results");
        io.emit('client:display', data);
    });
});

setInterval(function () {
    io.emit('logger:run');
}, 30000);

app.use('/', express.static('client'));

http.listen(port, function () {
    console.log('Running our app at http://localhost:3000')
});

...a logger.js file looking something like this...

logger/logger.js:

var speedtest = require('speedtest-net');
var fileSystem = require('fs');
var test = speedtest();
var fileName = __dirname + '/history.json';
var history = JSON.parse(fileSystem.readFileSync(fileName));
var socket = require('socket.io-client')('http://localhost:3000/');

socket.on('connect', function () {
    console.log('Logger is connected');
});

socket.on('logger:history', function () {
    socket.emit('server:results', history);
});

socket.on('logger:run', function () {
    console.log('Starting speedtest...');

    var test = speedtest();

    test.on('data', function (data) {
        var result = {
            download: data.speeds.download,
            upload: data.speeds.upload,
            ping: data.server.ping,
            date: Date.now()
        };

        history.push(result);
        socket.emit('server:results', history);

        var jsonResult = JSON.stringify(history);
        fileSystem.writeFile(fileName, jsonResult, function (err) {
            if (err) {
                console.log('Something went wrong: ' + err);
            } else {
                console.log('Speedtest finished');
            }
        });
    });

    test.on('error', function (err) {
        console.error(err);
    });
});

...and a client.js file looking something like this.

client/client.js:

var socket = io();

socket.on('connect', function (data) {
    console.log("I am connected");
});

socket.on('client:display', function (data) {
    console.log(data);
});

As we did in stage 2, start both the server and the logger, and open our web-page at http://localhost:3000/. Then open two terminals and have the browser ready.

Terminal 1. Run:

> node server.js

Server running on http://localhost:3000/

Terminal 2. Run:

> node logger/logger.js
Starting speedtest...

And finally open the web-page in the browser. Verify that the history is printed to the console in the browser, and that the server runs new speedtests. When the speedtest is done, check that the new resusts is printed in the browser.

Next assignment: Make-a-visualization-in-the-client