Using node.js to update HTML via external script?

I'm trying to set up a Node.js application that will serve up an HTML page in the front-end while pinging an IP. The end result will hopefully be a static web page that will display the status of the IP being pinged.

I have the HTML page running just fine using Express. It's basically just a static file with a single <a> whose text and color is changed by an external script. Temporarily, I have a button to toggle the displayed status, and so far it's looking good.

Question is, how do I update the HTML based on the result gotten from the Pinger (explained below)?

I have two Node.js source files. Obviously, the main one is server.js:

var express = require("express"),
app     = express(),
Pinger  = require("./pinger");

app.use(express.static(__dirname));
console.log("Using static files at /");
app.use("/styles", express.static(__dirname + '/styles'));
console.log("Using stylesheets at /styles");
app.use("/res", express.static(__dirname + '/res'));
console.log("Using resources at /res");

app.listen(3000);
console.log("Listening on port 3000");

var pinger = new Pinger('google.com'); /* how the instance would be created */

And there's the Pinger module:

var ping  = require('ping');

var Pinger = function() {

    this.host = arguments.length > 0 ? arguments[0] : 'google.com'; 
    this.isOnline = false;

    this.pingAll = function pingAll() {

        console.log(">>PING: " + host);
        ping.sys.probe(host, function(isAlive) {
            if (isAlive) console.log(">>PONG: " + host);
            else console.log("Unable to reach " + host);
        });

        // somehow return isAlive

    };

};

module.exports = Pinger;

Obviously, right now, the pinger's isOnline can only be false because it's never updated.

On a side note, how would I be able to update isOnline from inside the ping.sys.probe callback? I'm aware of the different scopes, and I'm pretty sure that just using this.isOnline = isAlive would be useless because this would refer to the callback (unless I'm wrong in the first place and over-thinking it).

You would need to switch to a templating engine and make the page dynamic. You call back could call the res.send / res.end function with the completed template, which would get pushed back to the client. Checkout jade or coffeekup, if its simple just build the html in a function rather than using an external template.

You are correct, this will refer to the scope of the callback function. What you can do though is create a reference to this of the pinger function.

Func = function () {
   var self = this;
   self.isOnline = false
   asyn(function (online) {
      self.isOnline = online;       
   }
}

self will be a reference to this of Func.

As for the communication between your static page and your server, you could simple set up a Ajax request to the server which would simple return pinger.isOnline. Or you could go to the extent of using something like socket.io if you wanted.

app.get('/ping', function (req, res) {
   res.json(200, {"ping": pinger.isOnline});
}

Now if you request /ping you will get a response with the value of your pinger.

You could also use socket.io:

npm install socket.io

Once you've set the isOnline from inside Pinger, in server.js:

var socketio = require('socket.io');
var io = socketio.listen(app);

io.sockets.on('connection', function(socket) {
  var msg = 'Cannot reach host';
  if (pinger.isAlive) {
    msg = 'Host is reachable';
  }
  socket.emit('ping result', {
    msg: msg
  });
});

From one of your client javascript:

// client.js
var socket = io.connect();

socket.on('ping result', function(data) {
  $('div.ping-result').html(data.msg);
});

In your html:

<script src="javascripts/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="javascripts/client.js"></script>

<div class="ping-result"></div>