jsonsync
v0.2.0
Published
Transport-agnostic operation-rich peer-to-peer JSON synchronization
Downloads
13
Maintainers
Readme
JsonSync
Transport-agnostic operation-rich peer-to-peer JSON synchronization
Derived from the Canop paper.
var JsonSync = require('jsonsync')
// network must have network.on('connect', function(node))
// and network.on('disconnect', function(node)),
// network.nodes must be an array of Nodes,
// which have node.send(string), node.on('receive', function(string)).
var data = new JsonSync({network: network})
// Showing changes.
data.on('update', updateView)
// Performing a local change.
data.add('/comments/-', "This article was flabberghasting.")
data.remove('/comments/0')
- Browser and Node.js
- Client-client, client-server, peer-to-peer networks
- Relies on JSON Patch
- Supports atomic compound operations
Please note that this is not ready for production. The protocol, in particular, is subject to change. On the other hand, for demos and personal projects, go right away!
API
.add(path, value)
.remove(path)
.replace(path, value)
.move(fromPath, toPath)
To perform an atomic compound operation (ie, a sequence of operations that must happen in that order with no concurrent operation inserted within them):
var value = data.get(origin)
var op = data.remove(origin) // First operation
data.replace(target, value, {after: op}) // Second operation
Cons
Currently, we do not guarantee intention preservation. Operations are not rebased to readjust indices based on concurrent operations. This precludes its use for character-by-character concurrent text editing. There is hope, however.
There is no lazy loading of huge lists. You get the whole JSON, and it has to be fully loaded on your node. If some JSON objects are too big, you can separate them into several JsonSync objects. For instance, if you have a chat app, you would have a separate object for each 10k messages, and your app could fetch the previous batch if it needs to go further in history.
Currently, you need to keep (and download) the whole history. We will make it possible in the future to also support automatic deletion of history that all nodes have in common, but if you enable that, it will preclude normal offline editing. (You will be able to do offline editing by performing a JSON diff when you reconnect, but your operations may be severely non-intention-preserving, requiring manual verification.)
Integration
┌──────────┐ action ┌───────┐
│CONTROLLER├───────→│ │ broadcast ┌─────────┐
└──────────┘ │ JSON │←─────────→│ NETWORK │
┌──────────┐ update │ MODEL │ └─────────┘
│ VIEW │←───────┤ │
└──────────┘ └───────┘
JSON Patch extensions used
mark
: a list of integers providing a unique timestamp.was
: stores the old value of a destructive operation. It allows performing undo without having to recompute everything from the beginning.- string add and remove: (planned) allows string editing.
arithmetic
: (planned) supports performing operations on numbers. For instance,{op: "arithmetic", path: "/score", value: "max(2*x^2, y)", var: {y: "/minScore"}
.
Warnings: (mostly designed to ensure operational reversibility)
- The use of the
add
operation on objects is strictly meant for the addition of a brand new key. JSON operations that perform an add on an object where the key already exists perform no modification. Usereplace
to update the value of a key. - The
copy
andmove
operations must not havepath
be a proper prefix of thefrom
location; ie., a location cannot be moved nor copied to one of its ancestors. Similarly, they must not havefrom
be a proper prefix of thepath
location. (For move operations, the latter is already enforced by the JSON Patch specification.) Finally, they must never overwrite a value.