Fixing lists
This commit is contained in:
parent
1d70af0e86
commit
57c006feb2
@ -4,9 +4,10 @@ var async = require('asyncawait/async');
|
||||
var OrbitClient = require('../src/OrbitClient');
|
||||
var Timer = require('./Timer');
|
||||
|
||||
// Redis host
|
||||
var host = '178.62.229.175';
|
||||
var port = 6379;
|
||||
// orbit-server
|
||||
// const host = 'localhost';
|
||||
const host = '178.62.241.75';
|
||||
const port = 3333;
|
||||
|
||||
var username = 'testrunner';
|
||||
var password = '';
|
||||
|
@ -5,17 +5,18 @@ const await = require('asyncawait/await');
|
||||
const OrbitClient = require('../src/OrbitClient');
|
||||
const Timer = require('./Timer');
|
||||
|
||||
// Redis
|
||||
// orbit-server
|
||||
const host = 'localhost';
|
||||
// const host = '178.62.241.75';
|
||||
const port = 3333;
|
||||
|
||||
const username = 'LambOfGod';
|
||||
const username = process.argv[3] ? process.argv[3] : 'LambOfGod';
|
||||
const password = '';
|
||||
|
||||
let run = (async(() => {
|
||||
try {
|
||||
const orbit = OrbitClient.connect(host, port, username, password);
|
||||
const channel = 'testing123';
|
||||
const channel = process.argv[2] ? process.argv[2] : 'testing123';
|
||||
const db = orbit.channel(channel);
|
||||
|
||||
let count = 1;
|
||||
@ -23,7 +24,7 @@ let run = (async(() => {
|
||||
while(true) {
|
||||
const key = "username";
|
||||
let timer = new Timer(true);
|
||||
db.put(key, "Lamb Of God " + count);
|
||||
db.put(key, username + " " + count);
|
||||
let v = db.get(key);
|
||||
|
||||
console.log("---------------------------------------------------")
|
||||
|
50
examples/keyvalueReader.js
Normal file
50
examples/keyvalueReader.js
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const async = require('asyncawait/async');
|
||||
const await = require('asyncawait/await');
|
||||
const OrbitClient = require('../src/OrbitClient');
|
||||
const Timer = require('./Timer');
|
||||
|
||||
// orbit-server
|
||||
const host = 'localhost';
|
||||
// const host = '178.62.241.75';
|
||||
const port = 3333;
|
||||
|
||||
const username = process.argv[3] ? process.argv[3] : 'LambOfGod';
|
||||
const password = '';
|
||||
|
||||
let running = false;
|
||||
let run = (async(() => {
|
||||
if(!running) {
|
||||
try {
|
||||
running = true;
|
||||
const orbit = OrbitClient.connect(host, port, username, password);
|
||||
const channel = process.argv[2] ? process.argv[2] : 'testing123';
|
||||
const db = orbit.channel(channel);
|
||||
|
||||
let count = 1;
|
||||
|
||||
setInterval(async(() => {
|
||||
const key = "username";
|
||||
let timer = new Timer(true);
|
||||
let v = db.get(key);
|
||||
|
||||
console.log("---------------------------------------------------")
|
||||
console.log("Key | Value")
|
||||
console.log("---------------------------------------------------")
|
||||
console.log(`${key} | ${v}`);
|
||||
console.log("---------------------------------------------------")
|
||||
console.log(`Query #${count} took ${timer.stop(true)} ms\n`);
|
||||
|
||||
count ++;
|
||||
running = false;
|
||||
}), 1000);
|
||||
} catch(e) {
|
||||
console.error("error:", e);
|
||||
console.error(e.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}))();
|
||||
|
||||
module.exports = run;
|
@ -5,17 +5,20 @@ const await = require('asyncawait/await');
|
||||
const OrbitClient = require('../src/OrbitClient');
|
||||
const Timer = require('./Timer');
|
||||
|
||||
// Redis
|
||||
// orbit-server
|
||||
const host = 'localhost';
|
||||
const port = 6379;
|
||||
// const host = '178.62.241.75';
|
||||
const port = 3333;
|
||||
|
||||
const username = 'LambOfGod';
|
||||
const username = process.argv[3] ? process.argv[3] : 'LambOfGod';
|
||||
const password = '';
|
||||
|
||||
const prefix = process.argv[4] ? process.argv[4] : 'LambOfGod';
|
||||
|
||||
let run = (async(() => {
|
||||
try {
|
||||
var orbit = OrbitClient.connect(host, port, username, password);
|
||||
const c1 = 'c1';
|
||||
const c1 = process.argv[2] ? process.argv[2] : 'c1';;
|
||||
const channel = orbit.channel(c1);
|
||||
|
||||
let count = 1;
|
||||
@ -26,23 +29,25 @@ let run = (async(() => {
|
||||
if(!running) {
|
||||
running = true;
|
||||
|
||||
// let timer = new Timer(true);
|
||||
channel.add("Hello " + count);
|
||||
// console.log(`Query #${count} took ${timer.stop(true)} ms\n`);
|
||||
let timer = new Timer(true);
|
||||
channel.add(prefix + count);
|
||||
console.log(`Query #${count} took ${timer.stop(true)} ms\n`);
|
||||
|
||||
const c = channel.iterator({ limit: -1 }).collect().length;
|
||||
let items = channel.iterator({ limit: 5 }).collect();
|
||||
let timer2 = new Timer(true);
|
||||
// const c = channel.iterator({ limit: -1 }).collect().length;
|
||||
let items = channel.iterator({ limit: -1 }).collect();
|
||||
console.log("---------------------------------------------------")
|
||||
console.log("Key | Value")
|
||||
console.log("---------------------------------------------------")
|
||||
console.log(items.map((e) => `${e.payload.key} | ${e.payload.value}`).join("\n"));
|
||||
console.log("---------------------------------------------------")
|
||||
console.log(`Found ${items.length} items from ${c}\n`);
|
||||
// console.log(`Found ${items.length} items from ${c}\n`);
|
||||
console.log(`Query 2 #${count} took ${timer2.stop(true)} ms\n`);
|
||||
|
||||
running = false;
|
||||
count ++;
|
||||
}
|
||||
}), 500);
|
||||
}), 2000);
|
||||
|
||||
} catch(e) {
|
||||
console.error("error:", e);
|
||||
|
@ -5,9 +5,10 @@ var await = require('asyncawait/await');
|
||||
var OrbitClient = require('../src/OrbitClient');
|
||||
var Timer = require('./Timer');
|
||||
|
||||
// Redis
|
||||
var host = 'localhost';
|
||||
var port = 6379;
|
||||
// orbit-server
|
||||
// const host = 'localhost';
|
||||
const host = '178.62.241.75';
|
||||
const port = 3333;
|
||||
|
||||
var username = process.argv[2] ? process.argv[2] : 'DankoJones';
|
||||
var password = '';
|
||||
|
@ -30,6 +30,13 @@ class DataStore {
|
||||
return this._fetchRecursive(options);
|
||||
}
|
||||
|
||||
_fetchOne(item) {
|
||||
return new Promise(async((resolve, reject) => {
|
||||
await(item.getPayload());
|
||||
resolve({ hash: item.data, payload: item.Payload });
|
||||
}));
|
||||
}
|
||||
|
||||
_fetchRecursive(options, currentAmount, deleted, res) {
|
||||
const opts = {
|
||||
amount: options && options.amount ? options.amount : DefaultAmount,
|
||||
@ -47,17 +54,20 @@ class DataStore {
|
||||
let handledItems = deleted ? deleted : [];
|
||||
let item;
|
||||
|
||||
// Fetch the item from ipfs
|
||||
const node = this.list.items[this.list.items.length - currentAmount - 1];
|
||||
if(node)
|
||||
item = await(this._fetchOne(node));
|
||||
if(node) item = await(this._fetchOne(node));
|
||||
|
||||
const canAdd = (firstHash, key, foundItemsCount) => {
|
||||
return (!opts.key || (opts.key && opts.key === item.payload.key)) &&
|
||||
(!opts.first || (opts.first && (opts.first === item.payload.key && foundItemsCount === 0))
|
||||
|| (opts.first && (opts.first !== item.payload.key && foundItemsCount > 0)))
|
||||
};
|
||||
|
||||
if(item && item.payload) {
|
||||
const wasHandled = _.includes(handledItems, item.payload.key);
|
||||
const wasHandled = _.includes(handledItems, item.payload.key); // Last Write Wins, if it was handled, ignore the rest
|
||||
if((item.payload.op === HashCacheOps.Put || item.payload.op === HashCacheOps.Add) && !wasHandled) {
|
||||
if((!opts.key || (opts.key && opts.key === item.payload.key)) &&
|
||||
(!opts.first || (opts.first && (opts.first === item.payload.key && result.length === 0))
|
||||
|| (opts.first && (opts.first !== item.payload.key && result.length > 0))))
|
||||
{
|
||||
if(canAdd(opts.first, item.payload.key, result.length)) {
|
||||
result.push(item);
|
||||
handledItems.push(item.payload.key);
|
||||
}
|
||||
@ -85,15 +95,6 @@ class DataStore {
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
_fetchOne(item) {
|
||||
return new Promise((resolve, reject) => {
|
||||
await(item.getPayload());
|
||||
const f = item.compact();
|
||||
const res = { hash: f.data, payload: f.Payload };
|
||||
resolve(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DataStore;
|
||||
|
@ -15,6 +15,8 @@ const PubSub = require('./PubSub');
|
||||
const List = require('./list/OrbitList');
|
||||
const DataStore = require('./DataStore');
|
||||
|
||||
var Timer = require('../examples/Timer');
|
||||
|
||||
const pubkey = Keystore.getKeys().publicKey;
|
||||
const privkey = Keystore.getKeys().privateKey;
|
||||
|
||||
@ -27,11 +29,22 @@ class OrbitClient {
|
||||
channel(hash, password) {
|
||||
if(password === undefined) password = '';
|
||||
|
||||
this._pubsub.subscribe(hash, password, async((hash, message) => {
|
||||
const processMsg = async((hash, message) => {
|
||||
const other = await(List.fromIpfsHash(this._ipfs, message));
|
||||
if(other.id !== this.user.username)
|
||||
if(other.id !== this.user.username) {
|
||||
this._store.join(other);
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const onLatest = async((hash, message) => {
|
||||
console.log("--> Received latest list:", message)
|
||||
if(message) {
|
||||
const other = await(List.fromIpfsHash(this._ipfs, message));
|
||||
this._store.join(other);
|
||||
}
|
||||
});
|
||||
|
||||
this._pubsub.subscribe(hash, password, processMsg, onLatest);
|
||||
|
||||
return {
|
||||
iterator: (options) => this._iterator(hash, password, options),
|
||||
@ -106,9 +119,12 @@ class OrbitClient {
|
||||
}
|
||||
|
||||
_publish(data) {
|
||||
let post = new Post(data);
|
||||
// post.encrypt(privkey, pubkey);
|
||||
return await (ipfsAPI.putObject(this._ipfs, JSON.stringify(post)));
|
||||
return new Promise((resolve, reject) => {
|
||||
let post = new Post(data);
|
||||
// post.encrypt(privkey, pubkey);
|
||||
const res = await (ipfsAPI.putObject(this._ipfs, JSON.stringify(post)));
|
||||
resolve(res);
|
||||
})
|
||||
}
|
||||
|
||||
_createMessage(channel, password, operation, key, value) {
|
||||
@ -121,13 +137,13 @@ class OrbitClient {
|
||||
|
||||
/* DB Operations */
|
||||
_add(channel, password, data) {
|
||||
const post = this._publish(data);
|
||||
const post = await(this._publish(data));
|
||||
const key = post.Hash;
|
||||
return await(this._createOperation(channel, password, HashCacheOps.Add, key, post.Hash, data));
|
||||
}
|
||||
|
||||
_put(channel, password, key, data) {
|
||||
const post = this._publish(data);
|
||||
const post = await(this._publish(data));
|
||||
return await(this._createOperation(channel, password, HashCacheOps.Put, key, post.Hash));
|
||||
}
|
||||
|
||||
@ -136,12 +152,18 @@ class OrbitClient {
|
||||
}
|
||||
|
||||
_createOperation(channel, password, operation, key, value, data) {
|
||||
const hash = this._createMessage(channel, password, operation, key, value);
|
||||
const res = await(this._store.add(hash));
|
||||
const listHash = await(this._store.list.getIpfsHash());
|
||||
await(this._pubsub.publish(channel, listHash));
|
||||
// return res;
|
||||
var create = async(() => {
|
||||
return new Promise(async((resolve, reject) => {
|
||||
const hash = this._createMessage(channel, password, operation, key, value);
|
||||
const res = await(this._store.add(hash));
|
||||
const listHash = await(this._store.list.getIpfsHash());
|
||||
await(this._pubsub.publish(channel, listHash));
|
||||
resolve();
|
||||
}));
|
||||
})
|
||||
await(create());
|
||||
return key;
|
||||
// return res;
|
||||
}
|
||||
|
||||
_deleteChannel(channel, password) {
|
||||
|
@ -8,13 +8,25 @@ class Pubsub {
|
||||
this.ipfs = ipfs;
|
||||
this._subscriptions = {};
|
||||
this._socket = io(`http://${host}:${port}`);
|
||||
this._socket.on('connect', (socket) => console.log('Connected to', `http://${host}:${port}`));
|
||||
this._socket.on('connect', (socket) => console.log(`Connected to http://${host}:${port}`));
|
||||
this._socket.on('disconnect', (socket) => console.log(`Disconnected from http://${host}:${port}`));
|
||||
this._socket.on('event', (e) => console.log('Event:', e));
|
||||
this._socket.on('error', (e) => console.log('error:', e));
|
||||
this._socket.on('message', this._handleMessage.bind(this));
|
||||
this._socket.on('latest', (hash, message) => {
|
||||
console.log(">", hash, message);
|
||||
if(this._subscriptions[hash]) {
|
||||
this._subscriptions[hash].head = message;
|
||||
|
||||
if(this._subscriptions[hash].onLatest)
|
||||
this._subscriptions[hash].onLatest(hash, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
subscribe(hash, password, callback) {
|
||||
subscribe(hash, password, callback, onLatest) {
|
||||
if(!this._subscriptions[hash]) {
|
||||
this._subscriptions[hash] = { head: null, callback: callback };
|
||||
this._subscriptions[hash] = { head: null, callback: callback, onLatest: onLatest };
|
||||
this._socket.emit('subscribe', { channel: hash });
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,18 @@ const _ = require('lodash');
|
||||
const Node = require('./Node');
|
||||
|
||||
class List {
|
||||
constructor(id) {
|
||||
constructor(id, seq, ver, items) {
|
||||
this.id = id;
|
||||
this.seq = 0;
|
||||
this.ver = 0;
|
||||
this._items = [];
|
||||
this.seq = seq ? seq : 0;
|
||||
this.ver = ver ? ver : 0;
|
||||
this._items = items ? items : [];
|
||||
this._currentBatch = [];
|
||||
}
|
||||
|
||||
get compactId() {
|
||||
return "" + this.id + "." + this.seq + "." + this.ver;
|
||||
}
|
||||
|
||||
get items() {
|
||||
return this._items.concat(this._currentBatch);
|
||||
}
|
||||
@ -41,7 +45,7 @@ class List {
|
||||
}
|
||||
|
||||
_isReferencedInChain(all, item) {
|
||||
let isReferenced = _.findLast(all, (e) => this._references(e, item)) !== undefined;
|
||||
const isReferenced = _.findLast(all, (e) => this._references(e, item)) !== undefined;
|
||||
return isReferenced;
|
||||
}
|
||||
|
||||
@ -51,7 +55,7 @@ class List {
|
||||
|
||||
_references(a, b) {
|
||||
for(let i = 0; i < a.next.length; i ++) {
|
||||
if(b.compactId === a.next[i])
|
||||
if(b.compactId === a.next[i].compactId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -70,14 +74,9 @@ class List {
|
||||
id: this.id,
|
||||
seq: this.seq,
|
||||
ver: this.ver,
|
||||
items: this._currentBatch.map((f) => f.compact())
|
||||
items: this._currentBatch.map((f) => f.toJson())
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
const items = this.items.map((f) => JSON.stringify(f.compact())).join("\n");
|
||||
return `id: ${this.id}, seq: ${this.seq}, ver: ${this.ver}, items:\n${items}`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = List;
|
||||
|
@ -16,6 +16,10 @@ class Node {
|
||||
compact() {
|
||||
return { id: this.id, seq: this.seq, ver: this.ver, data: this.data, next: this.next }
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return { id: this.id, seq: this.seq, ver: this.ver, data: this.data, next: this.next }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Node;
|
||||
|
@ -7,25 +7,54 @@ const ipfsAPI = require('orbit-common/lib/ipfs-api-promised');
|
||||
const List = require('./List');
|
||||
const Node = require('./OrbitNode');
|
||||
|
||||
const MaxBatchSize = 200;
|
||||
const MaxBatchSize = 10; // How many items per sequence. Saves a snapshot to ipfs in batches of this many items.
|
||||
const MaxHistory = 1000; // How many items to fetch in the chain per join
|
||||
|
||||
class OrbitList extends List {
|
||||
constructor(id, ipfs) {
|
||||
super(id);
|
||||
this._ipfs = ipfs;
|
||||
this.hash = null;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
add(data) {
|
||||
const heads = super._findHeads(this.items);
|
||||
const node = new Node(this._ipfs, this.id, this.seq, this.ver, data, heads);
|
||||
this._currentBatch.push(node);
|
||||
this.ver ++;
|
||||
|
||||
if(this.ver >= MaxBatchSize)
|
||||
this._commit();
|
||||
|
||||
return node.ipfsHash;
|
||||
const heads = super._findHeads(this.items);
|
||||
const node = new Node(this._ipfs, this.id, this.seq, this.ver, data, heads);
|
||||
node._commit();
|
||||
this._currentBatch.push(node);
|
||||
this.ver ++;
|
||||
|
||||
}
|
||||
|
||||
join(other) {
|
||||
super.join(other);
|
||||
|
||||
// WIP: fetch missing nodes
|
||||
let depth = 0;
|
||||
|
||||
const isReferenced = (all, item) => _.findLast(all, (f) => f === item) !== undefined;
|
||||
const fetchRecursive = (hash) => {
|
||||
hash = hash instanceof Node === true ? hash.hash : hash;
|
||||
let allHashes = this._items.map((a) => a.hash);
|
||||
depth ++;
|
||||
if(!isReferenced(allHashes, hash)) {
|
||||
const item = Node.fromIpfsHash(this._ipfs, hash);
|
||||
if(item.next && depth < MaxHistory) {
|
||||
item.heads.forEach(fetchRecursive);
|
||||
const indices = item.heads.map((k) => _.findIndex(this._items, (b) => b.hash === k));
|
||||
const idx = indices.length > 0 ? Math.max(_.max(indices) + 1, 0) : 0;
|
||||
this._items.splice(idx, 0, item)
|
||||
// console.log("added", item.compactId, "at", idx, item.data, depth);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
other.items.forEach((e) => e.heads.forEach(fetchRecursive));
|
||||
// console.log("--> Fetched", MaxHistory, "items from the history\n");
|
||||
}
|
||||
|
||||
clear() {
|
||||
@ -34,23 +63,38 @@ class OrbitList extends List {
|
||||
}
|
||||
|
||||
getIpfsHash() {
|
||||
const list = await(ipfsAPI.putObject(this._ipfs, JSON.stringify(this.toJson())));
|
||||
return list.Hash;
|
||||
return new Promise(async((resolve, reject) => {
|
||||
var data = await(this.toJson())
|
||||
const list = await(ipfsAPI.putObject(this._ipfs, JSON.stringify(data)));
|
||||
resolve(list.Hash);
|
||||
}));
|
||||
}
|
||||
|
||||
static fromIpfsHash(ipfs, hash) {
|
||||
const l = await(ipfsAPI.getObject(ipfs, hash));
|
||||
const list = OrbitList.fromJson(ipfs, JSON.parse(l.Data));
|
||||
return list;
|
||||
return new Promise(async((resolve, reject) => {
|
||||
const l = await(ipfsAPI.getObject(ipfs, hash));
|
||||
const list = OrbitList.fromJson(ipfs, JSON.parse(l.Data));
|
||||
resolve(list);
|
||||
}));
|
||||
}
|
||||
|
||||
toJson() {
|
||||
let items = {};
|
||||
this._currentBatch.forEach((f) => Object.defineProperty(items, f.compactId.toString(), { value: f.ipfsHash, enumerable: true }));
|
||||
return {
|
||||
id: this.id,
|
||||
seq: this.seq,
|
||||
ver: this.ver,
|
||||
items: items
|
||||
}
|
||||
}
|
||||
|
||||
static fromJson(ipfs, json) {
|
||||
let list = new List(json.id);
|
||||
list.seq = json.seq;
|
||||
list.ver = json.ver;
|
||||
// list._items = _.uniqWith(json.items.map((f) => new Node(ipfs, f.id, f.seq, f.ver, f.data, f.next)), _.isEqual);
|
||||
list._items = json.items.map((f) => new Node(ipfs, f.id, f.seq, f.ver, f.data, f.next));
|
||||
return list;
|
||||
const items = Object.keys(json.items).map((f) => {
|
||||
const hash = json.items[f];
|
||||
return Node.fromIpfsHash(ipfs, hash);
|
||||
});
|
||||
return new List(json.id, json.seq, json.ver, items);
|
||||
}
|
||||
|
||||
static get batchSize() {
|
||||
|
@ -6,32 +6,49 @@ const ipfsAPI = require('orbit-common/lib/ipfs-api-promised');
|
||||
const Node = require('./Node');
|
||||
|
||||
class OrbitNode extends Node {
|
||||
constructor(ipfs, id, seq, ver, data, next) {
|
||||
super(id, seq, ver, data, next);
|
||||
constructor(ipfs, id, seq, ver, data, next, hash) {
|
||||
super(id, seq, ver, data);
|
||||
this.hash = null;
|
||||
this._ipfs = ipfs;
|
||||
this.next = next;
|
||||
this.hash = hash ? hash : this.ipfsHash;
|
||||
}
|
||||
|
||||
get compactId() {
|
||||
if(!this.hash) {
|
||||
const t = this.compact();
|
||||
const r = await(ipfsAPI.putObject(this._ipfs, JSON.stringify(t)));
|
||||
this.hash = r.Hash;
|
||||
}
|
||||
return "" + this.id + "." + this.seq + "." + this.ver + "." + this.hash;
|
||||
return "" + this.id + "." + this.seq + "." + this.ver;
|
||||
}
|
||||
|
||||
get ipfsHash() {
|
||||
this._commit();
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
get heads() {
|
||||
return Object.keys(this.next).map((e) => this.next[e]);
|
||||
}
|
||||
|
||||
compact() {
|
||||
let res = { id: this.id, seq: this.seq, ver: this.ver, data: this.data }
|
||||
let items = {};
|
||||
|
||||
if(this.next)
|
||||
this.next.forEach((f) => Object.defineProperty(items, f.compactId.toString(), { value: f.ipfsHash, enumerable: true }));
|
||||
|
||||
Object.assign(res, { next: items });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_commit() {
|
||||
if(!this.hash) {
|
||||
const t = this.compact();
|
||||
const r = await(ipfsAPI.putObject(this._ipfs, JSON.stringify(t)));
|
||||
this.hash = r.Hash;
|
||||
}
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
getPayload() {
|
||||
if(!this.Payload) {
|
||||
if(!this.Payload) {
|
||||
const payload = await(ipfsAPI.getObject(this._ipfs, this.data));
|
||||
this.Payload = JSON.parse(payload.Data);
|
||||
if(this.Payload.value) {
|
||||
@ -39,10 +56,20 @@ class OrbitNode extends Node {
|
||||
this.Payload.value = JSON.parse(value.Data)["content"];
|
||||
}
|
||||
}
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
compact() {
|
||||
return { id: this.id, seq: this.seq, ver: this.ver, data: this.data, next: this.next, Payload: this.Payload }
|
||||
static fromIpfsHash(ipfs, hash) {
|
||||
const create = async(() => {
|
||||
return new Promise(async((resolve, reject) => {
|
||||
const o = await(ipfsAPI.getObject(ipfs, hash));
|
||||
const f = JSON.parse(o.Data)
|
||||
const node = new OrbitNode(ipfs, f.id, f.seq, f.ver, f.data, f.next, hash)
|
||||
resolve(node);
|
||||
}));
|
||||
});
|
||||
const node = await(create());
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,19 +60,6 @@ describe('List', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
it('presents the list as a string', (done) => {
|
||||
const list = new List('A');
|
||||
list.add("hello1")
|
||||
list.add("hello2")
|
||||
list.add("hello3")
|
||||
const str = list.toString();
|
||||
const expected = `id: A, seq: 0, ver: 3, items:\n{"id":"A","seq":0,"ver":0,"data":"hello1","next":[]}\n{"id":"A","seq":0,"ver":1,"data":"hello2","next":["A.0.0"]}\n{"id":"A","seq":0,"ver":2,"data":"hello3","next":["A.0.1"]}`;
|
||||
assert.equal(str, expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('items', () => {
|
||||
it('returns items', (done) => {
|
||||
const list = new List('A');
|
||||
@ -208,8 +195,9 @@ describe('List', () => {
|
||||
list1.add("helloA3")
|
||||
|
||||
assert.equal(list1._currentBatch.length, 2);
|
||||
assert.equal(list1._currentBatch[1].next.length, 1);
|
||||
assert.equal(list1._currentBatch[1].next.length, 2);
|
||||
assert.equal(list1._currentBatch[1].next[0], 'A.1.0');
|
||||
assert.equal(list1._currentBatch[1].next[1], 'B.0.1');
|
||||
done();
|
||||
});
|
||||
|
||||
@ -232,8 +220,9 @@ describe('List', () => {
|
||||
const lastItem = list1.items[list1.items.length - 1];
|
||||
|
||||
assert.equal(list1.items.length, 7);
|
||||
assert.equal(lastItem.next.length, 1);
|
||||
assert.equal(lastItem.next.length, 2);
|
||||
assert.equal(lastItem.next[0], 'A.2.0');
|
||||
assert.equal(lastItem.next[1], 'B.0.1');
|
||||
done();
|
||||
});
|
||||
|
||||
@ -266,10 +255,12 @@ describe('List', () => {
|
||||
|
||||
const lastItem = list1.items[list1.items.length - 1];
|
||||
|
||||
assert.equal(list1.items.length, 11);
|
||||
assert.equal(lastItem.next.length, 2);
|
||||
assert.equal(lastItem.next[0], 'A.4.0');
|
||||
assert.equal(lastItem.next[1], 'D.0.2');
|
||||
assert.equal(lastItem.next[1], 'B.0.1');
|
||||
assert.equal(lastItem.next[2], 'C.0.0');
|
||||
assert.equal(lastItem.next[3], 'D.0.2');
|
||||
assert.equal(list1.items.length, 11);
|
||||
assert.equal(lastItem.next.length, 4);
|
||||
done();
|
||||
});
|
||||
|
||||
|
@ -70,7 +70,6 @@ describe('Orbit Client', () => {
|
||||
it('adds five items', async((done) => {
|
||||
for(let i = 0; i < 5; i ++) {
|
||||
let hash = db.add('hello');
|
||||
// console.log(hash)
|
||||
assert.notEqual(hash, null);
|
||||
assert.equal(hash.startsWith('Qm'), true);
|
||||
assert.equal(hash.length, 46);
|
||||
|
@ -47,11 +47,15 @@ describe('OrbitList', async(function() {
|
||||
const text = 'testing 1 2 3 4';
|
||||
list.add(text)
|
||||
const hash = await(list.getIpfsHash());
|
||||
assert.equal(hash, 'QmbV4JSx25tZ7P3HVpcUXuqju4rNcPsoLPpiG1pcE1AdVw');
|
||||
|
||||
const l = await(ipfsAPI.getObject(ipfs, hash));
|
||||
const list2 = List.fromJson(ipfs, JSON.parse(l.Data));
|
||||
assert.equal(list2.items[0].data, text);
|
||||
assert.equal(list2.items[0].id, 'A');
|
||||
assert.equal(list2.items[0].seq, 0);
|
||||
assert.equal(list2.items[0].ver, 0);
|
||||
assert.equal(list2.items[0].hash, 'QmWqjmn62GQjR7RTsUKXMtxDYVoY7GQVCfUECGmLET3BQ2');
|
||||
assert.equal(Object.keys(list2.items[0].next).length, 0);
|
||||
|
||||
done();
|
||||
}));
|
||||
@ -65,11 +69,11 @@ describe('OrbitList', async(function() {
|
||||
list.add(text1)
|
||||
|
||||
hash = await(list.getIpfsHash());
|
||||
assert.equal(hash, 'QmcBjB93PsJGz2LrVy5e1Z8mtwH99B8yynsa5f4q3GanEe');
|
||||
// assert.equal(hash, 'QmcBjB93PsJGz2LrVy5e1Z8mtwH99B8yynsa5f4q3GanEe');
|
||||
|
||||
list.add(text2)
|
||||
hash = await(list.getIpfsHash());
|
||||
assert.equal(hash, 'Qmf358H1wjuX3Bbaag4SSEiujoruowVUNR5pLCNQs8vivP');
|
||||
// assert.equal(hash, 'Qmf358H1wjuX3Bbaag4SSEiujoruowVUNR5pLCNQs8vivP');
|
||||
|
||||
const l = await(ipfsAPI.getObject(ipfs, hash));
|
||||
const list2 = List.fromJson(ipfs, JSON.parse(l.Data));
|
||||
@ -84,7 +88,7 @@ describe('OrbitList', async(function() {
|
||||
it('returns the list as ipfs hash', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
const hash = await(list.getIpfsHash());
|
||||
assert.equal(hash, 'QmVkddks6YBH88TqJf7nFHdyb9PjebPmJAxaRvWdu8ueoE');
|
||||
assert.equal(hash.startsWith('Qm'), true);
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -97,25 +101,6 @@ describe('OrbitList', async(function() {
|
||||
}));
|
||||
}));
|
||||
|
||||
describe('fromJson', () => {
|
||||
it('creates a list from parsed json', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
list.add("hello1")
|
||||
list.add("hello2")
|
||||
list.add("hello3")
|
||||
const str = JSON.stringify(list.toJson(), null, 2)
|
||||
const res = List.fromJson(ipfs, JSON.parse(str));
|
||||
assert.equal(res.id, 'A');
|
||||
assert.equal(res.seq, 0);
|
||||
assert.equal(res.ver, 3);
|
||||
assert.equal(res.items.length, 3);
|
||||
assert.equal(res.items[0].compactId, 'A.0.0.QmZfdeMV77si491NPX83Q8eRYE9WNzVorHrfWJPrJ51brt');
|
||||
assert.equal(res.items[1].compactId, 'A.0.1.QmbbtEWe4qHLSjtW2HkPuszFW3zfBTXBdPrkXMdbePxqfK');
|
||||
assert.equal(res.items[2].compactId, 'A.0.2.QmT6wQwBZsH6b3jQVxmM5L7kqV39nr3F99yd5tN6nviQPe');
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('fromIpfsHash', () => {
|
||||
it('creates a list from ipfs hash', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
@ -123,54 +108,71 @@ describe('OrbitList', async(function() {
|
||||
list.add("hello2")
|
||||
list.add("hello3")
|
||||
const hash = await(list.getIpfsHash());
|
||||
assert.equal(hash, 'QmThvyS6FUsHvT7oC2pGNMTAdhjUncNsVMbXAkUB72J8n1');
|
||||
const res = await(List.fromIpfsHash(ipfs, hash));
|
||||
|
||||
assert.equal(res.id, 'A');
|
||||
assert.equal(res.seq, 0);
|
||||
assert.equal(res.ver, 3);
|
||||
assert.equal(res.items.length, 3);
|
||||
assert.equal(res.items[0].compactId, 'A.0.0.QmZfdeMV77si491NPX83Q8eRYE9WNzVorHrfWJPrJ51brt');
|
||||
assert.equal(res.items[1].compactId, 'A.0.1.QmbbtEWe4qHLSjtW2HkPuszFW3zfBTXBdPrkXMdbePxqfK');
|
||||
assert.equal(res.items[2].compactId, 'A.0.2.QmT6wQwBZsH6b3jQVxmM5L7kqV39nr3F99yd5tN6nviQPe');
|
||||
assert.equal(res.items[0].compactId, 'A.0.0');
|
||||
assert.equal(res.items[0].hash, 'QmQQyTLqcB7ySH5zVCbks1UWQEgrv3m5ygSRL88BHghg95');
|
||||
assert.equal(res.items[1].compactId, 'A.0.1');
|
||||
assert.equal(res.items[1].hash, 'Qmbwx1b2CYxMmpQmJFKRsqDdGjD5CwfB2QRGP63jypyYFC');
|
||||
assert.equal(res.items[2].compactId, 'A.0.2');
|
||||
assert.equal(res.items[2].hash, 'QmfLnHHPbMwwAzUNs8inVGzM8tXxb2eLeeQb8Zgc7p3nfY');
|
||||
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('toJson', async(() => {
|
||||
it('presents the list as json', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
|
||||
describe('serialize', async(() => {
|
||||
|
||||
let list;
|
||||
const expected = {
|
||||
id: "A",
|
||||
seq: 0,
|
||||
ver: 3,
|
||||
items: {
|
||||
"A.0.0": "QmQQyTLqcB7ySH5zVCbks1UWQEgrv3m5ygSRL88BHghg95",
|
||||
"A.0.1": "Qmbwx1b2CYxMmpQmJFKRsqDdGjD5CwfB2QRGP63jypyYFC",
|
||||
"A.0.2": "QmfLnHHPbMwwAzUNs8inVGzM8tXxb2eLeeQb8Zgc7p3nfY"
|
||||
}
|
||||
};
|
||||
|
||||
before(async((done) => {
|
||||
list = new List('A', ipfs);
|
||||
list.add("hello1")
|
||||
list.add("hello2")
|
||||
list.add("hello3")
|
||||
const json = list.toJson();
|
||||
const expected = {
|
||||
id: 'A',
|
||||
seq: 0,
|
||||
ver: 3,
|
||||
items: [
|
||||
{ id: 'A', seq: 0, ver: 0, data: 'hello1', next: [], Payload: undefined },
|
||||
{ id: 'A', seq: 0, ver: 1, data: 'hello2', next: ['A.0.0.QmZfdeMV77si491NPX83Q8eRYE9WNzVorHrfWJPrJ51brt'], Payload: undefined },
|
||||
{ id: 'A', seq: 0, ver: 2, data: 'hello3', next: ['A.0.1.QmbbtEWe4qHLSjtW2HkPuszFW3zfBTXBdPrkXMdbePxqfK'], Payload: undefined }
|
||||
]
|
||||
};
|
||||
// console.log(JSON.stringify(json, null, 1))
|
||||
assert.equal(_.isEqual(json, expected), true);
|
||||
done();
|
||||
}));
|
||||
|
||||
describe('toJson', async(() => {
|
||||
it('presents the list as json', async((done) => {
|
||||
const json = list.toJson();
|
||||
assert.equal(JSON.stringify(json), JSON.stringify(expected));
|
||||
done();
|
||||
}));
|
||||
}));
|
||||
|
||||
describe('fromJson', () => {
|
||||
it('creates a list from parsed json', async((done) => {
|
||||
const str = JSON.stringify(list.toJson(), null, 2)
|
||||
const res = List.fromJson(ipfs, JSON.parse(str));
|
||||
|
||||
assert.equal(res.id, 'A');
|
||||
assert.equal(res.seq, 0);
|
||||
assert.equal(res.ver, 3);
|
||||
assert.equal(res.items.length, 3);
|
||||
assert.equal(res.items[0].hash, 'QmQQyTLqcB7ySH5zVCbks1UWQEgrv3m5ygSRL88BHghg95');
|
||||
assert.equal(res.items[1].hash, 'Qmbwx1b2CYxMmpQmJFKRsqDdGjD5CwfB2QRGP63jypyYFC');
|
||||
assert.equal(res.items[2].hash, 'QmfLnHHPbMwwAzUNs8inVGzM8tXxb2eLeeQb8Zgc7p3nfY');
|
||||
done();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
|
||||
describe('toString', () => {
|
||||
it('presents the list as a string', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
list.add("hello1")
|
||||
list.add("hello2")
|
||||
list.add("hello3")
|
||||
const str = list.toString();
|
||||
const expected = `id: A, seq: 0, ver: 3, items:\n{"id":"A","seq":0,"ver":0,"data":"hello1","next":[]}\n{"id":"A","seq":0,"ver":1,"data":"hello2","next":["A.0.0.QmZfdeMV77si491NPX83Q8eRYE9WNzVorHrfWJPrJ51brt"]}\n{"id":"A","seq":0,"ver":2,"data":"hello3","next":["A.0.1.QmbbtEWe4qHLSjtW2HkPuszFW3zfBTXBdPrkXMdbePxqfK"]}`;
|
||||
assert.equal(str, expected);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('items', () => {
|
||||
it('returns items', async((done) => {
|
||||
@ -209,25 +211,19 @@ describe('OrbitList', async(function() {
|
||||
|
||||
it('adds 100 items to a list', async((done) => {
|
||||
const list = new List('A', ipfs);
|
||||
const amount = 100;
|
||||
|
||||
for(let i = 1; i < 101; i ++) {
|
||||
for(let i = 1; i <= amount; i ++) {
|
||||
list.add("hello" + i);
|
||||
}
|
||||
|
||||
assert.equal(list.id, 'A');
|
||||
assert.equal(list.seq, 0);
|
||||
assert.equal(list.ver, 100);
|
||||
assert.equal(list.items.length, 100);
|
||||
assert.equal(list._currentBatch.length, 100);
|
||||
assert.equal(list._items.length, 0);
|
||||
assert.equal(list.items.length, amount);
|
||||
|
||||
const item = list.items[list.items.length - 1];
|
||||
assert.equal(item, list._currentBatch[list._currentBatch.length - 1]);
|
||||
assert.equal(item.id, 'A');
|
||||
assert.equal(item.seq, 0);
|
||||
assert.equal(item.ver, 99);
|
||||
assert.equal(item.data, 'hello100');
|
||||
assert.equal(item.next, 'A.0.98.QmPZ1Qmf52ko62xh9RDYcVGNMWx8ZCtfFNyrvqyE1UmhG1');
|
||||
assert.equal(item.data, 'hello' + amount);
|
||||
assert.notEqual(item.next.length, 0);
|
||||
|
||||
done();
|
||||
}));
|
||||
@ -240,18 +236,18 @@ describe('OrbitList', async(function() {
|
||||
}
|
||||
|
||||
assert.equal(list.id, 'A');
|
||||
assert.equal(list.seq, 1);
|
||||
assert.equal(list.ver, 0);
|
||||
assert.equal(list.seq, 0);
|
||||
assert.equal(list.ver, List.batchSize);
|
||||
assert.equal(list.items.length, List.batchSize);
|
||||
assert.equal(list._currentBatch.length, 0);
|
||||
assert.equal(list._items.length, List.batchSize);
|
||||
assert.equal(list._currentBatch.length, List.batchSize);
|
||||
assert.equal(list._items.length, 0);
|
||||
|
||||
const item = list.items[list.items.length - 1];
|
||||
assert.equal(item.id, 'A');
|
||||
assert.equal(item.seq, 0);
|
||||
assert.equal(item.ver, List.batchSize - 1);
|
||||
assert.equal(item.data, 'hello' + List.batchSize);
|
||||
assert.equal(item.next, 'A.0.198.QmRKrcfkejCvxTxApZACjHpxzAKKGnCtFi2rD31CT7RkBS');
|
||||
assert.notEqual(item.next.length, 0);
|
||||
|
||||
done();
|
||||
}));
|
||||
@ -298,8 +294,13 @@ describe('OrbitList', async(function() {
|
||||
list1.add("helloA3")
|
||||
|
||||
assert.equal(list1._currentBatch.length, 3);
|
||||
assert.equal(list1._currentBatch[0].next.length, 0);
|
||||
assert.equal(list1._currentBatch[1].next.length, 1);
|
||||
assert.equal(list1._currentBatch[1].next[0].compactId, 'A.0.0');
|
||||
assert.equal(list1._currentBatch[1].next[0].hash, 'QmYTUeiK82guFDyB9tJgHZuBpNkUqNyFBuajYrCsaxPXvW');
|
||||
assert.equal(list1._currentBatch[2].next.length, 1);
|
||||
assert.equal(list1._currentBatch[2].next[0], 'A.0.1.QmW3cnX41CNSAEkZE23w4qMRcsAY8MEUtsCT4wZmRZfQ76');
|
||||
assert.equal(list1._currentBatch[2].next[0].compactId, 'A.0.1');
|
||||
assert.equal(list1._currentBatch[2].next[0].hash, 'QmUycQmNU8apkbPqsWPK3VxMHJeHt86UQrzfSFDNRGbvsd');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -314,8 +315,10 @@ describe('OrbitList', async(function() {
|
||||
|
||||
assert.equal(list1._currentBatch.length, 1);
|
||||
assert.equal(list1._currentBatch[0].next.length, 2);
|
||||
assert.equal(list1._currentBatch[0].next[0], 'A.0.0.QmaHqKY1GUJTKGF6KA3QLoDaD3TS7oa6wHGTAxY6sVLKD9');
|
||||
assert.equal(list1._currentBatch[0].next[1], 'B.0.1.QmbsBfrDfqtTbaPNzuF8KNR1jbK74LwMe4UM2G6DgN6zmQ');
|
||||
assert.equal(list1._currentBatch[0].next[0].compactId, 'A.0.0');
|
||||
assert.equal(list1._currentBatch[0].next[0].hash, 'QmYTUeiK82guFDyB9tJgHZuBpNkUqNyFBuajYrCsaxPXvW');
|
||||
assert.equal(list1._currentBatch[0].next[1].compactId, 'B.0.1');
|
||||
assert.equal(list1._currentBatch[0].next[1].hash, 'QmVmkwMoz4vnvHQwvFwqaoWCrjonsPpyJ6i436Zajht5ao');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -332,7 +335,8 @@ describe('OrbitList', async(function() {
|
||||
|
||||
assert.equal(list1._currentBatch.length, 2);
|
||||
assert.equal(list1._currentBatch[1].next.length, 1);
|
||||
assert.equal(list1._currentBatch[1].next[0], 'A.1.0.QmPxBabxGovTzTphiwoiEDCRnTGYwqZ7M7jahVVctbaJdF');
|
||||
assert.equal(list1._currentBatch[1].next[0].compactId, 'A.1.0');
|
||||
assert.equal(list1._currentBatch[1].next[0].hash, 'QmYHXzXaahAL9iChAUtVsvdncKfQf7ShEfveZnL7qvGfTT');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -356,7 +360,8 @@ describe('OrbitList', async(function() {
|
||||
|
||||
assert.equal(list1.items.length, 7);
|
||||
assert.equal(lastItem.next.length, 1);
|
||||
assert.equal(lastItem.next[0], 'A.2.0.QmTpRBszPFnxtuKccYJ4YShQoeYm2caeFhmMVBfiY1u7Jc');
|
||||
assert.equal(lastItem.next[0].compactId, 'A.2.0');
|
||||
assert.equal(lastItem.next[0].hash, 'QmUCzHbqj3qKeV2JUzYB4j9B6pLmpSghD4JJa5WmLMJHVB');
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -391,8 +396,10 @@ describe('OrbitList', async(function() {
|
||||
|
||||
assert.equal(list1.items.length, 11);
|
||||
assert.equal(lastItem.next.length, 2);
|
||||
assert.equal(lastItem.next[0], 'A.4.0.Qmb7oeViDbsKTDNo7HAueFn47z3pon2fVptXNdXhcAigFz');
|
||||
assert.equal(lastItem.next[1], 'D.0.2.QmajSkuVj64RLy8YGVPqkDb4V52FjqDsvbGhJsLmkQLxsL');
|
||||
assert.equal(lastItem.next[0].compactId, 'A.4.0');
|
||||
assert.equal(lastItem.next[0].hash, 'QmW9TLhTvZMDnbyweaL3X2oZvCo2zgU9JZaYzg9gBYHTe4');
|
||||
assert.equal(lastItem.next[1].compactId, 'D.0.2');
|
||||
assert.equal(lastItem.next[1].hash, 'QmVT3DvmggXq3AdVK7JBfF4Jit3xpbgqP8dFK7TePtit4B');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -32,8 +32,8 @@ describe('OrbitNode', function() {
|
||||
assert.equal(node.seq, 0);
|
||||
assert.equal(node.ver, 0);
|
||||
assert.equal(node.data, null);
|
||||
assert.equal(node.next instanceof Array, true);
|
||||
assert.equal(node.hash, null);
|
||||
assert.equal(node.next, undefined);
|
||||
assert.equal(node.hash, 'QmNcbwc5V42kkQbnBvtWsmREbUy8PB5cG3J5DTyPWqYkho');
|
||||
assert.equal(node._ipfs, ipfs);
|
||||
done();
|
||||
}));
|
||||
@ -44,8 +44,8 @@ describe('OrbitNode', function() {
|
||||
assert.equal(node.seq, 0);
|
||||
assert.equal(node.ver, 0);
|
||||
assert.equal(node.data, 'QmTnaGEpw4totXN7rhv2jPMXKfL8s65PhhCKL5pwtJfRxn');
|
||||
assert.equal(node.next instanceof Array, true);
|
||||
assert.equal(node.hash, null);
|
||||
assert.equal(node.next, undefined);
|
||||
assert.equal(node.hash, 'QmULakc8SCkz5wz3s1TDkQgZWP1yBrhdXMpHJGJY3sV33r');
|
||||
assert.equal(node._ipfs, ipfs);
|
||||
done();
|
||||
}));
|
||||
@ -55,8 +55,8 @@ describe('OrbitNode', function() {
|
||||
it('presents the node as a string with id, sequence, version and hash', async((done) => {
|
||||
const node1 = new Node(ipfs, 'A', 0, 0, "QmTnaGEpw4totXN7rhv2jPMXKfL8s65PhhCKL5pwtJfRxn");
|
||||
const node2 = new Node(ipfs, 'B', 123, 456, "QmdcCucbM2rnHHaVhAmjMxWDY5cCDwtTtjhYuS5nBHThQq");
|
||||
assert.equal(node1.compactId, 'A.0.0.QmcfXxBTpZGmWnYVUiPTpW4Uaf9e1x34Qh9vthvuAjmhTb');
|
||||
assert.equal(node2.compactId, 'B.123.456.QmWCVngHttRQQhrmgr94GZzY5F57m3g6fDdDwK9mgHFRn2');
|
||||
assert.equal(node1.compactId, 'A.0.0');
|
||||
assert.equal(node2.compactId, 'B.123.456');
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user