LiquidRTC - Peer to Peer liquid framework
LiquidRTC is a framework facilitating the development of liquid software in networks without a central authoritative server.
The goal is to have a developer write any single page app they wish and be able to hand that app to the framework as easily as possible. The framework will create connections between the peers automatically and pass that connection object to the developer written app. The connections are strictly between peers with absolutely no intermediate server.
The app can be sent over to any connected peer. The developer can then use this object as they wish, exchanging freeform messages with any number of connected peers.
To meet this goal the framework consists of these parts:
- WebRTC connection wizard
- A simple node.js server and browser code snippet using socket.io to bootstrap the WebRTC handshake
- Program serializer
- Handles user inputted files, inlines them into a single DOM and injects extra javascript to hand the created connection over to the app etc.
- Injected UI elements
- Give the user some way of sending the app to other peers. In the form of an extra button on the upper right hand side corner that opens a menu.
Example
The following example is a walkthough of a minimalistic note-taking app being loaded in one browser, being used, then sent over to another peer and the work continued co-operatively. It focuses on the users view of an application written using the framework. A quick overview of the required code to support the features shown follows this example.
The framework is opened by the user1.
user1 drag & drops the files that make up his app to the page and the app opens in a new tab. The loader has injected an extra button on the top right corner of the page.
user1 clicks "New note", gives the note a name "Idea 1" and writes something down.
his pal, user2 wants to join test the great app, so user2 too opens the framework page. It looks just the same as it did for user1 earlier. At this point the framework will have created a peer-to-peer connection between user1 and user2 without any extra work from either of them.
user1 now clicks the button the framework added to his app and a menu opens. From the select box he selects 'user2' and clicks 'send'. The application opens in user2's browser*. This program was sent directly from one browser to another, neither the http-, nor the socket.io-server ever saw any of it.
The way the note app was written, the notes get synchronized only when it is changed. user1 makes a change to the note and it gets sent over to user2. Similarly user2 adds something to the note and user1 sees the changes immediately.
user1 gets another idea and adds a new note "Idea 2". He starts writing down this new note. user2 can see a new note appeared to the list of notes, but continues writing the first note.
Both users do have both of the notes. Any number of extra peers can join the app and will get all the notes written. If any of the peers chooses to create a new note all the peers will immediately get to know about the note and can watch it being written or even join in writing.
This example was extremely simple with automatic synchronization. The developer can however choose how they wish to use the provided connectivity, for example have a button to send the state as there was for sending the application.
*) If he has given permission for js to open pop-ups
Code
The following is a high level overview of the framework on the developer side. It is not intended to give all the details required for creating apps with the framework.
The program loader injects the required code to create the connection between peers automatically, but all state synchronization is left for the developer. The framework exposes a global function init_datasignal , which need to be passed a callback that accepts a pseudo WebRTC data channel. This data channel has functions on that takes two parameters, a message type and a function how to handle this message, send which is used to send a message to selected peers and broadcast to send the same message to all other peers.
To listen to state change messages, our note-taking application has the following code:
if(typeof(init_datasignal) === 'function') {
init_datasignal( function(ds) {
ds.on('editor-state', function(msg) {
update_note(msg.note, msg.msg);
});
broadcast = ds.broadcast;
});
}
var update_note = function (n, t) {
if(notes[n] === undefined) {
createNote(n);
}
if(currentNote == undefined) {
selectNote(n);
}
notes[n] = t;
if(n == currentNote) {
$('.editor').val(notes[currentNote]);
}
};
update_note is completely oblivious about WebRTC. Any synchronizing method would require similar, if not the same function.
To send the changes, we saved the ds.send function as broadcast that we can now use.
var syncNote = function (n) {
var msg = {};
msg.note = n;
msg.msg = notes[n];
broadcast('editor-state', msg);
};
$('.editor').on("change keyup paste", function() {
if(notes[currentNote] != $(this).val()) {
notes[currentNote] = $(this).val();
syncNote(currentNote);
}
});