At the last IndieWeb Dinner, we discussed implementing realtime display of indieweb comments when viewing a note. This is analogous to when you're looking at a post on Facebook and someone adds a comment, it shows up automatically with no page refresh.
Given the realtime nature of webmention, I was able to add this feature to p3k in just one evening!
The video below is a demonstration of realtime comments on one of my posts in p3k! Unfortunately it's me commenting on my own post, but you get the idea.
The left window shows what someone sees when viewing a post.
The right window is me typing a reply to my note. After I click "post," the note is posted, which sends a webmention to the "in-reply-to" URL, which the left window picks up on through the Websockets connnection!
There is a slight delay between when the note is posted on the right and when it appears on the left, mostly because I was tethered to my phone's Internet in the middle of San Francisco with poor reception.
Show me the code!
Below is the code that makes this possible.
Client-Side WebSockets
First, the browser makes a WebSocket connection to my server. It sends the URL the browser window is currently open to which registeres a listener on the server. You can see the live version of this code at the bottom of the source code of this page.
var commentContainerSelector = '.references ul';
if($(commentContainerSelector).length > 0 && "WebSocket" in window) {
var ws = new WebSocket(window.location.origin.replace("http","ws")+":8077");
ws.onopen = function(event) {
// Send the current window URL to the server to register to receive notifications about this URL
ws.send(window.location);
};
ws.onmessage = function(event) {
var data = JSON.parse(event.data);
if(data && data.type == "webmention") {
// Check if we've already added a comment for this ID, and update the existing one if so
if($("#"+data.element_id).length == 0) {
$(commentContainerSelector).append(data.html);
} else {
$("#"+data.element_id).html(data.html);
}
}
};
}
WebSocket Server
The server script is literally the code below.
var WebSocketServer = require('ws').Server;
var Redis = require('redis');
var port = 8077;
var wss = new WebSocketServer({port: port});
wss.on('connection', function(ws) {
// console.log("New websockets connection");
ws.on('message', function(message) {
var redis = Redis.createClient(6379, 'localhost');
var channel = 'replies::' + message;
redis.subscribe(channel);
// console.log('Listening for comments on channel ' + channel);
redis.on('message', function (channel, message) {
console.log('Sent comment to channel ' + channel);
ws.send(message);
});
ws.on('close', function(){
// console.log('Killing listener for channel ' + channel);
redis.unsubscribe();
redis.end();
});
ws.on('error', function(){
// console.log('Killing listener for channel ' + channel);
redis.unsubscribe();
redis.end();
});
});
});
console.log("WebSocket Server Listening on port "+port);
This simply sets up a WebSocket server that echos messages received on a Redis pub/sub channel to a WebSocket listener.
The Glue
The piece that brings it to life was simply a matter of adding a little bit of code to my code when a new webmention is received by my server.
At the bottom of my webmention handling code, I added these four lines of code.
<?php
ob_start();
p3k\Site::displayComment($sourceURL); // Renders the comment HTML
$html = ob_get_clean();
redis()->publish('replies::' . $targetURL, json_encode(array(
'type' => 'webmention',
'element_id' => 'external_' . preg_replace(array('/[\/:\.]+/'), array('_'), $sourceURL);,
'html' => $html
)));
?>
This works great since I already have a method in p3k which handles rendering an HTML version of a comment given a URL. I just broadcast the HTML on a Redis channel matching the URL of the comment.
How can you get started?
You can try adding a comment in realtime to one of my notes! Try replying to the test note I posted here.
You'll need to:
- Write a reply to my note on your own site, linking to my note (See indiewebcamp.com/comment for more details)
- Optionally add h-entry markup (it will look better if you do!)
- Send me a webmention from your site or by simply pasting the URL in the webmention form at the bottom of my note.
You should nearly instantly see your reply appear on my site!
http://aaronparecki.com/articles/2013/10/13/1/realtime-indieweb-comments
I only mentioned the idea at the @indiewebcamp dinner at 21st Amendment http://aaronparecki.com/events/2013/09/30/1/indieweb-dinner-at-21st-amendment and he's already implemented it live on his site! ...