Project dependency
Add this to your project dependencies:
You can just load replikativ as a library.
Global namespace
The datatypes for state management are organized in a global namespace which allows you to address and share state with other peers and applications. Each datatype is addressed by a user and a globally unique uuid:
Peer setup
Next you need to set up a peer. One can either integrate it with your http server through a ring-middleware or start directly a dedicated peer.
Finally you can interact with the peer through a stage. The stage provides the API to the peer for applications.
Now lets provide the datatype for our application:
For test purposes we set up another peer similarly.
Now you are set up :).
State changes
[['assoc [:name "Peter"]]]
is encoding a user-defined function application to
apply to some associative local state. Note that you should use the same key (or
one that can be mapped one-to-one).
Now let us wire the peers up:
Do they converge?
Feel free to play around :) Finally you can release the network connections by finishing the peers.
Streaming
Direct state access as done above can be cumbersome, as you want to react on all state changes in your application logic. By mutating replikativ and reacting to state changes from the whole system, you can let the state flow in a circle in your local application and gain a functional pipeline.
Let’s stream the OR-Map changes into an associative datastructure like a map in
an atom. To do so we define runtime functions which interpret the streamed
transactions with the eval-fn
map:
These are in effect a reduction over the identity applying the functions in the order provided by the datatype (details follow in the next section).
Now we start a stream of function applications on the identity of the val-atom
.
That way you can decide locally when you want to access the data and how to
interpret it for your desired identity type. Instead of an atom this can very
well be Datomic or a database of your choice. If you
provide an optional :applied-log
key, the identity will be treated as durable
and changes will only be applied once also after system restarts.
Order of events
It is important to note that the streaming functions you provide follow the
semantics of the datatypes you use. In an OR-Map for instance no order of
assoc
or dissoc
transactions is provided, the only guarantee is that you see
a corresponding dissoc
after its assoc
.
To get order with strong consistency semantics, e.g. if you cannot use a default conflict resolution mechanism of a CRDT, you can use CDVCS.
Shutdown
The ClojureScript API is the same, except that you cannot have blocking IO and cannot open a websocket server in the browser (but we have already WebRTC in mind ;) ):