7.8 KiB
OrbitDB
Introduction
Distributed, peer-to-peer database on IPFS.
This is the Javascript implementation and it works both in Node.js and Browsers.
- Client-side database to be embedded in Javascript applications
- Stores all data in IPFS
- Aggregation happens on client side and data is eventually consistent
- Designed to work offline first
Check out a visualization of the data flow at https://github.com/haadcode/proto2
Live demo: http://celebdil.benet.ai:8080/ipfs/Qmezm7g8mBpWyuPk6D84CNcfLKJwU6mpXuEN5GJZNkX3XK/
NOTE: the README can be out of date, I'm working to get up to date. If you find a problem, please open an issue or a PR.
Currently requires orbit-server for pubsub communication. This will change in the future as soon as IPFS provides pubsub.
Data stores
Currently available data stores:
Usage:
const kvstore = orbit.kvstore('db name')
const events = orbit.eventlog('db name')
const feed = orbit.feed('db name')
const counters = orbit.counter('db name')
Documentation for individual stores are WIP, please see each store's source code for available public methods.
Install
npm install orbit-db
Examples
Node.js examples
To run the examples, make sure to run a local orbit-server
Before running the examples, install dependencies with:
npm install
Key-Value store example:
node examples/keyvalue.js <host:port> <username> <channel> <key> <value>
Event log example (run several in separate shells):
node examples/eventlog.js <host:port> <username> <channel> <data> <interval in ms>
Benchmark writes:
node examples/benchmark.js <host:port> <username> <channel>;
Browser examples
Build the examples:
npm install
npm run build:examples
Then open examples/browser.html
or examples/index.html
. See the full example here.
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="../dist/orbitdb.min.js" charset="utf-8"></script>
<script type="text/javascript" src="../node_modules/logplease/dist/logplease.min.js" charset="utf-8"></script>
<script type="text/javascript" src="../node_modules/ipfs/dist/index.min.js" charset="utf-8"></script>
<script type="text/javascript">
const ipfs = IpfsApi();
OrbitDB.connect('localhost:3333', 'user1', '', ipfs)
.then((orbit) => orbit.kvstore('test'))
.then((db) => db.put('hello', 'world'))
.then((res) => {
const result = db.get(key)
console.log(result)
})
</script>
</body>
</html>
API
NOTE: the API documentation is currently out of date. It will be updated soon!
See usage example below
OrbitDB calls its namespaces channels. A channel is similar to "table", "keyspace", "topic", "feed" or "collection" in other db systems.
connect(<host:port>, username, password)
channel(name, password)
.add(data: String) // Insert an event to a channel, returns <ipfs-hash> of the event
.iterator([options]) // Returns an iterator of events
// options : {
// gt: <ipfs-hash>, // Return events newer than <ipfs-hash>
// gte: <ipfs-hash>, // Return events newer then <ipfs-hash> (inclusive)
// lt: <ipfs-hash>, // Return events older than <ipfs-hash>
// lte: <ipfs-hash>, // Return events older than <ipfs-hash> (inclusive)
// limit: -1, // Number of events to return, -1 returns all, default 1
// reverse: true // Return items oldest first, default latest first
// }
.put(key, data: String) // Insert (key,value) to a channel
.get(key) // Retrieve value
.del({ key: <key or hash> }) // Remove entry
.delete() // Deletes the channel, all data will be "removed" (unassociated with the channel, actual data is not deleted from ipfs)
Usage
const async = require('asyncawait/async');
const ipfsAPI = require('ipfs-api');
const OrbitDB = require('orbit-db');
// local ipfs daemon
const ipfs = ipfsAPI();
async(() => {
// Connect
const orbit = await(OrbitClient.connect('localhost:3333', 'usernamne', '', ipfs));
/* Event Log */
const eventlog = orbit.eventlog('eventlog test');
const hash = await(eventlog.add('hello')); // <ipfs-hash>
// Remove event
await(eventlog.remove(hash));
// Iterator options
const options = { limit: -1 }; // fetch all messages
// Get events
const iter = eventlog.iterator(options); // Symbol.iterator
const next = iter.next(); // { value: <item>, done: false|true}
// OR:
// var all = iter.collect(); // returns all elements as an array
// OR:
// for(let i of iter)
// console.log(i.hash, i.item);
/* Delete database locally */
eventlog.delete();
/* KV Store */
const kvstore = orbit.kvstore('kv test');
await(kvstore.put('key1', 'hello world'));
kvstore.get('key1'); // returns "hello world"
await(kvstore.del('key1'));
})();
Development
Source Code
The entry point for the code is src/Client.js and the DB implementation is src/OrbitDB.js
Run Tests
npm test
Keep tests running while development:
mocha -w
Build distributables
npm install
npm run build
TODO
- make ipfs-log emit events ('data', 'load')
- Store: this._log.events.on('data', (log, entries) => this._index.updateIndex(log, entries))
- merge 'readable' and 'data' events (only one)
Notes
Data structure description
For future IPLD references
List snapshots are posted to pubsub:
> QmRzWAiFdLkdkwBDehzxhHdhfwbDKDnzqBnX53va58PuQu
> ...
Get a list snapshot
ipfs object get QmRzWAiFdLkdkwBDehzxhHdhfwbDKDnzqBnX53va58PuQu
{
"Links": [],
"Data": {
"id": "user123",
"items": [
"QmNwREbsgGgiQPXxpvGanD55inFjUXjpEqjiPtpa39P7Mn",
"QmQxndNEzWxKT5KRqRsty7JDGcbPVazaYPCqfB5z1mxmon",
"QmUN1X97M2t8MX55H8VoPGXu2fLBpr91iCAzHkXudSMvDE"
]
}
}
Get the item
ipfs object get QmNwREbsgGgiQPXxpvGanD55inFjUXjpEqjiPtpa39P7Mn
{
"Links": [],
"Data": {
"id": "user123",
"data": "QmasZEUwc67yftPvdSxRLWenmvF8faLnS7TMphQpn4PCWZ",
"next": [
"QmS17ABxzFEVoHv5WEvATetNEZhN2vkNApRPcFQUaJfij3"
]
}
}
Get the item's data (operation)
ipfs object get QmasZEUwc67yftPvdSxRLWenmvF8faLnS7TMphQpn4PCWZ
{
"Links": [],
"Data": {
"op": "PUT",
"key": "default",
"value": "QmaAPEKDdaucQZRseJmKmWwZhgftBSwj8TD1xEomgcxo1X",
"meta":{
"type": "text",
"size": -1,
"from": "user123",
"ts": 1456494484094
}
}
}
Get the value
ipfs object get QmaAPEKDdaucQZRseJmKmWwZhgftBSwj8TD1xEomgcxo1X
{
"Links": [],
"Data": {
"content": "LambOfGod 347",
"ts": 1456494484089
}
}