mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Initial version
This commit is contained in:
commit
f8e363eedd
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*sublime*
|
||||
node_modules/
|
||||
debug.log
|
||||
WIP/
|
65
BetterRequest.js
Normal file
65
BetterRequest.js
Normal file
@ -0,0 +1,65 @@
|
||||
'use strict'
|
||||
|
||||
var unirest = require('unirest')
|
||||
|
||||
class Request {
|
||||
constructor() {
|
||||
this.url = '';
|
||||
this.method = 'GET';
|
||||
this.headers = {};
|
||||
this.body = {};
|
||||
}
|
||||
|
||||
get(url) {
|
||||
return this._init('GET', url);
|
||||
}
|
||||
|
||||
post(url) {
|
||||
return this._init('POST', url);
|
||||
}
|
||||
|
||||
put(url) {
|
||||
return this._init('PUT', url);
|
||||
}
|
||||
|
||||
delete(url) {
|
||||
return this._init('DELETE', url);
|
||||
}
|
||||
|
||||
_init(method, url) {
|
||||
this.url = url;
|
||||
this.method = method;
|
||||
this.body = {};
|
||||
this.headers = {};
|
||||
return this;
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
this.headers[key] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
send(body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
end(callback) {
|
||||
if(!this.url.startsWith("http"))
|
||||
this.url = "http://" + this.url
|
||||
|
||||
unirest(this.method, this.url)
|
||||
.headers(this.headers)
|
||||
.type('application/json')
|
||||
.send(this.body)
|
||||
.end((res) => {
|
||||
if(res.error)
|
||||
callback(res.body ? res.body.message : "Connection refused", null);
|
||||
else
|
||||
callback(null, res.body);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = new Request();
|
85
Encryption.js
Normal file
85
Encryption.js
Normal file
@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
var Base58 = require('bs58');
|
||||
|
||||
var algorithm = 'aes-256-ecb';
|
||||
var useEncryption = true;
|
||||
|
||||
/* ENCRYPTION / DECRYPTION */
|
||||
function encrypt(text, privkey, pubkey) {
|
||||
if(!useEncryption)
|
||||
return text;
|
||||
|
||||
var encrypted;
|
||||
try {
|
||||
var cipher = crypto.createCipher(algorithm, privkey)
|
||||
encrypted = cipher.update(text, 'utf8', 'hex')
|
||||
encrypted += cipher.final('hex');
|
||||
} catch(e) {
|
||||
console.log("Error while encrypting:", e, e.stack);
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
function decrypt(text, privkey, pubkey) {
|
||||
if(!useEncryption)
|
||||
return text;
|
||||
|
||||
var decrypted;
|
||||
try {
|
||||
var cipher = crypto.createDecipher(algorithm, privkey)
|
||||
decrypted = cipher.update(text, 'hex', 'utf8')
|
||||
decrypted += cipher.final('utf8');
|
||||
} catch(e) {
|
||||
console.log("Error while decrypting:", e, e.stack);
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
/* SIGNING FUNCTIONS */
|
||||
function hashWithSHA512(data, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var hash = crypto.createHmac('sha512', salt);
|
||||
hash.update(data);
|
||||
var value = hash.digest('hex');
|
||||
return value;
|
||||
}
|
||||
|
||||
function sign(data, privkey, seq, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var sign = crypto.createSign('RSA-SHA256');
|
||||
var hash = hashWithSHA512(data, "" + salt)
|
||||
sign.update("" + seq + hash);
|
||||
var sig = sign.sign(privkey, 'hex');
|
||||
return sig;
|
||||
}
|
||||
|
||||
function verify(data, pubkey, sig, seq, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var verify = crypto.createVerify('RSA-SHA256');
|
||||
var hash = hashWithSHA512(data, salt);
|
||||
verify.update("" + seq + hash);
|
||||
var verified = verify.verify(pubkey, sig, 'hex');
|
||||
return verified;
|
||||
}
|
||||
|
||||
/* PUBLIC */
|
||||
module.exports = {
|
||||
encrypt: function(payload, privkey, pubkey) {
|
||||
return encrypt(payload, privkey, pubkey);
|
||||
},
|
||||
decrypt: function(payload, privkey, pubkey) {
|
||||
return decrypt(payload, privkey, pubkey);
|
||||
},
|
||||
sign: (data, privateKey, sequenceNumber, salt) => {
|
||||
return sign(data, privateKey, sequenceNumber, salt);
|
||||
},
|
||||
verify: (data, publicKey, signature, sequenceNumber, salt) => {
|
||||
return verify(data, publicKey, signature, sequenceNumber, salt);
|
||||
},
|
||||
hash: (data, salt) => {
|
||||
return hashWithSHA512(data, salt);
|
||||
}
|
||||
}
|
83
HashCacheClient.js
Normal file
83
HashCacheClient.js
Normal file
@ -0,0 +1,83 @@
|
||||
'use strict'
|
||||
|
||||
var request = require('./BetterRequest');
|
||||
|
||||
class HashCacheClient {
|
||||
constructor(host, credentials) {
|
||||
this.host = host
|
||||
this.credentials = credentials
|
||||
this.linkedList = this.linkedList.bind(this)
|
||||
}
|
||||
|
||||
linkedList(hash, password) {
|
||||
return {
|
||||
head: () => this._get(hash, password),
|
||||
add: (head) => this._add(hash, password, head),
|
||||
setMode: (mode) => this._setModes(hash, password, mode),
|
||||
delete: () => this._delete(hash, password)
|
||||
}
|
||||
}
|
||||
|
||||
_get(hash, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.get(this.host + '/channel/' + hash)
|
||||
.set('Authorization', this.credentials)
|
||||
.send({ password: password })
|
||||
.end((err, res) => { this._resolveRequest(err, res, resolve, reject) });
|
||||
})
|
||||
}
|
||||
|
||||
_add(hash, password, head) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.put(this.host + '/channel/' + hash + '/add')
|
||||
.set('Authorization', this.credentials)
|
||||
.send({ head: head, password: password })
|
||||
.end((err, res) => { this._resolveRequest(err, res, resolve, reject) });
|
||||
})
|
||||
}
|
||||
|
||||
_setModes(hash, password, modes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.post(this.host + '/channel/' + hash)
|
||||
.set('Authorization', this.credentials)
|
||||
.send({ modes: modes, password: password })
|
||||
.end((err, res) => { this._resolveRequest(err, res, resolve, reject) });
|
||||
})
|
||||
}
|
||||
|
||||
_delete(hash, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.delete(this.host + '/channel/' + hash)
|
||||
.set('Authorization', this.credentials)
|
||||
.end((err, res) => { this._resolveRequest(err, res, resolve, reject) });
|
||||
})
|
||||
}
|
||||
|
||||
_resolveRequest(err, res, resolve, reject) {
|
||||
if(err)
|
||||
reject(res ? res : err.toString());
|
||||
else
|
||||
resolve(res ? res : {});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
connect: (host, username, password) => {
|
||||
var credentials = `Basic ${username}=${password}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
request
|
||||
.post(host + '/register')
|
||||
.set('Authorization', credentials)
|
||||
.end((err, res) => {
|
||||
if(err)
|
||||
reject(res ? res.body.message : err.toString())
|
||||
else
|
||||
resolve(new HashCacheClient(host, credentials, res));
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
31
HashCacheItem.js
Normal file
31
HashCacheItem.js
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
var encryption = require('./Encryption');
|
||||
|
||||
class HashCacheItem {
|
||||
constructor(sequenceNumber, targetHash, metaInfo) {
|
||||
this.seq = sequenceNumber;
|
||||
this.target = targetHash;
|
||||
this.meta = metaInfo;
|
||||
}
|
||||
}
|
||||
|
||||
class EncryptedHashCacheItem extends HashCacheItem {
|
||||
constructor(sequenceNumber, targetHash, metaInfo, publicKey, privateKey, salt) {
|
||||
super(sequenceNumber, targetHash, metaInfo, publicKey, privateKey, salt);
|
||||
this.pubkey = publicKey;
|
||||
this.target = encryption.encrypt(targetHash, privateKey, publicKey);
|
||||
this.payload = this.target; // old hash-cache api compatibility
|
||||
this.meta = encryption.encrypt(JSON.stringify(metaInfo), privateKey, publicKey);
|
||||
try {
|
||||
this.sig = encryption.sign(this.target, privateKey, this.seq, salt || "");
|
||||
} catch(e) {
|
||||
console.log("Signing HashCacheItem failed:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
HashCacheItem: HashCacheItem,
|
||||
EncryptedHashCacheItem: EncryptedHashCacheItem
|
||||
};
|
11
ItemTypes.js
Normal file
11
ItemTypes.js
Normal file
@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
let ItemTypes = {
|
||||
Message: "text",
|
||||
Snippet: "snippet",
|
||||
File: "file",
|
||||
List: "list",
|
||||
Link: "link"
|
||||
};
|
||||
|
||||
module.exports = ItemTypes;
|
20
Keystore.js
Normal file
20
Keystore.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var getAppPath = () => {
|
||||
return process.type && process.env.ENV !== "dev" ? process.resourcesPath + "/app/" : process.cwd();
|
||||
}
|
||||
|
||||
var privkey = fs.readFileSync(path.resolve(getAppPath(), 'keys/private.pem')).toString('ascii');
|
||||
var pubkey = fs.readFileSync(path.resolve(getAppPath(), 'keys/public.pem')).toString('ascii');
|
||||
|
||||
module.exports = {
|
||||
getKeys: (hash) => {
|
||||
return {
|
||||
publicKey: pubkey,
|
||||
privateKey: privkey
|
||||
};
|
||||
}
|
||||
}
|
49
MessageFactory.js
Normal file
49
MessageFactory.js
Normal file
@ -0,0 +1,49 @@
|
||||
// 'use strict';
|
||||
|
||||
// var async = require('asyncawait/async');
|
||||
// var await = require('asyncawait/await');
|
||||
// var ipfsAPI = require('./ipfs-api-promised');
|
||||
// var HashCacheItem = require('./HashCacheItem').EncryptedHashCacheItem;
|
||||
// var MetaInfo = require('./MetaInfo');
|
||||
// var ItemTypes = require('./ItemTypes');
|
||||
// var Keystore = require('./Keystore');
|
||||
// var Post = require('./Post');
|
||||
// var encryption = require('./Encryption');
|
||||
|
||||
// var pubkey = Keystore.getKeys().publicKey;
|
||||
// var privkey = Keystore.getKeys().privateKey;
|
||||
|
||||
// class MessageFactory {
|
||||
|
||||
// static create(text, seq) {
|
||||
// // var seq = this.channels[hash].seq;
|
||||
// var size = -1;
|
||||
// var metaInfo = new MetaInfo(ItemTypes.Message, size, new Date().getTime());
|
||||
// var hcItem = new HashCacheItem(seq, post.Hash, metaInfo, pubkey, privkey, password);
|
||||
// var item = await (ipfsAPI.putObject(this.ipfs, JSON.stringify(hcItem)));
|
||||
// var newHead = { Hash: item.Hash };
|
||||
|
||||
// if(seq > 0) {
|
||||
// var iter = await (this._iterator(hash, password))
|
||||
// var prevHead = iter.next();
|
||||
// var headItem = await (ipfsAPI.getObject(this.ipfs, prevHead.hash));
|
||||
// seq = JSON.parse(headItem.Data)["seq"] + 1;
|
||||
// newHead = await (ipfsAPI.patchObject(this.ipfs, item.Hash, prevHead.hash))
|
||||
// }
|
||||
|
||||
// return newHead;
|
||||
// }
|
||||
|
||||
// static _publishContent(ipfs, text) {
|
||||
// var post = new Post(text);
|
||||
// var enc = MessageFactory._encryptPost(post);
|
||||
// var res = await (ipfsAPI.putObject(ipfs, JSON.stringify(enc)));
|
||||
// return res.Hash;
|
||||
// }
|
||||
|
||||
// static _encryptPost(post) {
|
||||
// return new Post(encryption.encrypt(post.content, privkey, pubkey));
|
||||
// }
|
||||
// }
|
||||
|
||||
// module.exports = MessageFactory;
|
13
MetaInfo.js
Normal file
13
MetaInfo.js
Normal file
@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
var encryption = require('./Encryption');
|
||||
|
||||
class MetaInfo {
|
||||
constructor(type, size, ts) {
|
||||
this.type = type;
|
||||
this.size = size;
|
||||
this.ts = ts;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaInfo;
|
213
OrbitClient.js
Normal file
213
OrbitClient.js
Normal file
@ -0,0 +1,213 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var ipfsDaemon = require('./ipfs-daemon');
|
||||
var ipfsAPI = require('./ipfs-api-promised');
|
||||
var HashCache = require('./HashCacheClient');
|
||||
var HashCacheItem = require('./HashCacheItem').EncryptedHashCacheItem;
|
||||
var MetaInfo = require('./MetaInfo');
|
||||
var ItemTypes = require('./ItemTypes');
|
||||
var Keystore = require('./Keystore');
|
||||
var Post = require('./Post');
|
||||
var encryption = require('./Encryption');
|
||||
|
||||
var pubkey = Keystore.getKeys().publicKey;
|
||||
var privkey = Keystore.getKeys().privateKey;
|
||||
|
||||
class OrbitClientFactory {
|
||||
static connect(host, username, password, ipfs) {
|
||||
if(!ipfs) {
|
||||
var ipfsd = await(ipfsDaemon());
|
||||
ipfs = ipfsd.daemon;
|
||||
}
|
||||
|
||||
var client = new OrbitClient(host, username, password, ipfs);
|
||||
await(client._connect())
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
class OrbitClient {
|
||||
constructor(host, username, password, ipfs) {
|
||||
this.host = host;
|
||||
this.credentials = { username: username, password: password };
|
||||
this.channels = {};
|
||||
this.ipfs = ipfs;
|
||||
}
|
||||
|
||||
channel(hash, password) {
|
||||
return {
|
||||
iterator: (options) => this._iterator(hash, password, options),
|
||||
send: (text, options) => {
|
||||
if(!this.channels[hash]) {
|
||||
this.channels[hash] = { seq: 0 }
|
||||
var item = await(this.client.linkedList(hash, password).head())
|
||||
if(item.head) {
|
||||
var headItem = await (ipfsAPI.getObject(this.ipfs, item.head));
|
||||
this.channels[hash] = { seq: JSON.parse(headItem.Data)["seq"] + 1 }
|
||||
}
|
||||
} else {
|
||||
this.channels[hash] = { seq: this.channels[hash].seq + 1 }
|
||||
}
|
||||
return this._send(hash, password, text, options);
|
||||
},
|
||||
delete: () => this._delete(hash, password),
|
||||
setMode: (mode) => { /* TODO */ }
|
||||
}
|
||||
}
|
||||
|
||||
_iterator(channel, password, options) {
|
||||
var currentIndex = 0;
|
||||
var messages = [];
|
||||
|
||||
if(!options) options = {};
|
||||
|
||||
// Options
|
||||
var limit = options.limit ? options.limit : 1;
|
||||
var gt = options.gt ? options.gt : null;
|
||||
var gte = options.gte ? options.gte : null;
|
||||
var lt = options.lt ? options.lt : null;
|
||||
var lte = options.lte ? options.lte : null;
|
||||
var reverse = options.reverse ? options.reverse : false;
|
||||
|
||||
var startFromHash;
|
||||
if(lt || lte) {
|
||||
startFromHash = lte ? lte : lt;
|
||||
} else {
|
||||
var channel = await (this.client.linkedList(channel, password).head())
|
||||
startFromHash = channel.head ? channel.head : null;
|
||||
}
|
||||
|
||||
if((gt || lt) && limit > -1) limit += 1;
|
||||
|
||||
if(startFromHash) {
|
||||
// Get messages
|
||||
messages = this._fetchRecursive(startFromHash, password, limit, gte ? gte : gt, 0);
|
||||
|
||||
// Slice the array
|
||||
var startIndex = 0;
|
||||
var endIndex = messages.length;
|
||||
if(limit > -1) {
|
||||
startIndex = Math.max(messages.length - limit, 0);
|
||||
endIndex = messages.length - ((gt || lt) ? 1 : 0);
|
||||
} else if(limit === -1) {
|
||||
endIndex = messages.length - (gt ? 1 : 0);
|
||||
}
|
||||
|
||||
messages = messages.slice(startIndex, endIndex)
|
||||
}
|
||||
|
||||
if(reverse) messages.reverse();
|
||||
|
||||
// Iterator interface implementation
|
||||
let iterator = {
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
},
|
||||
next: () => {
|
||||
var item = { value: messages[currentIndex], done: false };
|
||||
if(currentIndex < messages.length)
|
||||
currentIndex ++;
|
||||
else
|
||||
item = { value: null, done: true };
|
||||
return item;
|
||||
},
|
||||
collect: () => {
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
// return Promise.resolve(iterator);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
_fetchOne(hash, password) {
|
||||
var item = null;
|
||||
if(hash) {
|
||||
item = await (ipfsAPI.getObject(this.ipfs, hash));
|
||||
var data = JSON.parse(item.Data);
|
||||
|
||||
// verify
|
||||
var verified = encryption.verify(data.target, data.pubkey, data.sig, data.seq, password);
|
||||
if(!verified) throw "Item '" + hash + "' has the wrong signature"
|
||||
|
||||
// decrypt
|
||||
var targetDec = encryption.decrypt(data.target, privkey, 'TODO: pubkey');
|
||||
var metaDec = encryption.decrypt(data.meta, privkey, 'TODO: pubkey');
|
||||
data.target = targetDec;
|
||||
data.meta = JSON.parse(metaDec);
|
||||
item.Data = data;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
_fetchRecursive(hash, password, amount, last, currentDepth) {
|
||||
var res = [];
|
||||
|
||||
if(!last && amount > -1 && currentDepth >= amount)
|
||||
return res;
|
||||
|
||||
var message = await (this._fetchOne(hash, password));
|
||||
res.push({ hash: hash, item: message });
|
||||
|
||||
currentDepth ++;
|
||||
|
||||
if((last && hash === last))
|
||||
return res;
|
||||
|
||||
if(message && message.Links[0]) {
|
||||
var next = this._fetchRecursive(message.Links[0].Hash, password, amount, last, currentDepth);
|
||||
res = res.concat(next);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_publish(text) {
|
||||
var post = new Post(text);
|
||||
post.encrypt(privkey, pubkey);
|
||||
return await (ipfsAPI.putObject(this.ipfs, JSON.stringify(post)));
|
||||
}
|
||||
|
||||
_createMessage(channel, password, post) {
|
||||
var seq = this.channels[channel].seq;
|
||||
var size = -1;
|
||||
var metaInfo = new MetaInfo(ItemTypes.Message, size, new Date().getTime());
|
||||
var hcItem = new HashCacheItem(seq, post.Hash, metaInfo, pubkey, privkey, password);
|
||||
var item = await (ipfsAPI.putObject(this.ipfs, JSON.stringify(hcItem)));
|
||||
var newHead = { Hash: item.Hash };
|
||||
|
||||
if(seq > 0) {
|
||||
var iter = this._iterator(channel, password);
|
||||
var prevHead = iter.next().value;
|
||||
var headItem = await (ipfsAPI.getObject(this.ipfs, prevHead.hash));
|
||||
seq = JSON.parse(headItem.Data)["seq"] + 1;
|
||||
newHead = await (ipfsAPI.patchObject(this.ipfs, item.Hash, prevHead.hash))
|
||||
}
|
||||
|
||||
return newHead;
|
||||
}
|
||||
|
||||
_send(channel, password, text, options) {
|
||||
// TODO: check options for what type to publish as (text, snippet, file, etc.)
|
||||
var post = this._publish(text);
|
||||
var message = this._createMessage(channel, password, post);
|
||||
await(this.client.linkedList(channel, password).add(message.Hash))
|
||||
return message.Hash;
|
||||
}
|
||||
|
||||
_delete(channel, password) {
|
||||
await(this.client.linkedList(channel, password).delete())
|
||||
delete this.channels[channel];
|
||||
return true;
|
||||
}
|
||||
|
||||
_connect() {
|
||||
this.client = await(HashCache.connect(this.host, this.credentials.username, this.credentials.password));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = OrbitClientFactory;
|
15
Post.js
Normal file
15
Post.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var encryption = require('./Encryption');
|
||||
|
||||
class Post {
|
||||
constructor(content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
encrypt(privkey, pubkey) {
|
||||
this.content = encryption.encrypt(this.content, privkey, pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Post;
|
65
README.md
Normal file
65
README.md
Normal file
@ -0,0 +1,65 @@
|
||||
# orbit-client
|
||||
|
||||
## Introduction
|
||||
|
||||
***VERY MUCH WIP! WILL NOT WORK WHEN CLONED, orbit-server REQUIRED!***
|
||||
|
||||
Client library to interact with orbit-server. Implements the levelDOWN API without get(key, cb).
|
||||
|
||||
orbit-server uses linked lists on top of IPFS.
|
||||
|
||||
### TODO
|
||||
- local caching of messages
|
||||
- channel.send()
|
||||
- check options for what type to publish as (text, snippet, file, etc.)
|
||||
- channel.setMode()
|
||||
|
||||
## API
|
||||
|
||||
connect(host, username, password)
|
||||
|
||||
channel(name, password)
|
||||
|
||||
.send(text)
|
||||
|
||||
.iterator([options])
|
||||
|
||||
.delete()
|
||||
|
||||
## Usage
|
||||
```javascript
|
||||
var OrbitClient = require('./OrbitClient');
|
||||
|
||||
var host = 'localhost:3006'; // orbit-server address
|
||||
|
||||
// Connect
|
||||
var orbit = OrbitClient.connect(host, username, password); // OrbitClient
|
||||
|
||||
var channelName = 'hello-world';
|
||||
var channelPwd = '';
|
||||
|
||||
// Send a message
|
||||
var head = orbit.channel(channelName, channelPwd).send('hello'); // <ipfs-hash>
|
||||
|
||||
// Iterator options
|
||||
var options = { limit: -1 }; // fetch all messages
|
||||
// {
|
||||
// gt: <hash>,
|
||||
// gte: <hash>,
|
||||
// lt: <hash>,
|
||||
// lte: <hash>,
|
||||
// limit: 10,
|
||||
// reverse: true
|
||||
// }
|
||||
|
||||
// Get messages
|
||||
var iter = orbit.channel(channelName, channelPwd).iterator(options); // Symbol.iterator
|
||||
var next = iter.next(); // { value: <item>, done: false|true}
|
||||
|
||||
// OR:
|
||||
// for(let i of iter)
|
||||
// console.log(i.hash, i.item.Data.seq);
|
||||
|
||||
// delete channel
|
||||
var result = orbit.channel(channelName, channelPwd).delete(); // true | false
|
||||
```
|
21
TODO.md.js
Normal file
21
TODO.md.js
Normal file
@ -0,0 +1,21 @@
|
||||
var orbit = await (OrbitClient.connect(host, username, password));
|
||||
var head = await (orbit.channel(channelName, channelPwd).send('hello world'));
|
||||
var iter = await (orbit.channel(channelName, channelPwd).iterator());
|
||||
var next = iter.next();
|
||||
var deleted = await (orbit.channel(channelName, channelPwd).delete());
|
||||
var modes = await (orbit.channel(channelName, channelPwd).setMode({mode: '+r', params: 'password': '123' }));
|
||||
|
||||
// Pubsub
|
||||
await (orbit.channel(channelName, channelPwd).subscribe(onMessage));
|
||||
var head = await (orbit.channel(channelName, channelPwd).publish('hello world'));
|
||||
|
||||
|
||||
|
||||
orbit.connect(host, username, password)
|
||||
|
||||
orbit.channels.list() // { 'ch1':{...}, 'ch2': {...} }
|
||||
orbit.channels.join('ch3', password)
|
||||
orbit.channels.leave('ch3')
|
||||
orbit.channels.onMessage(callback)
|
||||
|
||||
orbit.publish('ch3', 'hello!')
|
81
ipfs-api-promised.js
Normal file
81
ipfs-api-promised.js
Normal file
@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
var ipfsAPI = {
|
||||
cat: (ipfs, hash, cb) => {
|
||||
var ipfscat = Promise.promisify(ipfs.cat);
|
||||
return ipfscat(hash);
|
||||
},
|
||||
ls: async ((ipfs, hash) => {
|
||||
var ipfsls = Promise.promisify(ipfs.ls);
|
||||
return ipfsls(hash);
|
||||
}),
|
||||
add: async ((ipfs, filePath) => {
|
||||
var addFiles = Promise.promisify((filePath, cb) => {
|
||||
ipfs.add(filePath, { recursive: true }, cb);
|
||||
});
|
||||
return addFiles(filePath);
|
||||
}),
|
||||
getObject: async ((ipfs, hash) => {
|
||||
var getObject = Promise.promisify(ipfs.object.get);
|
||||
return getObject(hash);
|
||||
}),
|
||||
putObject: async ((ipfs, payload) => {
|
||||
var putObject = Promise.promisify((payload, cb) => {
|
||||
ipfs.object.put(new Buffer(JSON.stringify({ Data: payload })), "json", cb);
|
||||
});
|
||||
return putObject(payload);
|
||||
}),
|
||||
patchObject: async ((ipfs, root, target) => {
|
||||
var patchObject = Promise.promisify((root, target, cb) => {
|
||||
ipfs.object.patch(root, ["add-link", "next", target], cb);
|
||||
});
|
||||
return patchObject(root, target);
|
||||
}),
|
||||
statObject: async ((ipfs, hash) => {
|
||||
var getObject = Promise.promisify(ipfs.object.stat);
|
||||
return getObject(hash);
|
||||
}),
|
||||
pinObject: async ((ipfs, hash) => {
|
||||
var pinObject = Promise.promisify(ipfs.pin.add);
|
||||
return pinObject(hash);
|
||||
}),
|
||||
getPinned: async ((ipfs) => {
|
||||
var getPinned = Promise.promisify(ipfs.pin.list);
|
||||
var list = await (getPinned());
|
||||
return Object.keys(list.Keys);
|
||||
}),
|
||||
swarmPeers: async ((ipfs) => {
|
||||
var getPeers = Promise.promisify(ipfs.swarm.peers);
|
||||
return getPeers();
|
||||
}),
|
||||
swarmConnect: async ((ipfs, hash) => {
|
||||
var connect = Promise.promisify(ipfs.swarm.connect);
|
||||
return await (connect(hash));
|
||||
}),
|
||||
dhtPut: async ((ipfs, key, value) => {
|
||||
var put = Promise.promisify(ipfs.dht.put);
|
||||
return put(key, value);
|
||||
}),
|
||||
dhtGet: async ((ipfs, key) => {
|
||||
var get = Promise.promisify(ipfs.dht.get);
|
||||
return get(key);
|
||||
}),
|
||||
dhtQuery: async ((ipfs, peerID) => {
|
||||
var query = Promise.promisify(ipfs.dht.query);
|
||||
return query(peerID);
|
||||
}),
|
||||
dhtFindProviders: async ((ipfs, hash) => {
|
||||
var findprov = Promise.promisify(ipfs.dht.findprovs);
|
||||
return findprov(hash);
|
||||
}),
|
||||
dhtFindPeer: async ((ipfs, peerID) => {
|
||||
var findpeer = Promise.promisify(ipfs.dht.findpeer);
|
||||
return findpeer(peerID);
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = ipfsAPI;
|
35
ipfs-daemon.js
Normal file
35
ipfs-daemon.js
Normal file
@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var Promise = require('bluebird');
|
||||
var ipfsdCtl = require('ipfsd-ctl');
|
||||
|
||||
let getUserHome = () => {
|
||||
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||
};
|
||||
|
||||
let ipfsPath = path.resolve(getUserHome() + '/.ipfs');
|
||||
|
||||
var startIpfs = async (() => {
|
||||
let ipfs, nodeInfo;
|
||||
|
||||
try {
|
||||
var ipfsNode = Promise.promisify(ipfsdCtl.local.bind(ipfsPath))
|
||||
var ipfsd = await (ipfsNode());
|
||||
var start = Promise.promisify(ipfsd.startDaemon.bind(ipfsd));
|
||||
ipfs = await (start());
|
||||
var getId = Promise.promisify(ipfs.id);
|
||||
nodeInfo = await (getId())
|
||||
} catch(e) {
|
||||
console.log("Error initializing ipfs daemon:", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return { daemon: ipfs, nodeInfo: nodeInfo };
|
||||
});
|
||||
|
||||
module.exports = async(() => {
|
||||
return await(startIpfs());
|
||||
});
|
27
keys/private.pem
Normal file
27
keys/private.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAnVo7VWOTSXV9Jril0lBB0G0b2Smoj5TozbK3fZ86rkgJSdiE
|
||||
sIbD/dpl6oQSraHXX8Cpu9AdqvzDd3Mf/8SsKfHmobNRUKUPZkgHWbK1eMfIq+kh
|
||||
0ggE4wXYTKAA7kGIzCUWGkSG2tqo7R5FDHdbpQtevh+qqg1I8cYccS1WVXFNy9Em
|
||||
vdLPXH7a8ZsWzM9XrW7LX5Bpo1z2+LYVHcNYG04zVA8Ulrv3bG24ATCRKQdxzVpQ
|
||||
mNx8r9W47ESo9krLoNbwrY4A7rURQjBOBS5tUq52Ui2YImA3BG57O8jY/fBT0u9O
|
||||
5D8BsmjBM+4/0t7I2r1OcAc9ERNy89iBsjSLawIDAQABAoIBAFn8aygm/OkqpnrJ
|
||||
aBNBUJIIg7+KYlpSV1yjUuolcGKQ0bcIesGVIGqBRn16MFBZ2JhqzuaYWw8Y5BPg
|
||||
o7EaYTbPnwxkRyFuc8MTeBik6cD7x9gASBYb/edyxUL00fNvSPMuVliJTfHE0Ixi
|
||||
HizF6YQWX4UtCOWdGVUi7csPmWrcrnYbALHPtb7Z4u/hSa1N4ZuaHd8ljWwDgLgB
|
||||
P8B/5beeZVtpfYgrEorqRwIXxVR/vo1fafV/DUtctEPg7wEIsPAyd1Gt9WVmv1Ij
|
||||
RyxXyhicGJWQnVlj6Iraco8OqSGjRspsMxnS+ccic+1U2ImDBpTHmoSj4ncyGNMP
|
||||
WPodN2kCgYEAzdC9KGge/1Vm8IGGfiqm1Uu8GKhAJOi4t3i1p9f3jH5OyEM8PRHv
|
||||
6hYqtoa+bTBfA5ErQSBI7Yn7qSHrCV1cV9MWD5wnxAKzRHwMAM81HbH2P6D2l/YH
|
||||
QVUmdgKy7zIWUDHxaeFUdbM55Z3NQIrEmyLnv4pzQivT9tBDhHUip78CgYEAw7hg
|
||||
C6mOvV6rb3MXVplZlIUmccNcEVNkc/0mcLCJ33BMV+hR4DBf+abNIeutKq8Q0hbZ
|
||||
PWgbprzQAL7mnMbQXv3yVdIQrcCZKJ4Y7Tz5sofVtNVQCPbLcG/k+beM96q/jodr
|
||||
IYzExub3pX9LzgZHoMdwzLDKDKy6iT0iORkLZ1UCgYBtVNuHIXiF7toWHNhTIVkq
|
||||
qWasOoSIls+5NvhYxxMLoPU80OqpDmRCF7Bs8bsqya1PecheekYDWW9Ec24ltWCe
|
||||
jtWDSVKef0i3sqW1sFzo/2ZuepVEOD+2ZwNdYSWohxTvWPiDZF23gJPa9C7agFzc
|
||||
hHhTebqshhe9Xvje3lKghQKBgFB2eU3yHFOwGuzLtRmOG+zaPK7icPRSg2bH+Ui0
|
||||
20m3wjsVsKtpV9ur/oNmf5+fr1uftxnutgd7ckwML4Tem4WiA0HTBbZZCt5O+NJ3
|
||||
kfQasfoRBEFbLNIBvnIHSvX7BZuUArAdTjyzcbZhOgnuPP5VYANW3woM7PdE4c/1
|
||||
guGtAoGAKhL5UTD2aQDYFWt4fQvoHTrGIT5LcifegYRd+jQRiW7DRg4opknPWdj8
|
||||
xvBExU1ZXtvxpT+KuvAhAqjc8usC+5VhoEYbX2F06ubqhy9aQbCtL5sIhZPVIUIq
|
||||
UVYu1uWj9FqTJWgVhdMQ3P6PrIb9UaWRwkBYsGJulbT88YPet6I=
|
||||
-----END RSA PRIVATE KEY-----
|
19
keys/public.pem
Normal file
19
keys/public.pem
Normal file
@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDBjCCAe4CCQDai2CYe+oyADANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
|
||||
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
|
||||
cyBQdHkgTHRkMB4XDTE1MTAyNDE4MzQwNloXDTE1MTEyMzE4MzQwNlowRTELMAkG
|
||||
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
|
||||
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AJ1aO1Vjk0l1fSa4pdJQQdBtG9kpqI+U6M2yt32fOq5ICUnYhLCGw/3aZeqEEq2h
|
||||
11/AqbvQHar8w3dzH//ErCnx5qGzUVClD2ZIB1mytXjHyKvpIdIIBOMF2EygAO5B
|
||||
iMwlFhpEhtraqO0eRQx3W6ULXr4fqqoNSPHGHHEtVlVxTcvRJr3Sz1x+2vGbFszP
|
||||
V61uy1+QaaNc9vi2FR3DWBtOM1QPFJa792xtuAEwkSkHcc1aUJjcfK/VuOxEqPZK
|
||||
y6DW8K2OAO61EUIwTgUubVKudlItmCJgNwRuezvI2P3wU9LvTuQ/AbJowTPuP9Le
|
||||
yNq9TnAHPRETcvPYgbI0i2sCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAjYne/qu7
|
||||
7KylXi39x72cY/sEpTErKMhCJNm4DL3Mb4YfkDiOZFbNGO+1NKNKHB1DTbu5ECtT
|
||||
vYrBLGwLICklVpVP65podAHweDGGEMW6cp4ypWOpJM4NqyNtL8HKpi2PB/n3SkYi
|
||||
z7aCuagHbU+5YZhm4kj8KDjmbCyn7hU1vQVKf+fw+dLXNUAElI1GLv2tENEEevtl
|
||||
Tj7DurHCrxPcdrbgxQMIbDcpPMXVX4OlS51EsT5mVgGIoUFKZN8u9+AwzU+INKZp
|
||||
6SjbrK3y/HqI4jgeDQPY9GQcGooL1ro9OHfSz61m6WiYh9V6vjq2e8bmc00U/yTA
|
||||
lSErmB6aqZ2+0w==
|
||||
-----END CERTIFICATE-----
|
21
package.json
Normal file
21
package.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "orbit-client",
|
||||
"version": "1.0.0",
|
||||
"description": "A client module to communicate with an Orbit network",
|
||||
"main": "OrbitClient.js",
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
},
|
||||
"author": "Haad",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"asyncawait": "^1.0.1",
|
||||
"bluebird": "^3.1.1",
|
||||
"bs58": "^3.0.0",
|
||||
"ipfsd-ctl": "^0.7.1",
|
||||
"unirest": "^0.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "^2.3.4"
|
||||
}
|
||||
}
|
460
test/orbit-client-tests.js
Normal file
460
test/orbit-client-tests.js
Normal file
@ -0,0 +1,460 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var encryption = require('../Encryption');
|
||||
var OrbitClient = require('../OrbitClient');
|
||||
|
||||
// var mockServerAddresses = [
|
||||
// "localhost",
|
||||
// "127.0.0.1"
|
||||
// ];
|
||||
|
||||
// var serverConfig = {
|
||||
// networkId: "anon-test",
|
||||
// networkName: "Anonymous Networks TEST",
|
||||
// salt: "thisisthenetworksalt",
|
||||
// userDataPath: path.resolve("/tmp/anon-server-tests"),
|
||||
// verifyMessages: true
|
||||
// }
|
||||
|
||||
// Create the userDataPath in case it doesn't exist
|
||||
// if(!fs.existsSync(serverConfig.userDataPath))
|
||||
// fs.mkdirSync(serverConfig.userDataPath);
|
||||
|
||||
// Orbit
|
||||
var host = 'localhost:3006';
|
||||
var username = 'testrunner';
|
||||
var password = '';
|
||||
|
||||
describe('Orbit Client', () => {
|
||||
// let ipfs, server, orbit, httpServer;
|
||||
let orbit;
|
||||
|
||||
let head = '';
|
||||
let second = '';
|
||||
let items = [];
|
||||
let channel = 'abc';
|
||||
|
||||
before(function(done) {
|
||||
// logger.setLevel('ERROR');
|
||||
// Start ipfs daemon
|
||||
// if(!ipfs && !server) {
|
||||
// var startIpfsDaemon = new Promise(async((resolve, reject) => {
|
||||
// ipfs = await(ipfsd());
|
||||
// ipfs.nodeInfo.Addresses = mockServerAddresses;
|
||||
// // Start hash-cache server
|
||||
// server = require('../../ipfs-backend/server/server')(ipfs.daemon, ipfs.nodeInfo, serverConfig);
|
||||
// httpServer = server.app.listen(3006, async(() => {
|
||||
// logger.info('network server listening at http://localhost:%s', 3006);
|
||||
// orbit = await(OrbitClient.connect(host, username, password, ipfs.daemon));
|
||||
// resolve();
|
||||
// }));
|
||||
// }));
|
||||
// startIpfsDaemon.then(done);
|
||||
// } else {
|
||||
// done();
|
||||
// }
|
||||
var start = () => new Promise(async((resolve, reject) => {
|
||||
orbit = OrbitClient.connect(host, username, password);
|
||||
resolve();
|
||||
}));
|
||||
start().then(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
// server.shutdown();
|
||||
// httpServer.close();
|
||||
// rmDir(serverConfig.userDataPath);
|
||||
done();
|
||||
});
|
||||
|
||||
/* TESTS */
|
||||
describe('Connect', function() {
|
||||
it('connects to hash-cache-server', async((done) => {
|
||||
assert.notEqual(orbit, null);
|
||||
assert.notEqual(orbit.client, null);
|
||||
assert.equal(orbit.host, host);
|
||||
assert.equal(orbit.credentials.username, username);
|
||||
assert.equal(orbit.credentials.password, password);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Delete channel', function() {
|
||||
it('deletes a channel', async((done) => {
|
||||
var result = orbit.channel(channel, '').delete();
|
||||
assert.equal(result, true);
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
assert.equal(iter.next().value, null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('deletes a channel with a password', async((done) => {
|
||||
done();
|
||||
}));
|
||||
|
||||
it('doesn\'t delete a channel when password is wrong', async((done) => {
|
||||
done();
|
||||
}));
|
||||
|
||||
it('doesn\'t delete a channel when user is not an op', async((done) => {
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Insert', function() {
|
||||
it('adds an item to an empty channel', async((done) => {
|
||||
try {
|
||||
head = orbit.channel(channel, '').send('hello');
|
||||
assert.notEqual(head, null);
|
||||
assert.equal(head.startsWith('Qm'), true);
|
||||
assert.equal(head.length, 46);
|
||||
} catch(e) {
|
||||
assert.equal(e, null);
|
||||
}
|
||||
done();
|
||||
}));
|
||||
|
||||
it('adds a new item to a channel with one item', async((done) => {
|
||||
try {
|
||||
second = orbit.channel(channel, '').send('hello');
|
||||
assert.notEqual(second, null);
|
||||
assert.notEqual(second, head);
|
||||
assert.equal(second.startsWith('Qm'), true);
|
||||
assert.equal(second.length, 46);
|
||||
} catch(e) {
|
||||
assert.equal(e, null);
|
||||
}
|
||||
done();
|
||||
}));
|
||||
|
||||
it('adds five items', async((done) => {
|
||||
for(var i = 0; i < 5; i ++) {
|
||||
try {
|
||||
var s = orbit.channel(channel, '').send('hello');
|
||||
assert.notEqual(s, null);
|
||||
assert.equal(s.startsWith('Qm'), true);
|
||||
assert.equal(s.length, 46);
|
||||
} catch(e) {
|
||||
assert.equal(e, null);
|
||||
}
|
||||
}
|
||||
done();
|
||||
}));
|
||||
|
||||
it('adds an item that is > 256 bytes', async((done) => {
|
||||
try {
|
||||
var msg = new Buffer(512);
|
||||
msg.fill('a')
|
||||
var s = orbit.channel(channel, '').send(msg.toString());
|
||||
assert.notEqual(s, null);
|
||||
assert.equal(s.startsWith('Qm'), true);
|
||||
assert.equal(s.length, 46);
|
||||
} catch(e) {
|
||||
assert.equal(e, null);
|
||||
}
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('Iterator', function() {
|
||||
var items = [];
|
||||
var itemCount = 5;
|
||||
|
||||
before(function(done) {
|
||||
var addMessages = () => new Promise(async((resolve, reject) => {
|
||||
var result = orbit.channel(channel, '').delete();
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
for(var i = 0; i < itemCount; i ++) {
|
||||
var s = orbit.channel(channel, '').send('hello');
|
||||
items.push(s);
|
||||
}
|
||||
resolve();
|
||||
}));
|
||||
addMessages().then(done);
|
||||
});
|
||||
|
||||
describe('Defaults', function() {
|
||||
it('returns an iterator', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
assert.notEqual(iter, null);
|
||||
assert.notEqual(iter.next, null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('implements Iterator interface', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -1 });
|
||||
var messages = [];
|
||||
|
||||
for(let i of iter)
|
||||
messages.push(i.hash);
|
||||
|
||||
assert.equal(messages.length, items.length);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 1 item as default', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var first = iter.next().value;
|
||||
var second = iter.next().value;
|
||||
assert.equal(first.hash, items[items.length - 1]);
|
||||
assert.equal(second, null);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Collect', function() {
|
||||
it('returns all items', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -1 });
|
||||
var messages = iter.collect();
|
||||
assert.equal(messages.length, items.length);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 1 item', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var messages = iter.collect();
|
||||
assert.equal(messages.length, 1);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 3 items', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: 3 });
|
||||
var messages = iter.collect();
|
||||
assert.equal(messages.length, 3);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Options: limit', function() {
|
||||
it('returns 1 item when limit is 0', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: 0 });
|
||||
var first = iter.next().value;
|
||||
var second = iter.next().value;
|
||||
assert.equal(first.hash, items[items.length - 1]);
|
||||
assert.equal(second, null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 1 item when limit is 1', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: 1 });
|
||||
var first = iter.next().value;
|
||||
var second = iter.next().value;
|
||||
assert.equal(first.hash, items[items.length - 1]);
|
||||
assert.equal(second, null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 3 items', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: 3 });
|
||||
var first = iter.next().value;
|
||||
var second = iter.next().value;
|
||||
var third = iter.next().value;
|
||||
var fourth = iter.next().value;
|
||||
assert.equal(first.hash, items[items.length - 1]);
|
||||
assert.equal(second.hash, items[items.length - 2]);
|
||||
assert.equal(third.hash, items[items.length - 3]);
|
||||
assert.equal(fourth, null);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -1 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
messages.reverse();
|
||||
assert.equal(messages.length, items.length);
|
||||
assert.equal(messages[0], items[0]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items when limit is bigger than -1', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -300 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, items.length);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items when limit is bigger than number of items', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: 300 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, items.length);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Options: reverse', function() {
|
||||
it('returns all items reversed', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -1, reverse: true });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, items.length);
|
||||
assert.equal(messages[0], items[0]);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Options: ranges', function() {
|
||||
describe('gt & gte', function() {
|
||||
it('returns 0 items when gt is the head', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ gt: head.hash });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 0);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 1 item when gte is the head', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ gte: items[items.length -1], limit: -1 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 1);
|
||||
assert.equal(messages[0], items[items.length -1]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 2 item when gte is defined', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ gte: items[items.length - 2], limit: -1 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 2);
|
||||
assert.equal(messages[0], items[items.length - 1]);
|
||||
assert.equal(messages[1], items[items.length - 2]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items when gte is the root item', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ gte: items[0], limit: -1 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, itemCount);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns items when gt is the root item', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ gt: items[0], limit: -1 });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, itemCount - 1);
|
||||
assert.equal(messages[0], items[items.length - 1]);
|
||||
assert.equal(messages[3], items[1]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns items when gt is defined', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ limit: -1});
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
var gt = messages[2];
|
||||
var iter2 = orbit.channel(channel, '').iterator({ gt: gt, limit: 100 });
|
||||
var messages2 = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages2.length, 2);
|
||||
assert.equal(messages2[0], messages[0]);
|
||||
assert.equal(messages2[1], messages[1]);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('lt & lte', function() {
|
||||
it('returns one item when lt is the head', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ lt: head.hash });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 1);
|
||||
assert.equal(messages[0], head.hash);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items when lt is head and limit is -1', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ lt: head.hash, limit: -1 });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, itemCount);
|
||||
assert.equal(messages[0], head.hash);
|
||||
assert.equal(messages[4], items[0]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 3 items when lt is head and limit is 3', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ lt: head.hash, limit: 3 });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 3);
|
||||
assert.equal(messages[0], head.hash);
|
||||
assert.equal(messages[2], items[2]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns null when lt is the root item', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ lt: items[0] });
|
||||
var messages = iter.collect();
|
||||
assert.equal(messages.length, 0);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns one item when lte is the root item', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator({ lte: items[0] });
|
||||
var messages = iter.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 1);
|
||||
assert.equal(messages[0], items[0]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns all items when lte is the head', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ lte: head.hash, limit: -1 });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, itemCount);
|
||||
assert.equal(messages[0], items[items.length - 1]);
|
||||
assert.equal(messages[4], items[0]);
|
||||
done();
|
||||
}));
|
||||
|
||||
it('returns 3 items when lte is the head', async((done) => {
|
||||
var iter = orbit.channel(channel, '').iterator();
|
||||
var head = iter.next().value;
|
||||
var iter2 = orbit.channel(channel, '').iterator({ lte: items[items.length - 2], limit: 3 });
|
||||
var messages = iter2.collect().map((e) => e.hash);
|
||||
|
||||
assert.equal(messages.length, 3);
|
||||
assert.equal(messages[0], items[items.length - 2]);
|
||||
assert.equal(messages[2], items[1]);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// let rmDir = function(dirPath) {
|
||||
// try { var files = fs.readdirSync(dirPath); }
|
||||
// catch(e) { return; }
|
||||
// if (files.length > 0)
|
||||
// for (var i = 0; i < files.length; i++) {
|
||||
// var filePath = dirPath + '/' + files[i];
|
||||
// if (fs.statSync(filePath).isFile())
|
||||
// fs.unlinkSync(filePath);
|
||||
// else
|
||||
// rmDir(filePath);
|
||||
// }
|
||||
// fs.rmdirSync(dirPath);
|
||||
// };
|
Loading…
x
Reference in New Issue
Block a user