Legion
Legion lets you easily create or extend web applications with peer-to-peer interactions!
Legion offers:
- Mutable data objects.
- Transparent peer-to-peer synchronization.
- Offline operation.
- Durability on the server.
- No Concurrency-issues!
- Secure data-sharing and access control.
With peer-to-peer enabled, your get lower client-to-client latency, reduced server load and disconnected operation!1
The code to run your own is available on github: https://github.com/albertlinde/Legion
Legion is under continuous development and not production-stable. Work in progress:
- Peer-to-peer coordination (to lower the amount of resources required on the central server).
- Peer-to-peer caching.
- Peer-trust (i.e., preventing cheating).
- Additional overlay choices.
- Additional CRDTs.
Legion was partially supported by the European projects Syncfree. and Lightkone, and FCT/MCTES project PTDC/CCI-INF/32662/2017, Lisboa - 01 - 0145 - FEDER - 032662 (SAMOA). The Legion development team combines researchers from the Informatics Department, FCT, NOVA University of Lisbon and the NOVA LINCS Laboratory in Portugal and researchers from the Technische Universität Kaiserslautern in Germany.
Part of the computing resources used for this work were supported by an AWS in Education Research Grant.
API usage
The following code shows how the Legion framework can be used at the client.
var options = { client_id: randInt(), client_secret: randInt() //ex: username, pwd }; var legion = new Legion(options); //New Legion instance. var groupOptions = { id: "default", secret: "default" //ex: chat rooms with login keys }; legion.joinGroup(groupOptions, function (group) { //joins a group of peers var objectStore = group.getObjectStore(); //object manipulation var messageAPI = group.getMessageAPI(); //message sending (...) });
Data types
The main use of legion is sharing mutable-data between users.
Operations executed on any object are propagated between peers directly when connected, and through the server between network-partitioned peers. Propagation of changes is done always respecting causal order
The available data types are Counters, Sets, Maps, and Lists. These are implemented as Delta-CRDTs3, meaning any concurrency conflicts are automatically resolved!
All data types can be instantiated with legion.DATA_TYPE. All clients connected to the group will replicate this object. Details on restricting creating new objects can be found within the GitHub tutorials.
Counter
Counters are used to share an integer value between users. Counters can be incremented and decremented by any value.
var counter = objectStore.getOrCreate("counterID", legion.Counter); counter.increment(1); //Argument must be >= 1 counter.decrement(1); //Argument must be >= 1 counter.increment(138); //Argument must be >= 1 counter.decrement(138); //Argument must be >= 1 console.log(counter.getValue()); //Returns the current value. counter.setOnStateChange(function (updates, meta) {//called when data is updated console.log(updates); console.log(meta); });
Counter | Add(1) | Remove(1) | Value |
---|---|---|---|
1 | |||
2 | |||
3 |
Set
Sets keep objects only once.
var set = objectStore.getOrCreate("setID", legion.Set); set.add(element); //Ads if not existing. set.remove(element); //Removes if exists. console.log(set.asArray()); //Array of elements console.log(set.contains(element)); //Boolean console.log(set.size()); //Number set.setOnStateChange(function (updates, meta) {//called when data is updated console.log(updates); console.log(meta); });
Set | Add(element) | Remove(element) | Elements |
---|---|---|---|
1 | |||
2 | |||
3 |
Set 1 Elements
Set 2 Elements
Set 3 Elements
Map
Maps keep key-value pairs.
var map = objectStore.get("mapID", legion.Map); map.set(key, value); //Adds a key-value pair map.get(key); //Returns value for given key. map.delete(key); //Deletes the key-value pair. console.log(map.asArray()); //Array of pairs console.log(map.keys()); //Array console.log(map.values()); //Array console.log(map.contains(element)); //Boolean console.log(map.size()); //Number map.setOnStateChange(function (updates, meta) {//called when data is updated console.log(updates); console.log(meta); });
Map | Set(key, value) | Delete(key) | # Keys |
---|---|---|---|
1 | |||
2 | |||
3 |
Map 1 Elements
Map 2 Elements
Map 3 Elements
List
Lists keep a ordered list of elements.
var list = objectStore.get("listID", legion.List); list.add(pos, element); //Adds an element to given position list.delete(pos); //Removes current element at given position list.get(pos) //Returns the element at given position console.log(list.asArray()); //Array of elements console.log(list.size()); //Number list.setOnStateChange(function (updates, meta) {//called when data is updated console.log(updates); console.log(meta); });
Input
List | Add(pos, value) | Remove(pos) | Length |
---|---|---|---|
List 1 | |||
List 2 | |||
List 3 |
List 1 Elements
List 2 Elements
List 3 Elements
Messaging
Besides sharing objects, legion can also be used to send messages directly to the group.
Currently supported primitives are broadcast and unicast.
messageAPI.setHandlerFor(String, Function(arg)); messageAPI.broadcast(String, *); //JSON.stringify(*) must parse. //example: messageAPI.setHandlerFor("Message", function(message){ //use messsage.data }); messageAPI.broadcast("Message", {value: "Hi.", from:"Albert"});
Messaging example
References
1 Legion White Paper: PDF
2 Legion WWW'17 Conference Paper: [PDF] [ACM] [Bib]
3 Delta CRDTs: [PDF] [ACM] [Bib]
Copyright Notice: The reports contained in this page are included by the contributing authors as a mechanism to ensure timely dissemination of scholarly/technical information on a non-commercial basis. Copyright and all rights therein are maintained by the authors, despite the fact they have offered this information electronically. It is understood that all individuals copying this information will adhere to the terms/ constraints invoked by each author's copyright. Reports may not be copied for commercial redistribution, republication, or dissemination without the explicit permission of the authors.
Contact
Webpage: Albert van der Linde