Converge is a set of libraries for working with convergent replicated datatypes (CRDTs) in Clojure and ClojureScript.
https://clojure.org/reference/deps_and_cli#_dependencies Both modules can be imported by specifying a :git/url, :sha, and :deps/root in your deps.edn :deps like the following example:
converge/converge {:git/url "https://github.com/evidentsystems/converge"
:sha "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:deps/root "./converge"}
converge/transit {:git/url "https://github.com/evidentsystems/converge"
:sha "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:deps/root "./transit"}
;; etc.
The main module, converge
, provides a convergent reference type for
Clojure and ClojureScript, with support for various pluggable backends
implementing different convergence algorithms. Its local modification
and access API resembles the behavior of an Atom (i.e. swap!
,
reset!
, and deref
). However, it also has API functions for
accessing (converge.api/peek-patches
, converge.api/pop-patches!
)
patches generated by local modifications, and for applying patches
from the local actor to/from remote actors or merging with a remote
convergent ref (converge.api/merge!
).
The main guarantee provided by this reference type is that local swap!/reset! operations and patching/merging between various distributed actors will converge: that is, two convergent references with the same underlying log of operations will have the same value, regardless of the order in which these references received these operations.
This module also provides two functions for synchronizing convergent
references: converge.api/clock
and converge.api/patch-from-clock
.
Finally, this main module provides the converge.serialize
namespace,
which contains generic functions for transforming converge types in
preparation for serialization/deserialization (used by transit
,
nippy
, etc. modules).
The converge-nippy
module wires up the serialization handlers to
work with nippy
serialization in Clojure.
The converge-storage
module defines a small API for storing,
synchronizing, and fetching convergent refs to/from various storage
systems:
- The local filesystem (also useful with
git
and other VCS) via:converge.storage.filesystem/sync-directory
: initializes new convergent reference storage directory or patches an existing one (by adding a new file to the directory) as needed based on the state of the given in-memory convergent refconverge.storage.filesystem/from-directory
: creates an in-memory convergent reference from contents of a previously sync'd directory
- Other storage systems are under consideration
The converge-transit
module wires up the serialization handlers to
work with transit-clj
and transit-cljs
.
We have high-level plans to provide other functionality commonly used with CRDT, such as implementation of the synchronization protocol atop various communication channels:
- WebRTC
- Websocket
- HTTP
We also plan to support other serialization mechanisms like Fressian.
Finally, we plan to provide a means of tracking/diffing/merging structured data (EDN) alongside the semi-structured data (files, lines, directories) in a Git repository.
⚠️ Converge is beta quality software. Its API and implementation may change. Use at your own risk!
Evident Systems is using Converge in oNote to support real-time and async/repository-based collaboration.
All converge libaries in this repository are subject to the following:
Copyright 2020 Evident Systems LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.