Fixing lists

This commit is contained in:
haad 2016-02-25 14:06:02 +01:00
parent 1d70af0e86
commit 57c006feb2
16 changed files with 362 additions and 198 deletions

View File

@ -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 = '';

View File

@ -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("---------------------------------------------------")

View 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;

View File

@ -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);

View File

@ -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 = '';

View File

@ -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;

View File

@ -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) {

View File

@ -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 });
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -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();
});

View File

@ -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);

View File

@ -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();
}));

View File

@ -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();
}));
});