epidemic-broadcast-trees
Advanced tools
Comparing version 9.0.3 to 9.0.4
361
events.js
'use strict' | ||
module.exports = function (version) { | ||
const { note, getReceive, getReplicate, getSequence } = version | ||
var exports = { | ||
const exports = { | ||
note, | ||
@@ -15,11 +14,11 @@ getReceive, | ||
function isEmpty (o) { | ||
for (var k in o) return false | ||
return true | ||
if (o == null) return true | ||
return Object.keys(o).length === 0 | ||
} | ||
function isObject (o) { | ||
return o && 'object' === typeof o | ||
return o && typeof o === 'object' | ||
} | ||
function isBlocked(state, id, target) { | ||
function isBlocked (state, id, target) { | ||
return state.blocks[id] && state.blocks[id][target] | ||
@@ -32,7 +31,7 @@ } | ||
//check if a feed is already being replicated on another peer from ignoreId | ||
function isAlreadyReplicating(state, feedId, ignoreId) { | ||
for (var id in state.peers) { | ||
// check if a feed is already being replicated on another peer from ignoreId | ||
function isAlreadyReplicating (state, feedId, ignoreId) { | ||
for (const id in state.peers) { | ||
if (id !== ignoreId) { | ||
var peer = state.peers[id] | ||
const peer = state.peers[id] | ||
if (peer.notes && getReceive(peer.notes[id])) return id | ||
@@ -42,3 +41,3 @@ | ||
// this fixed a partial replication bug where a node is unable to send the full log | ||
var idHasSent = peer.replicating && peer.replicating[id] && peer.replicating[id].sent != -1 | ||
const idHasSent = peer.replicating && peer.replicating[id] && peer.replicating[id].sent !== -1 | ||
if (peer.replicating && peer.replicating[feedId] && peer.replicating[feedId].rx && idHasSent) return id | ||
@@ -54,4 +53,4 @@ } | ||
if (local == null) return remote | ||
if (local == -1 || remote == -1) return remote | ||
if (remote == 0) return 0 | ||
if (local === -1 || remote === -1) return remote | ||
if (remote === 0) return 0 | ||
if (remote > 0 && local > 0 && remote < local) return remote | ||
@@ -61,12 +60,13 @@ return Math.max(local, remote) | ||
//check if a feed is available from a peer apart from ignoreId | ||
// check if a feed is available from a peer apart from ignoreId | ||
function isAvailable(state, feedId, ignoreId) { | ||
for (var peerId in state.peers) { | ||
if (peerId != ignoreId) { | ||
var peer = state.peers[peerId] | ||
//BLOCK: check wether id has blocked this peer | ||
if ((peer.clock && peer.clock[feedId] || 0) > (state.clock[feedId] || 0) && isShared(state, feedId, peerId)) { | ||
return true | ||
} | ||
function isAvailable (state, feedId, ignoreId) { | ||
for (const peerId in state.peers) { | ||
if (peerId !== ignoreId) { | ||
const peer = state.peers[peerId] | ||
// BLOCK: check wether id has blocked this peer | ||
if ( | ||
((peer.clock && peer.clock[feedId]) || 0) > (state.clock[feedId] || 0) && | ||
isShared(state, feedId, peerId) | ||
) return true | ||
} | ||
@@ -76,14 +76,14 @@ } | ||
//jump to a particular key in a list, then iterate from there | ||
//back around to the key. this is used for switching away from | ||
//peers that stall so that you'll rotate through all the peers | ||
//not just swich between two different peers. | ||
// jump to a particular key in a list, then iterate from there | ||
// back around to the key. this is used for switching away from | ||
// peers that stall so that you'll rotate through all the peers | ||
// not just swich between two different peers. | ||
function eachFrom(keys, key, iter) { | ||
var i = keys.indexOf(key) | ||
function eachFrom (keys, key, iter) { | ||
const i = keys.indexOf(key) | ||
if (!~i) return | ||
//start at 1 because we want to visit all keys but key. | ||
for (var j = 1; j < keys.length; j++) | ||
if (iter(keys[(j+i) % keys.length], j)) | ||
return | ||
// start at 1 because we want to visit all keys but key. | ||
for (let j = 1; j < keys.length; j++) { | ||
if (iter(keys[(j + i) % keys.length], j)) { return } | ||
} | ||
} | ||
@@ -95,3 +95,3 @@ | ||
var rep = peer.replicating[feed] | ||
const rep = peer.replicating[feed] | ||
if (rep) { | ||
@@ -104,6 +104,6 @@ rep.rx = rx | ||
// defaults for backwards compatibility | ||
exports.getMsgAuthor = function(msg) { | ||
exports.getMsgAuthor = function (msg) { | ||
return msg.author | ||
} | ||
exports.getMsgSequence = function(msg) { | ||
exports.getMsgSequence = function (msg) { | ||
return msg.sequence | ||
@@ -113,9 +113,7 @@ } | ||
exports.initialize = function (id, getMsgAuthor, getMsgSequence) { | ||
if (getMsgAuthor) | ||
exports.getMsgAuthor = getMsgAuthor | ||
if (getMsgSequence) | ||
exports.getMsgSequence = getMsgSequence | ||
if (getMsgAuthor) { exports.getMsgAuthor = getMsgAuthor } | ||
if (getMsgSequence) { exports.getMsgSequence = getMsgSequence } | ||
return { | ||
id: id, | ||
id, | ||
clock: null, | ||
@@ -135,4 +133,4 @@ follows: {}, | ||
exports.connect = function (state, ev) { | ||
if (state.peers[ev.id]) throw new Error('already connected to peer:'+ev.id) | ||
if (typeof ev.client != 'boolean') throw new Error('connect.client must be boolean') | ||
if (state.peers[ev.id]) throw new Error('already connected to peer:' + ev.id) | ||
if (typeof ev.client !== 'boolean') throw new Error('connect.client must be boolean') | ||
@@ -148,5 +146,5 @@ // if (isBlocked(state, state.id, ev.id)) return state | ||
notes: null, | ||
//if we are client, wait until we receive notes to send code. | ||
//this is a weird way of doing it! shouldn't we just have a bit of state | ||
//for wether we have received a vector clock | ||
// if we are client, wait until we receive notes to send code. | ||
// this is a weird way of doing it! shouldn't we just have a bit of state | ||
// for wether we have received a vector clock | ||
replicating: ev.client ? null : {} | ||
@@ -163,32 +161,30 @@ } | ||
//this is when the stored peer clock has been loaded from the local database. | ||
//note, this must be handled before any messages are received. | ||
// this is when the stored peer clock has been loaded from the local database. | ||
// note, this must be handled before any messages are received. | ||
exports.peerClock = function (state, ev) { | ||
if (!state.peers[ev.id]) | ||
throw new Error('peerClock called for:'+ev.id + ' but only connected to:'+ Object.keys(state.peers)) | ||
var peer = state.peers[ev.id] | ||
var clock = peer.clock = ev.value | ||
if (!state.peers[ev.id]) { throw new Error('peerClock called for:' + ev.id + ' but only connected to:' + Object.keys(state.peers)) } | ||
const peer = state.peers[ev.id] | ||
const clock = peer.clock = ev.value | ||
//client should wait for the server notes, so that stream | ||
//can error before a peer sends a massive handshake. | ||
// client should wait for the server notes, so that stream | ||
// can error before a peer sends a massive handshake. | ||
if (peer.replicating == null) return state | ||
//always set an empty clock here, so that if we don't have anything | ||
//to send, we still send this empty clock. This only happens on a new connection. | ||
//in every other situation, clock is only sent if there is something in it. | ||
// always set an empty clock here, so that if we don't have anything | ||
// to send, we still send this empty clock. This only happens on a new connection. | ||
// in every other situation, clock is only sent if there is something in it. | ||
peer.notes = peer.notes || {} | ||
//iterate over following and create replications. | ||
//if we want to replicate a peer that has changed since their clock, | ||
//create a replication for that peer. | ||
// iterate over following and create replications. | ||
// if we want to replicate a peer that has changed since their clock, | ||
// create a replication for that peer. | ||
for (var id in state.follows) { | ||
var seq = clock[id] || 0, lseq = state.clock[id] || 0 | ||
//BLOCK: check wether id has blocked this peer | ||
for (const id in state.follows) { | ||
const seq = clock[id] || 0; const lseq = state.clock[id] || 0 | ||
// BLOCK: check wether id has blocked this peer | ||
if (isShared(state, id, ev.id) && seq !== -1 && seq !== state.clock[id]) { | ||
//if we are already replicating, and this feed is at zero, ask for it anyway, | ||
//XXX if a feed is at zero, but we are replicating on another peer | ||
//just don't ask for it yet? | ||
var replicating = isAlreadyReplicating(state, id, ev.id)// && lseq | ||
// if we are already replicating, and this feed is at zero, ask for it anyway, | ||
// XXX if a feed is at zero, but we are replicating on another peer | ||
// just don't ask for it yet? | ||
const replicating = isAlreadyReplicating(state, id, ev.id)// && lseq | ||
peer.replicating = peer.replicating || {} | ||
@@ -208,15 +204,15 @@ peer.replicating[id] = { | ||
//XXX handle replicating with only one peer. | ||
// XXX handle replicating with only one peer. | ||
exports.follow = function (state, ev) { | ||
//set to true once we have asked for this feed from someone. | ||
var replicating = false | ||
// set to true once we have asked for this feed from someone. | ||
let replicating = false | ||
if (!!state.follows[ev.id] !== ev.value) { | ||
state.follows[ev.id] = ev.value | ||
for (var id in state.peers) { | ||
var peer = state.peers[id] | ||
for (const id in state.peers) { | ||
const peer = state.peers[id] | ||
if (!peer.clock || !peer.replicating || !isShared(state, ev.id, id)) continue | ||
//BLOCK: check wether this feed has has blocked this peer. | ||
//..... don't replicate feeds with peers that have blocked them at all? | ||
// BLOCK: check wether this feed has has blocked this peer. | ||
// ..... don't replicate feeds with peers that have blocked them at all? | ||
//cases: | ||
// cases: | ||
// don't have feed | ||
@@ -226,13 +222,13 @@ // do have feed | ||
// peer rejects feed | ||
var seq = peer.clock[ev.id] || 0, lseq = state.clock[ev.id] || 0 | ||
const seq = peer.clock[ev.id] || 0; const lseq = state.clock[ev.id] || 0 | ||
if (seq === -1) { | ||
//peer explicitly does not replicate this feed, don't ask for it. | ||
} | ||
else if (ev.value === false) { //unfollow | ||
// peer explicitly does not replicate this feed, don't ask for it. | ||
} else if (ev.value === false) { // unfollow | ||
setNotes(peer, ev.id, -1, false) | ||
} | ||
else if (ev.value === true && seq !== state.clock[ev.id]) { | ||
} else if (ev.value === true && seq !== state.clock[ev.id]) { | ||
peer.replicating[ev.id] = { | ||
rx: true, tx: false, | ||
sent: -1, requested: lseq | ||
rx: true, | ||
tx: false, | ||
sent: -1, | ||
requested: lseq | ||
} | ||
@@ -248,10 +244,10 @@ setNotes(peer, ev.id, lseq, !replicating) | ||
exports.retrive = function (state, msg) { | ||
//check if any peer requires this msg | ||
for (var id in state.peers) { | ||
var peer = state.peers[id] | ||
// check if any peer requires this msg | ||
for (const id in state.peers) { | ||
const peer = state.peers[id] | ||
if (!peer.replicating) continue | ||
//BLOCK: check wether id has blocked this peer | ||
// BLOCK: check wether id has blocked this peer | ||
const author = exports.getMsgAuthor(msg) | ||
const sequence = exports.getMsgSequence(msg) | ||
var rep = peer.replicating[author] | ||
const rep = peer.replicating[author] | ||
@@ -262,3 +258,3 @@ if (rep && rep.tx && rep.sent === sequence - 1) { | ||
if (rep.sent < state.clock[author]) { | ||
//use continue, not return because we still need to loop through other peers. | ||
// use continue, not return because we still need to loop through other peers. | ||
if (~peer.retrive.indexOf(author)) continue | ||
@@ -272,3 +268,3 @@ peer.retrive.push(author) | ||
function isAhead(seq1, seq2) { | ||
function isAhead (seq1, seq2) { | ||
if (seq2 === -1) return false | ||
@@ -282,26 +278,24 @@ if (seq2 == null) return true | ||
const sequence = exports.getMsgSequence(msg) | ||
//check if any peer requires this msg | ||
if (state.clock[author] != null && state.clock[author] !== sequence - 1) | ||
return state //ignore | ||
// check if any peer requires this msg | ||
if (state.clock[author] != null && state.clock[author] !== sequence - 1) { return state } // ignore | ||
var lseq = state.clock[author] = sequence | ||
for (var id in state.peers) { | ||
var peer = state.peers[id] | ||
const lseq = state.clock[author] = sequence | ||
for (const id in state.peers) { | ||
const peer = state.peers[id] | ||
if (!peer.clock || !peer.replicating || !isShared(state, author, id)) continue | ||
//BLOCK: check wether msg.author has blocked this peer | ||
// BLOCK: check wether msg.author has blocked this peer | ||
var seq = peer.clock[author] | ||
const seq = peer.clock[author] | ||
var rep = peer.replicating[author] | ||
const rep = peer.replicating[author] | ||
if (rep && rep.tx && rep.sent == lseq - 1 && lseq > seq) { | ||
if (rep && rep.tx && rep.sent === lseq - 1 && lseq > seq) { | ||
peer.msgs.push(msg) | ||
rep.sent++ | ||
} | ||
//if we are ahead of this peer, and not in tx mode, let them know that. | ||
} // eslint-disable-line | ||
// if we are ahead of this peer, and not in tx mode, let them know that. | ||
else if ( | ||
isAhead(lseq, seq) && | ||
(rep ? !rep.tx && rep.sent != null : state.follows[author]) | ||
) | ||
setNotes(peer, author, sequence, false) | ||
) { setNotes(peer, author, sequence, false) } | ||
} | ||
@@ -312,21 +306,21 @@ | ||
//XXX if we only receive from a single peer, | ||
//then we shouldn't really get known messages? | ||
//except during the race when we have disabled a peer | ||
//but they havn't noticed yet. | ||
// XXX if we only receive from a single peer, | ||
// then we shouldn't really get known messages? | ||
// except during the race when we have disabled a peer | ||
// but they havn't noticed yet. | ||
exports.receive = function (state, ev) { | ||
var msg = ev.value | ||
//receive a message, validate and append. | ||
//if this message is forked, disable this feed | ||
const msg = ev.value | ||
// receive a message, validate and append. | ||
// if this message is forked, disable this feed | ||
if (!state.peers[ev.id]) throw new Error('lost peer state:'+ev.id) | ||
if (!state.peers[ev.id]) throw new Error('lost peer state:' + ev.id) | ||
//we _know_ that this peer is upto at least this message now. | ||
//(but maybe they already told us they where ahead further) | ||
// we _know_ that this peer is upto at least this message now. | ||
// (but maybe they already told us they where ahead further) | ||
const author = exports.getMsgAuthor(msg) | ||
const sequence = exports.getMsgSequence(msg) | ||
var peer = state.peers[ev.id] | ||
var rep = peer.replicating[author] | ||
const peer = state.peers[ev.id] | ||
const rep = peer.replicating[author] | ||
//if we havn't asked for this, ignore it. (this is remote speaking protocol wrong!) | ||
// if we havn't asked for this, ignore it. (this is remote speaking protocol wrong!) | ||
if (!rep) return state | ||
@@ -337,3 +331,3 @@ | ||
//if this message has already been seen, ignore. | ||
// if this message has already been seen, ignore. | ||
if (state.clock[author] >= sequence) { | ||
@@ -343,13 +337,12 @@ if (rep.rx) { | ||
} | ||
//XXX activate some other peer? | ||
// XXX activate some other peer? | ||
return state | ||
} | ||
//remember the time of the last message received | ||
// remember the time of the last message received | ||
state.peers[ev.id].ts = ev.ts | ||
//FORKS ignore additional messages if we have already found an invalid one. | ||
if (isShared(state, author, ev.id)) | ||
state.receive.push(ev) | ||
//Q: possibly update the receiving mode? | ||
// FORKS ignore additional messages if we have already found an invalid one. | ||
if (isShared(state, author, ev.id)) { state.receive.push(ev) } | ||
// Q: possibly update the receiving mode? | ||
@@ -359,43 +352,40 @@ return state | ||
//XXX check if we are already receiving a feed | ||
//and if so put this into lazy mode. | ||
// XXX check if we are already receiving a feed | ||
// and if so put this into lazy mode. | ||
exports.notes = function (state, ev) { | ||
//update replicating modes | ||
var clock = ev.value | ||
// update replicating modes | ||
let clock = ev.value | ||
//support sending clocks inside a thing with additional properties. | ||
//this is to allow room for backwards compatible upgrades. | ||
if (isObject(ev.value.clock)) | ||
clock = ev.value.clock | ||
// support sending clocks inside a thing with additional properties. | ||
// this is to allow room for backwards compatible upgrades. | ||
if (isObject(ev.value.clock)) { clock = ev.value.clock } | ||
var peer = state.peers[ev.id] | ||
if (!peer) throw new Error('lost state of peer:'+ev.id) | ||
const peer = state.peers[ev.id] | ||
if (!peer) throw new Error('lost state of peer:' + ev.id) | ||
if (!peer.clock) throw new Error("received notes, but has not set the peer's clock yet") | ||
var count = 0 | ||
let count = 0 | ||
//if we are client, and this is the first notes we receive | ||
// if we are client, and this is the first notes we receive | ||
if (!peer.replicating) { | ||
peer.replicating = {} | ||
state = exports.peerClock(state, {id: ev.id, value: state.peers[ev.id].clock}) | ||
state = exports.peerClock(state, { id: ev.id, value: state.peers[ev.id].clock }) | ||
} | ||
for (var id in clock) { | ||
for (const id in clock) { | ||
count++ | ||
var seq = peer.clock[id] = fixSeq(peer.clock[id], getSequence(clock[id])) | ||
var tx = getReceive(clock[id]) // is even | ||
var isReplicate = getReplicate(clock[id]) // !== -1 | ||
const seq = peer.clock[id] = fixSeq(peer.clock[id], getSequence(clock[id])) | ||
const tx = getReceive(clock[id]) // is even | ||
const isReplicate = getReplicate(clock[id]) // !== -1 | ||
var lseq = state.clock[id] || 0 | ||
const lseq = state.clock[id] || 0 | ||
//check if we are not following this feed. | ||
//BLOCK: or wether id has blocked this peer | ||
// check if we are not following this feed. | ||
// BLOCK: or wether id has blocked this peer | ||
if (!isShared(state, id, ev.id)) { | ||
if (!peer.replicating[id]) | ||
setNotes(peer, id, -1, false) | ||
peer.replicating[id] = {tx: false, rx: false, sent: -1, requested: -1} | ||
} | ||
else { | ||
var rep = peer.replicating[id] | ||
var replicating = isAlreadyReplicating(state, id, ev.id) | ||
if (!peer.replicating[id]) { setNotes(peer, id, -1, false) } | ||
peer.replicating[id] = { tx: false, rx: false, sent: -1, requested: -1 } | ||
} else { | ||
let rep = peer.replicating[id] | ||
const replicating = isAlreadyReplicating(state, id, ev.id) | ||
if (!rep) { | ||
@@ -409,12 +399,11 @@ rep = peer.replicating[id] = { | ||
setNotes(peer, id, lseq, lseq < seq && !replicating) | ||
} | ||
else if (!rep.rx && seq > lseq) { | ||
} else if (!rep.rx && seq > lseq) { | ||
if (!replicating) { | ||
peer.ts = ev.ts //remember ts, so we can switch this feed if necessary | ||
peer.ts = ev.ts // remember ts, so we can switch this feed if necessary | ||
setNotes(peer, id, lseq, true) | ||
} else { | ||
//if we are already replicating this via another peer | ||
//switch to this peer if it is further ahead. | ||
//(todo?: switch if the other peer's timestamp is old?) | ||
var _peer = state.peers[replicating] | ||
// if we are already replicating this via another peer | ||
// switch to this peer if it is further ahead. | ||
// (todo?: switch if the other peer's timestamp is old?) | ||
const _peer = state.peers[replicating] | ||
// note: _peer.clock[id] may be undefined, if we have | ||
@@ -426,3 +415,3 @@ // just connected to them and sent our notes but not | ||
setNotes(peer, id, lseq, true) | ||
setNotes(_peer, id, lseq, false) //deactivate the previous peer | ||
setNotes(_peer, id, lseq, false) // deactivate the previous peer | ||
} | ||
@@ -432,5 +421,5 @@ } | ||
//positive seq means "send this to me please" | ||
// positive seq means "send this to me please" | ||
rep.tx = tx | ||
//in the case we are already ahead, get ready to send them messages. | ||
// in the case we are already ahead, get ready to send them messages. | ||
rep.sent = seq | ||
@@ -449,15 +438,14 @@ if (lseq > seq) { | ||
exports.timeout = function (state, ev) { | ||
var want = {} | ||
const want = {} | ||
for (var peerId in state.peers) { | ||
var peer = state.peers[peerId] | ||
//check if the peer hasn't received a message recently. | ||
for (const peerId in state.peers) { | ||
const peer = state.peers[peerId] | ||
// check if the peer hasn't received a message recently. | ||
//if we havn't received a message from this peer recently | ||
// if we havn't received a message from this peer recently | ||
if ((peer.ts || 0) + state.timeout < ev.ts) { | ||
//check if they have claimed a higher sequence, but not sent us | ||
for (var id in peer.replicating) { | ||
var rep = peer.replicating[id] | ||
//if yes, prepare to switch this feed to that peer | ||
// check if they have claimed a higher sequence, but not sent us | ||
for (const id in peer.replicating) { | ||
const rep = peer.replicating[id] | ||
// if yes, prepare to switch this feed to that peer | ||
if (rep.rx && isAvailable(state, id, peerId)) { | ||
@@ -471,8 +459,8 @@ want[id] = peerId | ||
var peerIds = Object.keys(state.peers) | ||
for (var feedId in want) { | ||
var ignoreId = want[feedId] | ||
const peerIds = Object.keys(state.peers) | ||
for (const feedId in want) { | ||
const ignoreId = want[feedId] | ||
eachFrom(peerIds, ignoreId, function (peerId) { | ||
var peer = state.peers[peerId] | ||
if (peer.clock && peer.clock[feedId] || 0 > state.clock[feedId] || 0) { | ||
const peer = state.peers[peerId] | ||
if ((peer.clock && peer.clock[feedId]) || state.clock[feedId] < 0 || 0) { | ||
peer.replicating = peer.replicating || {} | ||
@@ -484,3 +472,3 @@ peer.replicating[feedId] = peer.replicating[feedId] || { | ||
peer.ts = ev.ts | ||
//returning true triggers the end of eachFrom | ||
// returning true triggers the end of eachFrom | ||
return true | ||
@@ -497,21 +485,18 @@ } | ||
if (state.blocks[ev.id]) delete state.blocks[ev.id][ev.target] | ||
if (isEmpty(state.blocks[ev.id])) | ||
delete state.blocks[ev.id] | ||
} | ||
else { | ||
if (isEmpty(state.blocks[ev.id])) { delete state.blocks[ev.id] } | ||
} else { | ||
state.blocks[ev.id] = state.blocks[ev.id] || {} | ||
state.blocks[ev.id][ev.target] = true | ||
//if we blocked this peer, and we are also connected to them. | ||
//then stop replicating immediately. | ||
// if we blocked this peer, and we are also connected to them. | ||
// then stop replicating immediately. | ||
if (state.id === ev.id && state.peers[ev.target]) { | ||
//end replication immediately. | ||
// end replication immediately. | ||
state.peers[ev.target].blocked = ev.value | ||
} | ||
for (var id in state.peers) { | ||
var peer = state.peers[id] | ||
for (const id in state.peers) { | ||
const peer = state.peers[id] | ||
if (!peer.replicating) continue | ||
if (id === ev.target && peer.replicating[ev.id]) | ||
setNotes(peer, ev.id, -1, false) | ||
if (id === ev.target && peer.replicating[ev.id]) { setNotes(peer, ev.id, -1, false) } | ||
} | ||
@@ -518,0 +503,0 @@ } |
64
index.js
@@ -14,3 +14,3 @@ const Events = require('./events') | ||
var state = events.initialize(opts.id, opts.getMsgAuthor, opts.getMsgSequence) | ||
const state = events.initialize(opts.id, opts.getMsgAuthor, opts.getMsgSequence) | ||
state.timeout = opts.timeout || 3000 | ||
@@ -20,12 +20,12 @@ state.clock = {} | ||
if (!opts.isMsg) { | ||
opts.isMsg = function(m) { | ||
opts.isMsg = function (m) { | ||
return Number.isInteger(m.sequence) && m.sequence > 0 && | ||
typeof m.author == 'string' && m.content | ||
typeof m.author === 'string' && m.content | ||
} | ||
} | ||
var self = { | ||
const self = { | ||
id: opts.id, | ||
streams: {}, | ||
state: state, | ||
state, | ||
logging: opts.logging, | ||
@@ -37,28 +37,26 @@ progress: function () { | ||
if (opts.isFeed && !opts.isFeed(id)) return | ||
self.state = events.follow(self.state, {id: id, value: follows !== false, ts: timestamp()}) | ||
self.state = events.follow(self.state, { id, value: follows !== false, ts: timestamp() }) | ||
self.update() | ||
}, | ||
pause: function (id, paused) { | ||
self.state = events.pause(self.state, {id, paused: paused !== false}) | ||
self.state = events.pause(self.state, { id, paused: paused !== false }) | ||
self.update() | ||
}, | ||
block: function (id, target, value) { | ||
self.state = events.block(self.state, {id, target, value: value !== false, ts: timestamp()}) | ||
self.state = events.block(self.state, { id, target, value: value !== false, ts: timestamp() }) | ||
self.update() | ||
}, | ||
createStream: function (remoteId, version, client) { | ||
if (self.streams[remoteId]) | ||
self.streams[remoteId].end({name: 'Error', message: 'reconnected to peer', stack: ''}) | ||
if (self.streams[remoteId]) { self.streams[remoteId].end({ name: 'Error', message: 'reconnected to peer', stack: '' }) } | ||
if (self.logging) console.log('EBT:conn', remoteId) | ||
function onClose(peerState) { | ||
function onClose (peerState) { | ||
opts.setClock(remoteId, peerState.clock) | ||
} | ||
var stream = new Stream(this, remoteId, version, client, opts.isMsg, onClose) | ||
const stream = new Stream(this, remoteId, version, client, opts.isMsg, onClose) | ||
self.streams[remoteId] = stream | ||
opts.getClock(remoteId, (err, clock) => { | ||
//check if peer exists in state, because we may | ||
//have disconect in the meantime | ||
if (self.state.peers[remoteId]) | ||
stream.clock(err ? {} : clock) | ||
// check if peer exists in state, because we may | ||
// have disconect in the meantime | ||
if (self.state.peers[remoteId]) { stream.clock(err ? {} : clock) } | ||
}) | ||
@@ -73,4 +71,4 @@ | ||
} else { | ||
//this should never happen. | ||
//replication for this feed is in bad state now. | ||
// this should never happen. | ||
// replication for this feed is in bad state now. | ||
console.log('could not retrive msg:', err) | ||
@@ -84,15 +82,16 @@ } | ||
update: function () { | ||
//retrive next messages. | ||
//TODO: respond to back pressure from streams to each peer. | ||
//if a given stream is paused, don't retrive more msgs | ||
//for that peer/stream. | ||
for (var peer in self.state.peers) { | ||
var state = self.state.peers[peer] | ||
// retrive next messages. | ||
// TODO: respond to back pressure from streams to each peer. | ||
// if a given stream is paused, don't retrive more msgs | ||
// for that peer/stream. | ||
for (const peer in self.state.peers) { | ||
const state = self.state.peers[peer] | ||
while (state.retrive.length) { | ||
var id = state.retrive.shift() | ||
if (state.replicating[id]) | ||
const id = state.retrive.shift() | ||
if (state.replicating[id]) { | ||
opts.getAt({ | ||
id, | ||
sequence: state.replicating[id].sent+1 | ||
sequence: state.replicating[id].sent + 1 | ||
}, self._retrive) | ||
} | ||
} | ||
@@ -102,3 +101,3 @@ } | ||
if (self.state.receive.length) { | ||
var ev = self.state.receive.shift() | ||
const ev = self.state.receive.shift() | ||
opts.append(ev.value, function (err) { | ||
@@ -112,9 +111,8 @@ if (err) { | ||
for (var k in self.streams) | ||
self.streams[k].resume() | ||
}, | ||
for (const k in self.streams) { self.streams[k].resume() } | ||
} | ||
} | ||
var int = setInterval(() => { | ||
self.state = events.timeout(self.state, {ts: timestamp()}) | ||
const int = setInterval(() => { | ||
self.state = events.timeout(self.state, { ts: timestamp() }) | ||
self.update() | ||
@@ -121,0 +119,0 @@ }, state.timeout) |
{ | ||
"name": "epidemic-broadcast-trees", | ||
"description": "bandwidth efficient broadcast gossip", | ||
"version": "9.0.3", | ||
"version": "9.0.4", | ||
"homepage": "https://github.com/dominictarr/epidemic-broadcast-trees", | ||
@@ -10,2 +10,6 @@ "repository": { | ||
}, | ||
"scripts": { | ||
"test": "tape test/*.js | tap-arc", | ||
"lint": "standard --fix" | ||
}, | ||
"dependencies": { | ||
@@ -15,11 +19,10 @@ "push-stream": "^11.0.0" | ||
"devDependencies": { | ||
"bipf": "^1.3.0", | ||
"rng": "^0.2.2", | ||
"bipf": "^1.3.0", | ||
"standard": "^17.0.0", | ||
"tap-arc": "^0.3.5", | ||
"tape": "^4.6.3" | ||
}, | ||
"scripts": { | ||
"test": "set -e; for t in test/*.js; do node $t; done" | ||
}, | ||
"author": "'Dominic Tarr' <dominic.tarr@gmail.com> (http://dominictarr.com)", | ||
"license": "MIT" | ||
} |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable camelcase */ | ||
/* | ||
@@ -11,9 +12,9 @@ better progress algorithm: | ||
module.exports = function (state) { | ||
var prog = { start: 0, current: 0, target: 0 } | ||
for (var peer_id in state.peers) { | ||
var peer = state.peers[peer_id] | ||
const prog = { start: 0, current: 0, target: 0 } | ||
for (const peer_id in state.peers) { | ||
const peer = state.peers[peer_id] | ||
for (var feed_id in peer.replicating) { | ||
var rep = peer.replicating[feed_id] | ||
//progress for sending initial note | ||
for (const feed_id in peer.replicating) { | ||
const rep = peer.replicating[feed_id] | ||
// progress for sending initial note | ||
prog.target++ | ||
@@ -25,4 +26,4 @@ if (rep.sent != null) prog.current++ | ||
var seq = peer.clock[feed_id] | ||
var lseq = state.clock[feed_id] || 0 | ||
const seq = peer.clock[feed_id] | ||
const lseq = state.clock[feed_id] || 0 | ||
@@ -29,0 +30,0 @@ if (rep.rx && rep.requested != null && rep.requested > -1 && lseq < seq) { |
@@ -9,3 +9,3 @@ const v3 = require('./v3') | ||
function EBTStream (peer, remote, version, client, isMsg, onClose) { | ||
this.paused = true //start out paused | ||
this.paused = true // start out paused | ||
this.remote = remote | ||
@@ -17,3 +17,3 @@ this.peer = peer | ||
ts: timestamp(), | ||
client: client | ||
client | ||
}) | ||
@@ -39,9 +39,6 @@ this.ended = false | ||
if (this.peer.logging) { | ||
if (Buffer.isBuffer(data)) | ||
console.log("EBT:recv binary (" + this.peer.id + ")", "0x" + data.toString('hex')) | ||
else | ||
console.log("EBT:recv json (" + this.peer.id + ")", JSON.stringify(data, null, 2)) | ||
if (Buffer.isBuffer(data)) { console.log('EBT:recv binary (' + this.peer.id + ')', '0x' + data.toString('hex')) } else { console.log('EBT:recv json (' + this.peer.id + ')', JSON.stringify(data, null, 2)) } | ||
} | ||
if (this.ended) throw new Error('write after ebt stream ended:'+this.remote) | ||
if (this.ended) throw new Error('write after ebt stream ended:' + this.remote) | ||
@@ -67,3 +64,3 @@ if (this.isMsg(data)) { | ||
this.ended = true | ||
//check if we have already ended | ||
// check if we have already ended | ||
if (!this.peer.state.peers[this.remote]) return | ||
@@ -73,3 +70,3 @@ | ||
var peerState = this.peer.state.peers[this.remote] | ||
const peerState = this.peer.state.peers[this.remote] | ||
this.peer.state = events.disconnect(this.peer.state, { | ||
@@ -80,3 +77,3 @@ id: this.remote, | ||
if (this._onClose) this._onClose(peerState) | ||
//remove from the peer... | ||
// remove from the peer... | ||
delete this.peer.streams[this.remote] | ||
@@ -88,11 +85,10 @@ if (this.source && !this.source.ended) this.source.abort(err) | ||
EBTStream.prototype.canSend = function () { | ||
var state = this.peer.state.peers[this.remote] | ||
const state = this.peer.state.peers[this.remote] | ||
return ( | ||
this.sink && | ||
!this.sink.paused && | ||
!this.ended && ( | ||
//missing state means this peer was blocked, | ||
//end immediately. | ||
state.blocked || state.msgs.length || state.notes | ||
) | ||
!this.sink.paused && | ||
!this.ended && | ||
// missing state means this peer was blocked, | ||
// end immediately. | ||
(state.blocked || state.msgs.length || state.notes) | ||
) | ||
@@ -104,3 +100,3 @@ } | ||
var state = this.peer.state.peers[this.remote] | ||
const state = this.peer.state.peers[this.remote] | ||
while (this.canSend()) { | ||
@@ -111,14 +107,15 @@ if (state.blocked) { | ||
if (this.peer.logging) { | ||
if (Buffer.isBuffer(state.msgs[0])) | ||
console.log("EBT:send binary (" + this.peer.id + ")", "0x" + state.msgs[0].toString('hex')) | ||
else | ||
console.log("EBT:send json (" + this.peer.id + ")", JSON.stringify(state.msgs[0], null, 2)) | ||
if (Buffer.isBuffer(state.msgs[0])) { | ||
console.log('EBT:send binary (' + this.peer.id + ')', '0x' + state.msgs[0].toString('hex')) | ||
} else { | ||
console.log('EBT:send json (' + this.peer.id + ')', JSON.stringify(state.msgs[0], null, 2)) | ||
} | ||
} | ||
this.sink.write(state.msgs.shift()) | ||
} else { | ||
var notes = state.notes | ||
const notes = state.notes | ||
state.notes = null | ||
if (this.peer.logging) { | ||
const formattedNotes = {} | ||
for (let feed in notes) { | ||
for (const feed in notes) { | ||
const seq = notes[feed] | ||
@@ -131,3 +128,3 @@ formattedNotes[feed] = { | ||
} | ||
console.log("EBT:send notes (" + this.peer.id + ")", formattedNotes) | ||
console.log('EBT:send notes (' + this.peer.id + ')', formattedNotes) | ||
} | ||
@@ -134,0 +131,0 @@ this.sink.write(notes) |
@@ -1,8 +0,8 @@ | ||
var createSimulator = require('./simulator') | ||
var bipf = require("bipf") | ||
var events = require('../events')(require('../v3')) | ||
const createSimulator = require('./simulator') | ||
const bipf = require('bipf') | ||
const events = require('../events')(require('../v3')) | ||
function encode(data) { | ||
var len = bipf.encodingLength(data) | ||
var b = Buffer.alloc(len) | ||
function encode (data) { | ||
const len = bipf.encodingLength(data) | ||
const b = Buffer.alloc(len) | ||
bipf.encode(data, b, 0) | ||
@@ -12,4 +12,4 @@ return b | ||
function getMsgAuthor(msg) { | ||
var p = 0 // note you pass in p! | ||
function getMsgAuthor (msg) { | ||
let p = 0 // note you pass in p! | ||
p = bipf.seekKey(msg, p, Buffer.from('author')) | ||
@@ -19,4 +19,4 @@ return bipf.decode(msg, p) | ||
function getMsgSequence(msg) { | ||
var p = 0 // note you pass in p! | ||
function getMsgSequence (msg) { | ||
let p = 0 // note you pass in p! | ||
p = bipf.seekKey(msg, p, Buffer.from('sequence')) | ||
@@ -29,14 +29,14 @@ return bipf.decode(msg, p) | ||
var test = require('tape') | ||
const test = require('tape') | ||
test('binary test', function (t) { | ||
var tick = createSimulator(0, true, events) | ||
const tick = createSimulator(0, true, events) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
alice.append = function(msg) { | ||
var ary = alice.store[getMsgAuthor(msg)] = alice.store[getMsgAuthor(msg)] || [] | ||
if(getMsgSequence(msg) === ary.length + 1) { | ||
alice.append = function (msg) { | ||
const ary = alice.store[getMsgAuthor(msg)] = alice.store[getMsgAuthor(msg)] || [] | ||
if (getMsgSequence(msg) === ary.length + 1) { | ||
ary.push(msg) | ||
@@ -46,5 +46,5 @@ alice.state = events.append(alice.state, msg) | ||
} | ||
bob.append = function(msg) { | ||
var ary = bob.store[getMsgAuthor(msg)] = bob.store[getMsgAuthor(msg)] || [] | ||
if(getMsgSequence(msg) === ary.length + 1) { | ||
bob.append = function (msg) { | ||
const ary = bob.store[getMsgAuthor(msg)] = bob.store[getMsgAuthor(msg)] || [] | ||
if (getMsgSequence(msg) === ary.length + 1) { | ||
ary.push(msg) | ||
@@ -54,9 +54,9 @@ bob.state = events.append(bob.state, msg) | ||
} | ||
alice.init({}) | ||
bob.init({}) | ||
alice.append(encode({author: 'alice', sequence: 1, text: "test"})) | ||
alice.append(encode({author: 'alice', sequence: 2, text: "test2"})) | ||
alice.append(encode({author: 'alice', sequence: 3, text: "test3"})) | ||
alice.append(encode({ author: 'alice', sequence: 1, text: 'test' })) | ||
alice.append(encode({ author: 'alice', sequence: 2, text: 'test2' })) | ||
alice.append(encode({ author: 'alice', sequence: 3, text: 'test3' })) | ||
@@ -68,3 +68,3 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -71,0 +71,0 @@ t.deepEqual(bob.store, alice.store) |
@@ -1,35 +0,34 @@ | ||
var test = require('tape') | ||
const test = require('tape') | ||
var events = require('../events')(require('./options')) | ||
const events = require('../events')(require('./options')) | ||
var note = events.note | ||
const note = events.note | ||
test('blocks', function (t) { | ||
let state = events.initialize('alice') | ||
var state = events.initialize('alice') | ||
state.clock = { alice: 3, charles: 3, dawn: 3 } | ||
state.clock = {alice: 3, charles: 3, dawn: 3} | ||
state = events.follow(state, { id: 'alice', value: true }) | ||
state = events.follow(state, { id: 'charles', value: true }) | ||
state = events.follow(state, { id: 'dawn', value: true }) | ||
state = events.follow(state, {id: 'alice', value: true}) | ||
state = events.follow(state, {id: 'charles', value: true}) | ||
state = events.follow(state, {id: 'dawn', value: true}) | ||
state = events.block(state, {id: 'alice', target: 'bob', value: true}) | ||
t.deepEqual(state.blocks, {alice: {bob:true}}) | ||
state = events.block(state, {id: 'alice', target: 'bob', value: false}) | ||
state = events.block(state, { id: 'alice', target: 'bob', value: true }) | ||
t.deepEqual(state.blocks, { alice: { bob: true } }) | ||
state = events.block(state, { id: 'alice', target: 'bob', value: false }) | ||
t.deepEqual(state.blocks, {}) | ||
//do not allow connection to someone we block. | ||
state = events.block(state, {id: 'alice', target: 'bob', value: true}) | ||
state = events.block(state, {id: 'charles', target: 'dawn', value: true}) | ||
// do not allow connection to someone we block. | ||
state = events.block(state, { id: 'alice', target: 'bob', value: true }) | ||
state = events.block(state, { id: 'charles', target: 'dawn', value: true }) | ||
console.log(state) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
t.equal(state.peers.bob.blocked, true) | ||
state = events.connect(state, {id: 'dawn', client: false}) | ||
state = events.connect(state, { id: 'dawn', client: false }) | ||
state = events.peerClock(state, {id: 'dawn', value:{}}) | ||
state = events.peerClock(state, { id: 'dawn', value: {} }) | ||
//charles has blocked dawn, so do not give dawn charle's messages | ||
// charles has blocked dawn, so do not give dawn charle's messages | ||
t.deepEqual(state.peers.dawn.notes, { | ||
@@ -39,8 +38,11 @@ alice: note(3, true), dawn: note(3, true) | ||
//but dawn asks for charles anyway. | ||
state = events.notes(state, {id: 'dawn', value: { | ||
alice: note(2, true), dawn: note(2, true), charles: note(1, true) | ||
}}) | ||
// but dawn asks for charles anyway. | ||
state = events.notes(state, { | ||
id: 'dawn', | ||
value: { | ||
alice: note(2, true), dawn: note(2, true), charles: note(1, true) | ||
} | ||
}) | ||
//charles has blocked dawn, so do not give dawn charles' messages | ||
// charles has blocked dawn, so do not give dawn charles' messages | ||
t.deepEqual(state.peers.dawn.notes, { | ||
@@ -54,10 +56,10 @@ alice: note(3, true), dawn: note(3, true), charles: note(-1, false) | ||
test("don't send retrived message to blocked peer", function (t) { | ||
var state = events.initialize('alice') | ||
state.clock = {alice: 3, charles: 2} | ||
// state.block = {charles: {bob: true}} //charles blocks bob | ||
state = events.block(state, {id: 'charles', target: 'bob', value: true}) | ||
state = events.connect(state, {id: 'bob', ts: 1, client: false}) | ||
let state = events.initialize('alice') | ||
state.clock = { alice: 3, charles: 2 } | ||
// state.block = {charles: {bob: true}} //charles blocks bob | ||
state = events.block(state, { id: 'charles', target: 'bob', value: true }) | ||
state = events.connect(state, { id: 'bob', ts: 1, client: false }) | ||
console.log(state) | ||
state = events.peerClock(state, {id: 'bob', value: {}}) | ||
state = events.notes(state, {id: 'bob', value: {charles: 1}}) | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
state = events.notes(state, { id: 'bob', value: { charles: 1 } }) | ||
t.equal(state.peers.bob.replicating.charles.tx, false) | ||
@@ -67,3 +69,3 @@ t.equal(state.peers.bob.replicating.charles.sent, -1) | ||
//it's already in a state that the peer should be blocked. | ||
// it's already in a state that the peer should be blocked. | ||
@@ -74,9 +76,9 @@ t.end() | ||
test("don't send retrived message to blocked peer", function (t) { | ||
var state = events.initialize('alice') | ||
state.clock = {alice: 3, charles: 2} | ||
state = events.connect(state, {id: 'bob', ts: 1, client: false}) | ||
state = events.peerClock(state, {id: 'bob', value: {}}) | ||
let state = events.initialize('alice') | ||
state.clock = { alice: 3, charles: 2 } | ||
state = events.connect(state, { id: 'bob', ts: 1, client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
state = events.notes(state, {id: 'bob', value: {charles: 1}}) | ||
state = events.block(state, {id: 'charles', target: 'bob', value: true}) | ||
state = events.notes(state, { id: 'bob', value: { charles: 1 } }) | ||
state = events.block(state, { id: 'charles', target: 'bob', value: true }) | ||
@@ -89,22 +91,19 @@ t.equal(state.peers.bob.replicating.charles.tx, false) | ||
test("blocking false on a connected peer does nothing", function (t) { | ||
var state = events.initialize('alice') | ||
state.clock = {alice: 3, charles: 2} | ||
state = events.connect(state, {id: 'charles', ts: 1, client: false}) | ||
//state = events.peerClock(state, {id: 'charles', value: { charles: 2 }}) | ||
state = events.peerClock(state, {id: 'charles', value: {'alice': 0, 'charles': 0}}) | ||
test('blocking false on a connected peer does nothing', function (t) { | ||
let state = events.initialize('alice') | ||
state.clock = { alice: 3, charles: 2 } | ||
state = events.connect(state, { id: 'charles', ts: 1, client: false }) | ||
// state = events.peerClock(state, {id: 'charles', value: { charles: 2 }}) | ||
state = events.peerClock(state, { id: 'charles', value: { alice: 0, charles: 0 } }) | ||
state = events.follow(state, {id: 'alice', value: true}) | ||
state = events.follow(state, {id: 'charles', value: true}) | ||
state = events.follow(state, { id: 'alice', value: true }) | ||
state = events.follow(state, { id: 'charles', value: true }) | ||
state = events.notes(state, {id: 'charles', value: {charles: 2}}) | ||
const existingNote = state.peers['charles'].notes['alice'] | ||
state = events.notes(state, { id: 'charles', value: { charles: 2 } }) | ||
const existingNote = state.peers.charles.notes.alice | ||
// this should not change anything | ||
state = events.block(state, {id: 'alice', target: 'charles', value: false}) | ||
t.equal(state.peers['charles'].notes['alice'], existingNote) | ||
state = events.block(state, { id: 'alice', target: 'charles', value: false }) | ||
t.equal(state.peers.charles.notes.alice, existingNote) | ||
t.end() | ||
}) | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var charles = network['charles'] = tick.createPeer('charles') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const charles = network.charles = tick.createPeer('charles') | ||
@@ -21,5 +21,5 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
@@ -33,5 +33,5 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
@@ -42,3 +42,3 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
function isComplete (peer) { | ||
var prog = progress(peer.state) | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target) | ||
@@ -55,12 +55,5 @@ } | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) | ||
createTest(i, false) | ||
else | ||
createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { | ||
for (let i = 0; i < 100; i++) { createTest(i, false) } | ||
} else { createTest(+seed, true) } |
@@ -1,16 +0,16 @@ | ||
var test = require('tape') | ||
const test = require('tape') | ||
var events = require('../events')(require('./options')) | ||
const events = require('../events')(require('./options')) | ||
var note = events.note | ||
const note = events.note | ||
test('client does not send {} until received it', function (t) { | ||
var state = events.initialize('alice') | ||
state = events.connect(state, {id: 'bob', client: true}) | ||
state.follows = {alice: true, bob: true} | ||
state.clock = {alice:1, bob: 1} | ||
state = events.peerClock(state, {id: 'bob', value: {}}) | ||
let state = events.initialize('alice') | ||
state = events.connect(state, { id: 'bob', client: true }) | ||
state.follows = { alice: true, bob: true } | ||
state.clock = { alice: 1, bob: 1 } | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
t.equal(state.peers.bob.notes, null) | ||
state = events.notes(state, {id: 'bob', value: {}}) | ||
t.deepEqual(state.peers.bob.notes, {alice: note(1, true), bob: note(1, true)}) | ||
state = events.notes(state, { id: 'bob', value: {} }) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(1, true), bob: note(1, true) }) | ||
@@ -23,9 +23,9 @@ state.peers.bob.notes = null | ||
test('client does not send {} until received it, but will send empty note, one time', function (t) { | ||
var state = events.initialize('alice') | ||
state = events.connect(state, {id: 'bob', client: true}) | ||
state = events.peerClock(state, {id: 'bob', value: {}}) | ||
let state = events.initialize('alice') | ||
state = events.connect(state, { id: 'bob', client: true }) | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
t.equal(state.peers.bob.notes, null) | ||
state = events.notes(state, {id: 'bob', value: {}}) | ||
state = events.notes(state, { id: 'bob', value: {} }) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
t.end() | ||
}) |
var createSimulator = require('./simulator') | ||
var _events = require('../events')(require('./options')) | ||
var test = require('tape') | ||
var progress = require('../progress') | ||
var events = {} | ||
for(var k in _events) (function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if(state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
const createSimulator = require('./simulator') | ||
const _events = require('../events')(require('./options')) | ||
const test = require('tape') | ||
const progress = require('../progress') | ||
const events = {} | ||
for (const k in _events) { | ||
(function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if (state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
} | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var carl = network['carl'] = tick.createPeer('carl') | ||
var dawn = network['dawn'] = tick.createPeer('dawn') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const carl = network.carl = tick.createPeer('carl') | ||
const dawn = network.dawn = tick.createPeer('dawn') | ||
@@ -31,6 +32,6 @@ alice.state.timeout = bob.state.timeout = dawn.state.timeout = 2 | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
@@ -53,11 +54,10 @@ alice.follow('alice') | ||
tick.run(network) | ||
// carl.state.stalled = true | ||
// carl.state.stalled = true | ||
// alice.disconnect(carl) | ||
// alice.disconnect(carl) | ||
bob.disconnect(carl) | ||
// dawn.disconnect(carl) | ||
// dawn.disconnect(carl) | ||
alice.append({author: 'alice', sequence: 4, content: {}}) | ||
alice.append({ author: 'alice', sequence: 4, content: {} }) | ||
tick.run(network) | ||
@@ -69,4 +69,4 @@ | ||
function isComplete (peer, name) { | ||
var prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name +' is complete') | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name + ' is complete') | ||
} | ||
@@ -82,5 +82,3 @@ | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { for (let i = 0; i < 100; i++) createTest(i) } else createTest(+seed, true) |
@@ -1,67 +0,65 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function validate (queue, msg) { | ||
var sum = queue.reduce(function (a, b) { | ||
const sum = queue.reduce(function (a, b) { | ||
return a + b.content.value | ||
}, 0) | ||
if(sum != msg.content.sum) throw new Error('invalid sum:'+msg.content.sum+', expected:'+sum) | ||
if (sum !== msg.content.sum) throw new Error('invalid sum:' + msg.content.sum + ', expected:' + sum) | ||
} | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice', validate) | ||
var bob = network['bob'] = tick.createPeer('bob', validate) | ||
// var charles = network['charles'] = tick.createPeer('charles', validate) | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice', validate) | ||
const bob = network.bob = tick.createPeer('bob', validate) | ||
// var charles = network['charles'] = tick.createPeer('charles', validate) | ||
alice.init({}) | ||
bob.init({}) | ||
// charles.init({}) | ||
// charles.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {sum: 0, value: 1}}) | ||
alice.append({author: 'alice', sequence: 2, content: {sum: 1, value: 2}}) | ||
alice.append({author: 'alice', sequence: 3, content: {sum: 3, value: 3}}) | ||
alice.append({author: 'alice', sequence: 4, content: {sum: 6, value: 4}}) | ||
alice.append({author: 'alice', sequence: 5, content: {sum: 10, value: 5}}) | ||
alice.append({author: 'alice', sequence: 6, content: {sum: 15, value: 6}}) | ||
alice.append({author: 'alice', sequence: 7, content: {sum: 21, value: 7}}) | ||
alice.append({ author: 'alice', sequence: 1, content: { sum: 0, value: 1 } }) | ||
alice.append({ author: 'alice', sequence: 2, content: { sum: 1, value: 2 } }) | ||
alice.append({ author: 'alice', sequence: 3, content: { sum: 3, value: 3 } }) | ||
alice.append({ author: 'alice', sequence: 4, content: { sum: 6, value: 4 } }) | ||
alice.append({ author: 'alice', sequence: 5, content: { sum: 10, value: 5 } }) | ||
alice.append({ author: 'alice', sequence: 6, content: { sum: 15, value: 6 } }) | ||
alice.append({ author: 'alice', sequence: 7, content: { sum: 21, value: 7 } }) | ||
bob.append({author: 'alice', sequence: 1, content: {sum: 0, value: 1}}) | ||
bob.append({author: 'alice', sequence: 2, content: {sum: 1, value: 3}}) | ||
// bob.append({author: 'alice', sequence: 3, content: {sum: 4, value: 1}}) | ||
bob.append({ author: 'alice', sequence: 1, content: { sum: 0, value: 1 } }) | ||
bob.append({ author: 'alice', sequence: 2, content: { sum: 1, value: 3 } }) | ||
// bob.append({author: 'alice', sequence: 3, content: {sum: 4, value: 1}}) | ||
alice.follow('alice') | ||
bob.follow('alice') | ||
// charles.follow('alice') | ||
// charles.follow('alice') | ||
alice.connect(bob) | ||
// alice.connect(charles) | ||
// alice.connect(charles) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(bob.state.blocks, {alice: {alice: true}}) | ||
t.deepEqual(bob.state.blocks, { alice: { alice: true } }) | ||
var prog = progress(bob.state) | ||
const prog = progress(bob.state) | ||
t.equal(prog.current, prog.target) | ||
// t.equal(bob.state.peers.alice.replicating.alice.tx, false, 'bob is not transmitting forked alice with alice') | ||
// t.equal(bob.state.peers.alice.replicating.alice.tx, false, 'bob is not transmitting forked alice with alice') | ||
t.equal(bob.state.peers.alice.replicating.alice.rx, false, 'bob is not receiving forked alice with alice') | ||
if(log) | ||
if (log) { | ||
console.log( | ||
tick.output.map(function (e) { | ||
if(e.msg) | ||
return e.from+'>'+e.to+':'+e.value.sequence | ||
else | ||
return e.from+'>'+e.to+':'+JSON.stringify(e.value) | ||
if (e.msg) { return e.from + '>' + e.to + ':' + e.value.sequence } else { return e.from + '>' + e.to + ':' + JSON.stringify(e.value) } | ||
}).join('\n') | ||
) | ||
} | ||
@@ -72,5 +70,4 @@ t.end() | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) for(var i = 0; i < 100; i++) createTest(i) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) for (let i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
@@ -1,15 +0,13 @@ | ||
var test = require('tape') | ||
const test = require('tape') | ||
function isObject(o) { | ||
return o && 'object' === typeof o | ||
function isObject (o) { | ||
return o && typeof o === 'object' | ||
} | ||
function isFunction (f) { | ||
return 'function' === typeof f | ||
return typeof f === 'function' | ||
} | ||
function is (t, actual, expected, path) { | ||
if(isFunction(expected)) | ||
expected.call(actual) | ||
else t.equal(expected, actual, 'expected '+path.join('.')+' to equal:'+actual) | ||
if (isFunction(expected)) { expected.call(actual) } else t.equal(expected, actual, 'expected ' + path.join('.') + ' to equal:' + actual) | ||
} | ||
@@ -20,138 +18,135 @@ | ||
if(!(isObject(actual))) return is(t, actual, expected, path) | ||
if (!(isObject(actual))) return is(t, actual, expected, path) | ||
if(!isObject(expected)) | ||
return t.fail('expected object at path:'+path.join('.')) | ||
if (!isObject(expected)) { return t.fail('expected object at path:' + path.join('.')) } | ||
for(var k in expected) | ||
has(t, actual[k], expected[k], path.concat(k)) | ||
for (const k in expected) { has(t, actual[k], expected[k], path.concat(k)) } | ||
} | ||
module.exports = function (events) { | ||
const note = events.note | ||
var note = events.note | ||
test('initialize, connect to new peer', function (t) { | ||
let state = events.initialize() | ||
test('initialize, connect to new peer', function (t) { | ||
state = events.connect(state, { id: 'alice', client: false }) | ||
state = events.peerClock(state, { id: 'alice', value: {} }) | ||
var state = events.initialize() | ||
has(t, state, { | ||
peers: { | ||
alice: { clock: {}, msgs: [], notes: {}, replicating: {} } | ||
} | ||
}) | ||
state = events.connect(state, {id: 'alice', client: false}) | ||
state = events.peerClock(state, {id: 'alice', value: {}}) | ||
state = events.clock(state, {}) | ||
has(t, state, { | ||
peers: { | ||
alice: { clock: {}, msgs: [], notes: {}, replicating: {} }, | ||
} | ||
}) | ||
state = events.follow(state, { id: 'alice', value: true }) | ||
state = events.clock(state, {}) | ||
t.deepEqual(state.follows, { alice: true }) | ||
console.log(state.peers.alice) | ||
state = events.follow(state, {id: 'alice', value: true}) | ||
has(t, state.peers.alice, { | ||
clock: {}, | ||
notes: { alice: note(0, true) }, | ||
replicating: { alice: { rx: true } } | ||
}, ['state', 'peers', 'alice']) | ||
t.deepEqual(state.follows, {alice: true}) | ||
console.log(state.peers.alice) | ||
// lets say we send the note | ||
has(t, state.peers.alice, { | ||
clock: {}, | ||
notes: { alice: note(0, true) }, | ||
replicating: {alice: {rx: true}} | ||
}, ['state', 'peers', 'alice']) | ||
//lets say we send the note | ||
state = events.notes(state, {id: 'alice', value: {alice: note(2, true)}}) | ||
has(t, state, { | ||
clock: {}, | ||
follows: {alice: true}, | ||
peers: { | ||
alice: { | ||
clock: {alice: 2}, | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true | ||
state = events.notes(state, { id: 'alice', value: { alice: note(2, true) } }) | ||
has(t, state, { | ||
clock: {}, | ||
follows: { alice: true }, | ||
peers: { | ||
alice: { | ||
clock: { alice: 2 }, | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
}) | ||
var msg = {author: 'alice', sequence: 1, content: {}} | ||
state = events.receive(state, {id: 'alice', value:msg}) | ||
const msg = { author: 'alice', sequence: 1, content: {} } | ||
state = events.receive(state, { id: 'alice', value: msg }) | ||
has(t, state, { | ||
peers: { | ||
alice: { | ||
clock: {alice: 2}, | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true | ||
has(t, state, { | ||
peers: { | ||
alice: { | ||
clock: { alice: 2 }, | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
receive: [{id: 'alice', value: msg}], | ||
}) | ||
}, | ||
receive: [{ id: 'alice', value: msg }] | ||
}) | ||
var ev = state.receive.shift() | ||
const ev = state.receive.shift() | ||
state = events.append(state, ev.value) | ||
state = events.append(state, ev.value) | ||
has(t, state, { | ||
clock: {alice: 1} | ||
}) | ||
has(t, state, { | ||
clock: { alice: 1 } | ||
}) | ||
var msg2 = {author: 'alice', sequence: 2, content: {}} | ||
state = events.receive(state, {id: 'alice', value:msg2}) | ||
state = events.append(state, state.receive.shift().value) | ||
const msg2 = { author: 'alice', sequence: 2, content: {} } | ||
state = events.receive(state, { id: 'alice', value: msg2 }) | ||
state = events.append(state, state.receive.shift().value) | ||
has(t, state, { | ||
clock: {alice: 2} | ||
}) | ||
has(t, state, { | ||
clock: { alice: 2 } | ||
}) | ||
var msg3 = {author: 'alice', sequence: 3, content: {}} | ||
state = events.receive(state, {id: 'alice', value:msg3}) | ||
state = events.append(state, state.receive.shift().value) | ||
const msg3 = { author: 'alice', sequence: 3, content: {} } | ||
state = events.receive(state, { id: 'alice', value: msg3 }) | ||
state = events.append(state, state.receive.shift().value) | ||
has(t, state, { | ||
clock: {alice: 3} | ||
has(t, state, { | ||
clock: { alice: 3 } | ||
}) | ||
t.end() | ||
}) | ||
t.end() | ||
test('initialize, but append before peerClock loads', function (t) { | ||
let state = events.initialize() | ||
state = events.clock(state, { alice: 1, bob: 2 }) | ||
}) | ||
state = events.connect(state, { id: 'alice', client: false }) | ||
state = events.append(state, { author: 'bob', sequence: 3, content: {} }) | ||
test('initialize, but append before peerClock loads', function (t) { | ||
state = events.peerClock(state, { id: 'alice', value: {} }) | ||
// TODO > does this test anything? | ||
t.end() | ||
}) | ||
var state = events.initialize() | ||
state = events.clock(state, {alice: 1, bob: 2}) | ||
state = events.connect(state, {id: 'alice', client: false}) | ||
state = events.append(state, {author: 'bob', sequence: 3, content: {}}) | ||
state = events.peerClock(state, {id: 'alice', value: {}}) | ||
t.end() | ||
}) | ||
test('connect to two peers, append message one send, one note', function (t) { | ||
var state = { | ||
clock: { alice: 1 }, | ||
follows: { alice: true }, | ||
blocks: {}, | ||
peers: { | ||
bob: { | ||
clock: { alice: 1 }, | ||
msgs: [], retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true, sent: 1, retrive: false | ||
test('connect to two peers, append message one send, one note', function (t) { | ||
let state = { | ||
clock: { alice: 1 }, | ||
follows: { alice: true }, | ||
blocks: {}, | ||
peers: { | ||
bob: { | ||
clock: { alice: 1 }, | ||
msgs: [], | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true, sent: 1, retrive: false | ||
} | ||
} | ||
} | ||
}, | ||
charles: { | ||
clock: {alice: 1}, | ||
msgs: [], retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: false, tx: false, sent: 1, retrive: false | ||
}, | ||
charles: { | ||
clock: { alice: 1 }, | ||
msgs: [], | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: false, tx: false, sent: 1, retrive: false | ||
} | ||
} | ||
@@ -161,151 +156,153 @@ } | ||
} | ||
} | ||
var msg = {author: 'alice', sequence: 2, content: {}} | ||
state = events.append(state, msg) | ||
const msg = { author: 'alice', sequence: 2, content: {} } | ||
state = events.append(state, msg) | ||
has(t, state, { | ||
clock: { alice: 2 }, | ||
peers: { | ||
bob: { | ||
clock: { alice: 1 }, | ||
msgs: [msg], | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true, sent: 2, retrive: false | ||
has(t, state, { | ||
clock: { alice: 2 }, | ||
peers: { | ||
bob: { | ||
clock: { alice: 1 }, | ||
msgs: [msg], | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: true, tx: true, sent: 2, retrive: false | ||
} | ||
} | ||
} | ||
}, | ||
charles: { | ||
clock: { alice: 1 }, | ||
notes: { alice: note(2, false) }, | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: false, tx: false, sent: 1 | ||
}, | ||
charles: { | ||
clock: { alice: 1 }, | ||
notes: { alice: note(2, false) }, | ||
retrive: [], | ||
replicating: { | ||
alice: { | ||
rx: false, tx: false, sent: 1 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
t.end() | ||
}) | ||
t.end() | ||
test('replicate a hops=2 peer that my hops=1 friend still doesnt have', function (t) { | ||
let state = events.initialize() | ||
state = events.clock(state, {}) | ||
}) | ||
state = events.connect(state, { id: 'alice', client: false }) | ||
state = events.peerClock(state, { id: 'alice', value: { alice: 0, bob: 0 } }) | ||
test('replicate a hops=2 peer that my hops=1 friend still doesnt have', function (t) { | ||
var state = events.initialize() | ||
state = events.clock(state, {}) | ||
state = events.follow(state, { id: 'alice', value: true }) | ||
state = events.follow(state, { id: 'bob', value: true }) | ||
state = events.connect(state, {id: 'alice', client: false}) | ||
state = events.peerClock(state, {id: 'alice', value: {'alice': 0, 'bob': 0}}) | ||
t.ok(state.peers.alice.replicating.bob) | ||
state = events.follow(state, {id: 'alice', value: true}) | ||
state = events.follow(state, {id: 'bob', value: true}) | ||
t.end() | ||
}) | ||
t.ok(state.peers['alice'].replicating['bob']) | ||
test('replicate a hops=2 peer that my hops=1 friend still doesnt have (2)', function (t) { | ||
let state = events.initialize() | ||
state = events.clock(state, {}) | ||
t.end() | ||
}) | ||
state = events.follow(state, { id: 'alice', value: true }) | ||
state = events.follow(state, { id: 'bob', value: true }) | ||
test('replicate a hops=2 peer that my hops=1 friend still doesnt have (2)', function (t) { | ||
var state = events.initialize() | ||
state = events.clock(state, {}) | ||
state = events.connect(state, { id: 'alice', client: false }) | ||
state = events.peerClock(state, { id: 'alice', value: { alice: 0, bob: 0 } }) | ||
state = events.follow(state, {id: 'alice', value: true}) | ||
state = events.follow(state, {id: 'bob', value: true}) | ||
t.ok(state.peers.alice.replicating.bob) | ||
state = events.connect(state, {id: 'alice', client: false}) | ||
state = events.peerClock(state, {id: 'alice', value: {'alice': 0, 'bob': 0}}) | ||
t.end() | ||
}) | ||
t.ok(state.peers['alice'].replicating['bob']) | ||
test('reply to any clock they send, 1', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2, charles: 3 }, | ||
follows: { alice: true, bob: true, charles: true, darlene: false }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
t.end() | ||
}) | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 3, charles: 1 } }) | ||
t.deepEqual(state.peers.bob.notes, { bob: note(2, true), charles: note(3, true) }) | ||
test('reply to any clock they send, 1', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2, charles: 3 }, | ||
follows: { alice: true, bob: true, charles: true, darlene: false }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
state = events.notes(state, { id: 'bob', value: { alice: note(3, true), darlene: note(4, true) } }) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}}) | ||
t.deepEqual(state.peers.bob.notes, {bob: note(2, true), charles: note(3, true)}) | ||
// notes hasn't been sent, so this is merged with previous | ||
t.deepEqual(state.peers.bob.notes, { alice: note(3, false), bob: note(2, true), charles: note(3, true), darlene: note(-1, true) }) | ||
state = events.notes(state, {id: 'bob', value: {alice: note(3, true), darlene: note(4, true)}}) | ||
t.end() | ||
}) | ||
//notes hasn't been sent, so this is merged with previous | ||
t.deepEqual(state.peers.bob.notes, {alice: note(3, false), bob: note(2, true), charles: note(3, true), darlene: note(-1, true)}) | ||
test('reply to any clock they send, 2', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
t.end() | ||
}) | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 3, charles: 1 } }) | ||
t.deepEqual(state.peers.bob.notes, { bob: note(2, true) }) | ||
test('reply to any clock they send, 2', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: {}, | ||
} | ||
state = events.notes(state, { id: 'bob', value: { alice: note(3, true) } }) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}}) | ||
t.deepEqual(state.peers.bob.notes, {bob: note(2, true)}) | ||
// notes hasn't been sent, so this is merged with previous | ||
t.deepEqual(state.peers.bob.notes, { alice: note(3, false), bob: note(2, true) }) | ||
state = events.notes(state, {id: 'bob', value: {alice: note(3, true)}}) | ||
state = events.follow(state, { id: 'charles', value: true }) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(3, false), bob: note(2, true), charles: note(0, true) }) | ||
//notes hasn't been sent, so this is merged with previous | ||
t.deepEqual(state.peers.bob.notes, {alice: note(3, false), bob: note(2, true)}) | ||
t.end() | ||
}) | ||
state = events.follow(state, {id: 'charles',value: true}) | ||
t.deepEqual(state.peers.bob.notes, {alice: note(3, false), bob: note(2, true), charles: note(0, true)}) | ||
test('append when not in TX mode', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 3, charles: 1 } }) | ||
t.deepEqual(state.peers.bob.notes, { bob: note(2, true) }) | ||
t.end() | ||
}) | ||
state = events.notes(state, { id: 'bob', value: { alice: note(3, false) } }) | ||
let rep = state.peers.bob.replicating.alice | ||
t.equal(rep.tx, false) | ||
t.equal(rep.sent, 3) | ||
test('append when not in TX mode', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: 3, charles: 1}}) | ||
t.deepEqual(state.peers.bob.notes, {bob: note(2, true)}) | ||
console.log(state.peers.bob.replicating) | ||
state = events.notes(state, {id: 'bob', value: {alice: note(3, false)}}) | ||
var rep = state.peers.bob.replicating.alice | ||
t.equal(rep.tx, false) | ||
t.equal(rep.sent, 3) | ||
state = events.append(state, { author: 'alice', sequence: 4, content: {} }) | ||
t.deepEqual(state.peers.bob.notes, { bob: note(2, true), alice: note(4, false) }) | ||
rep = state.peers.bob.replicating.alice | ||
t.equal(rep.tx, false) | ||
t.equal(rep.sent, 3) | ||
console.log(state.peers.bob.replicating) | ||
state = events.notes(state, { id: 'bob', value: { alice: note(3, true) } }) | ||
t.deepEqual(state.peers.bob.retrive, ['alice']) | ||
state = events.append(state, {author: 'alice', sequence: 4, content: {}}) | ||
t.deepEqual(state.peers.bob.notes, {bob: note(2, true), alice: note(4, false)}) | ||
rep = state.peers.bob.replicating.alice | ||
t.equal(rep.tx, false) | ||
t.equal(rep.sent, 3) | ||
t.end() | ||
}) | ||
state = events.notes(state, {id: 'bob', value: {alice: note(3, true)}}) | ||
t.deepEqual(state.peers.bob.retrive, ['alice']) | ||
t.end() | ||
}) | ||
test('note when not in RX mode', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: { | ||
bob: { | ||
clock: {alice: 3, bob: 2}, | ||
retrive: [], | ||
msgs: [], | ||
notes: null, | ||
replicating: { | ||
alice: { | ||
tx:false, rx: false, sent: 3 | ||
test('note when not in RX mode', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: { | ||
bob: { | ||
clock: { alice: 3, bob: 2 }, | ||
retrive: [], | ||
msgs: [], | ||
notes: null, | ||
replicating: { | ||
alice: { | ||
tx: false, rx: false, sent: 3 | ||
} | ||
} | ||
@@ -315,198 +312,197 @@ } | ||
} | ||
} | ||
state = events.notes(state, {id: 'bob', value: {alice: note(5, false)}}) | ||
var rep = state.peers.bob.replicating.alice | ||
// t.equal(rep.tx, true) | ||
t.equal(rep.rx, true) | ||
t.equal(rep.sent, 5) | ||
t.deepEqual(state.peers.bob.notes, {alice: note(3, true)}) | ||
state = events.notes(state, { id: 'bob', value: { alice: note(5, false) } }) | ||
const rep = state.peers.bob.replicating.alice | ||
// t.equal(rep.tx, true) | ||
t.equal(rep.rx, true) | ||
t.equal(rep.sent, 5) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(3, true) }) | ||
console.log(state.peers.bob.replicating) | ||
console.log(state.peers.bob.replicating) | ||
// state = events.append(state, {author: 'alice', sequence: 4, content: {}}) | ||
// t.deepEqual(state.peers.bob.notes, {bob: note(2, true), alice: note(4, false)}) | ||
t.end() | ||
// state = events.append(state, {author: 'alice', sequence: 4, content: {}}) | ||
// t.deepEqual(state.peers.bob.notes, {bob: note(2, true), alice: note(4, false)}) | ||
t.end() | ||
}) | ||
}) | ||
test('note when value is not integer', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
test('note when value is not integer', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{}}) | ||
t.deepEqual(state.peers.bob.clock, {}) | ||
state = events.notes(state, { id: 'bob', value: { alice: true } }) | ||
t.deepEqual(state.peers.bob.clock, {}) | ||
state = events.notes(state, {id: 'bob', value: {alice: true}}) | ||
t.deepEqual(state.peers.bob.clock, { alice: -1 }) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(3, true), bob: note(2, true) }) | ||
t.deepEqual(state.peers.bob.clock, {alice: -1}) | ||
t.deepEqual(state.peers.bob.notes, {alice: note(3,true), bob: note(2, true)}) | ||
t.end() | ||
}) | ||
t.end() | ||
}) | ||
test('test sends empty clock if nothing needed', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
test('test sends empty clock if nothing needed', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 3, bob: 2 } }) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}}) | ||
t.deepEqual(state.peers.bob.clock, { alice: 3, bob: 2 }) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2}) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
// receive empty clock | ||
state = events.notes(state, { id: 'bob', value: {} }) | ||
t.deepEqual(state.peers.bob.replicating, {}) | ||
//receive empty clock | ||
state = events.notes(state, {id: 'bob', value: {}}) | ||
t.deepEqual(state.peers.bob.replicating, {}) | ||
t.end() | ||
}) | ||
t.end() | ||
}) | ||
test('connects in sync then another message', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 3, bob: 2 } }) | ||
test('connects in sync then another message', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: { alice: true, bob: true}, blocks: {}, | ||
peers: {} | ||
} | ||
t.deepEqual(state.peers.bob.clock, { alice: 3, bob: 2 }) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: 3, bob: 2}}) | ||
// receive empty clock | ||
state = events.notes(state, { id: 'bob', value: {} }) | ||
t.deepEqual(state.peers.bob.replicating, {}) | ||
t.deepEqual(state.peers.bob.clock, {alice: 3, bob: 2}) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
state = events.append(state, { author: 'alice', sequence: 4, content: {} }) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(4, false) }) | ||
//receive empty clock | ||
state = events.notes(state, {id: 'bob', value: {}}) | ||
t.deepEqual(state.peers.bob.replicating, {}) | ||
t.end() | ||
}) | ||
state = events.append(state, {author: 'alice', sequence: 4, content: {}}) | ||
t.deepEqual(state.peers.bob.notes, {alice: note(4, false)}) | ||
test('unfollow', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: {}, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
t.end() | ||
}) | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: {} }) | ||
test('unfollow', function (t) { | ||
t.deepEqual(state.peers.bob.clock, {}) | ||
t.deepEqual(state.peers.bob.notes, { }) | ||
state = events.notes(state, { id: 'bob', value: { alice: note(3, true), bob: note(2, true) } }) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(-1, true), bob: note(-1, true) }) | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: {}, blocks: {}, | ||
peers: {} | ||
} | ||
state.peers.bob.notes = null | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{}}) | ||
state = events.follow(state, { id: 'alice', value: false }) | ||
t.deepEqual(state.peers.bob.clock, {}) | ||
t.deepEqual(state.peers.bob.notes, { }) | ||
state = events.notes(state, {id: 'bob', value:{alice: note(3, true), bob: note(2, true)}}) | ||
t.deepEqual(state.peers.bob.notes, { alice: note(-1, true), bob: note(-1, true)}) | ||
t.deepEqual(state.peers.bob.notes, null) | ||
state.peers.bob.notes = null | ||
state = events.notes(state, { id: 'bob', value: { charles: note(-1, true) } }) | ||
t.deepEqual(state.peers.bob.notes, { charles: note(-1, true) }) | ||
state.peers.bob.notes = null | ||
state = events.notes(state, { id: 'bob', value: { charles: note(-1, true) } }) | ||
t.deepEqual(state.peers.bob.notes, null) | ||
state = events.follow(state, {id: 'alice', value: false}) | ||
t.end() | ||
}) | ||
t.deepEqual(state.peers.bob.notes, null) | ||
test('remember clock of unfollow', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
state = events.notes(state, {id: 'bob', value:{charles: note(-1, true)}}) | ||
t.deepEqual(state.peers.bob.notes, {charles: note(-1, true)}) | ||
state.peers.bob.notes = null | ||
state = events.notes(state, {id: 'bob', value:{charles: note(-1, true)}}) | ||
t.deepEqual(state.peers.bob.notes, null) | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: -1 } }) | ||
t.end() | ||
}) | ||
t.deepEqual(state.peers.bob.clock, { alice: -1 }) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
t.end() | ||
}) | ||
test('remember clock of unfollow', function (t) { | ||
test('notes can be passed inside {clock:{}} object', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true }, | ||
blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: -1 } }) | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: {alice: true}, blocks: {}, | ||
peers: {} | ||
} | ||
state = events.notes(state, { | ||
id: 'bob', | ||
value: { | ||
clock: { bob: note(4, true) } | ||
} | ||
}) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: -1}}) | ||
t.equal(state.peers.bob.clock.bob, 4) | ||
t.end() | ||
}) | ||
t.deepEqual(state.peers.bob.clock, {alice: -1}) | ||
t.deepEqual(state.peers.bob.notes, {}) | ||
test('test if timeout happens while loading', function (t) { | ||
let state = { | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {}, | ||
timeout: 1 | ||
} | ||
t.end() | ||
}) | ||
state = events.connect(state, { id: 'bob', ts: 1, client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: note(0, true), bob: note(0, true) } }) | ||
test('notes can be passed inside {clock:{}} object', function (t) { | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: {alice: true}, blocks: {}, | ||
peers: {} | ||
} | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: -1}}) | ||
state = events.connect(state, { id: 'charles', ts: 2, client: false }) | ||
console.log(state) | ||
state = events.timeout(state, { ts: 4 }) | ||
state = events.notes(state, {id: 'bob', value: { | ||
clock: {bob: note(4, true)} | ||
}}) | ||
t.end() | ||
}) | ||
t.equal(state.peers.bob.clock.bob, 4) | ||
t.end() | ||
}) | ||
test('test blocks while connected', function (t) { | ||
let state = { | ||
id: 'alice', // we are alice | ||
clock: { alice: 3, bob: 2 }, | ||
follows: { alice: true, bob: true }, | ||
blocks: {}, | ||
peers: {}, | ||
timeout: 1 | ||
} | ||
test('test if timeout happens while loading', function (t) { | ||
state = events.connect(state, { id: 'bob', ts: 1, client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: note(0, true), bob: note(0, true) } }) | ||
var state = { | ||
clock: { alice: 3, bob: 2}, | ||
follows: {alice: true, bob: true}, blocks: {}, | ||
peers: {}, | ||
timeout: 1 | ||
} | ||
// charles blocks bob | ||
state = events.block(state, { id: 'charles', target: 'bob', value: true }) | ||
t.deepEqual(state.blocks, { charles: { bob: true } }) | ||
t.notOk(state.peers.bob.blocked) | ||
state = events.block(state, { id: 'alice', target: 'bob', value: true }) | ||
t.deepEqual(state.blocks, { charles: { bob: true }, alice: { bob: true } }) | ||
t.equal(state.peers.bob.blocked, true) | ||
state = events.connect(state, {id: 'bob', ts: 1, client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: note(0, true), bob: note(0, true)}}) | ||
state = events.timeout(state, { ts: 4 }) | ||
state = events.connect(state, {id: 'charles', ts: 2, client: false}) | ||
console.log(state) | ||
state = events.timeout(state, {ts: 4}) | ||
t.end() | ||
}) | ||
test('test blocks while connected', function (t) { | ||
var state = { | ||
id: 'alice', //we are alice | ||
clock: { alice: 3, bob: 2}, | ||
follows: {alice: true, bob: true}, blocks: {}, | ||
peers: {}, | ||
timeout: 1 | ||
} | ||
state = events.connect(state, {id: 'bob', ts: 1, client: false}) | ||
state = events.peerClock(state, {id: 'bob', value:{alice: note(0, true), bob: note(0, true)}}) | ||
//charles blocks bob | ||
state = events.block(state, {id: 'charles', target: 'bob', value: true}) | ||
t.deepEqual(state.blocks, {charles: {bob: true}}) | ||
t.notOk(state.peers.bob.blocked) | ||
state = events.block(state, {id: 'alice', target: 'bob', value: true}) | ||
t.deepEqual(state.blocks, {charles: {bob: true}, alice: {bob: true}}) | ||
t.equal(state.peers.bob.blocked, true) | ||
state = events.timeout(state, {ts: 4}) | ||
t.end() | ||
}) | ||
t.end() | ||
}) | ||
} | ||
if(!module.parent) | ||
module.exports(require('./options')) | ||
if (!module.parent) { module.exports(require('./options')) } |
var createSimulator = require('./simulator') | ||
var _events = require('../events')(require('./options')) | ||
var test = require('tape') | ||
var progress = require('../progress') | ||
var events = {} | ||
for(var k in _events) (function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if(state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
const createSimulator = require('./simulator') | ||
const _events = require('../events')(require('./options')) | ||
const test = require('tape') | ||
const progress = require('../progress') | ||
const events = {} | ||
for (const k in _events) { | ||
(function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if (state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
} | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var carl = network['carl'] = tick.createPeer('carl') | ||
var dawn = network['dawn'] = tick.createPeer('dawn') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const carl = network.carl = tick.createPeer('carl') | ||
const dawn = network.dawn = tick.createPeer('dawn') | ||
@@ -31,6 +32,6 @@ alice.state.timeout = bob.state.timeout = dawn.state.timeout = 2 | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
@@ -54,3 +55,3 @@ alice.follow('alice') | ||
carl.state.stalled = true | ||
alice.append({author: 'alice', sequence: 4, content: {}}) | ||
alice.append({ author: 'alice', sequence: 4, content: {} }) | ||
@@ -63,4 +64,4 @@ tick.run(network) | ||
function isComplete (peer, name) { | ||
var prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name +' is complete') | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name + ' is complete') | ||
} | ||
@@ -76,10 +77,3 @@ | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { for (let i = 0; i < 100; i++) createTest(i) } else createTest(+seed, true) |
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var charles = network['charles'] = tick.createPeer('charles') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const charles = network.charles = tick.createPeer('charles') | ||
@@ -20,5 +20,5 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
@@ -33,5 +33,5 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
@@ -41,3 +41,3 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
if(log) tick.log() | ||
if (log) tick.log() | ||
@@ -48,18 +48,5 @@ t.end() | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) | ||
createTest(i) | ||
else | ||
createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { | ||
for (let i = 0; i < 100; i++) { createTest(i) } | ||
} else { createTest(+seed, true) } |
@@ -1,5 +0,5 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
var test = require('tape') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
const test = require('tape') | ||
@@ -14,20 +14,19 @@ function count (output) { | ||
return output.reduce(function (a, b) { | ||
if(b.msg) return a | ||
for(var k in b.value) | ||
a[b.from][k] = options.getSequence(b.value[k]) | ||
if (b.msg) return a | ||
for (const k in b.value) { a[b.from][k] = options.getSequence(b.value[k]) } | ||
return a | ||
}, {alice: {}, bob: {}}) | ||
}, { alice: {}, bob: {} }) | ||
} | ||
function isComplete (peer, name, t) { | ||
var prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name +' is complete') | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name + ' is complete') | ||
} | ||
test('loose local state', function (t) { | ||
var tick = createSimulator(0, true, options) | ||
const tick = createSimulator(0, true, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
let bob = network.bob = tick.createPeer('bob') | ||
@@ -37,7 +36,7 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
bob.append({author: 'bob', sequence: 2, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
bob.append({ author: 'bob', sequence: 2, content: {} }) | ||
@@ -51,8 +50,8 @@ alice.follow('bob') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
alice.disconnect(bob) | ||
//should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), {alice: {alice: 3, bob: 0}, bob: {alice: 0, bob: 2}}) | ||
// should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), { alice: { alice: 3, bob: 0 }, bob: { alice: 0, bob: 2 } }) | ||
t.equal(count(tick.output), 2) | ||
@@ -65,6 +64,6 @@ | ||
console.log("===========START OVER===========") | ||
console.log('===========START OVER===========') | ||
// bob gets a brick in his head and forgets everything | ||
bob = network['bob'] = tick.createPeer('bob') | ||
bob = network.bob = tick.createPeer('bob') | ||
bob.init({}) | ||
@@ -77,5 +76,5 @@ t.deepEqual(bob.store, {}) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
console.log("===========SECOND ROUND===========") | ||
console.log('===========SECOND ROUND===========') | ||
@@ -85,3 +84,3 @@ // simulate a contact message received in bobs feed | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -95,9 +94,9 @@ t.deepEqual(bob.store, alice.store) | ||
console.log("===========START OVER 2===========") | ||
console.log('===========START OVER 2===========') | ||
// bob gets a brick in his head and restores from backup | ||
bob = network['bob'] = tick.createPeer('bob') | ||
bob = network.bob = tick.createPeer('bob') | ||
bob.init({}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
@@ -108,5 +107,5 @@ bob.follow('bob') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
console.log("===========SECOND ROUND===========") | ||
console.log('===========SECOND ROUND===========') | ||
@@ -116,3 +115,3 @@ // simulate a contact message received in bobs feed | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -119,0 +118,0 @@ t.deepEqual(bob.store, alice.store) |
@@ -0,55 +1,56 @@ | ||
/* eslint-disable camelcase */ | ||
var test = require('tape') | ||
const test = require('tape') | ||
module.exports = function (events) { | ||
const note = events.note | ||
var note = events.note | ||
test('if connects to multiple peers, should replicate a feed from only one', function (t) { | ||
let state = events.initialize('alice') | ||
state.follows = { | ||
alice: true, bob: true, charles: true | ||
} | ||
state = events.clock(state, { alice: 3, bob: 2, charles: 5 }) | ||
test('if connects to multiple peers, should replicate a feed from only one', function (t) { | ||
state = events.connect(state, { id: 'bob', client: false }) | ||
state = events.peerClock(state, { id: 'bob', value: { alice: 2, bob: 2, charles: 5 } }) | ||
state = events.connect(state, { id: 'charles', client: false }) | ||
state = events.peerClock(state, { id: 'charles', value: { alice: 2, bob: 2, charles: 5 } }) | ||
var state = events.initialize('alice') | ||
state.follows = { | ||
alice: true, bob: true, charles: true | ||
} | ||
state = events.clock(state, {alice: 3, bob: 2, charles: 5}) | ||
state = events.connect(state, {id: 'bob', client: false}) | ||
state = events.peerClock(state, {id: 'bob', value: {alice: 2, bob: 2, charles: 5}}) | ||
state = events.connect(state, {id: 'charles', client: false}) | ||
state = events.peerClock(state, {id: 'charles', value: {alice: 2, bob: 2, charles: 5}}) | ||
console.log(state.peers) | ||
console.log(state.peers) | ||
state = events.notes(state, { | ||
id: 'bob', | ||
value: { | ||
alice: note(3, true), bob: note(5, true), charles: note(9, true) | ||
} | ||
}) | ||
state = events.notes(state, { | ||
id: 'charles', | ||
value: { | ||
alice: note(3, true), bob: note(4, true), charles: note(9, true) | ||
} | ||
}) | ||
console.log(state.peers) | ||
state = events.notes(state, {id: 'bob', value: { | ||
alice: note(3, true), bob: note(5, true), charles: note(9, true) | ||
}}) | ||
state = events.notes(state, {id: 'charles', value: { | ||
alice: note(3, true), bob: note(4, true), charles: note(9, true) | ||
}}) | ||
console.log(state.peers) | ||
//we should only request transmissions from at most one peer. | ||
var notes = {} | ||
for(var peer_id in state.peers) { | ||
var peer = state.peers[peer_id] | ||
for(var feed_id in peer.notes) { | ||
t.equal(events.getReceive(peer.notes[feed_id]), peer.replicating[feed_id].rx, 'implied rx state should be recorded, seq:'+peer.notes[feed_id]+', rx='+peer.replicating[feed_id].rx) | ||
if(events.getReceive(peer.notes[feed_id])) { | ||
notes[feed_id] = (notes[feed_id] || 0) + 1 | ||
// we should only request transmissions from at most one peer. | ||
const notes = {} | ||
for (const peer_id in state.peers) { | ||
const peer = state.peers[peer_id] | ||
for (const feed_id in peer.notes) { | ||
t.equal(events.getReceive(peer.notes[feed_id]), peer.replicating[feed_id].rx, 'implied rx state should be recorded, seq:' + peer.notes[feed_id] + ', rx=' + peer.replicating[feed_id].rx) | ||
if (events.getReceive(peer.notes[feed_id])) { | ||
notes[feed_id] = (notes[feed_id] || 0) + 1 | ||
} | ||
} | ||
} | ||
} | ||
console.log(JSON.stringify(state.peers, null, 2)) | ||
console.log(JSON.stringify(state.peers, null, 2)) | ||
t.deepEqual(notes, {alice: 1, bob: 1, charles: 1}) | ||
t.deepEqual(notes, { alice: 1, bob: 1, charles: 1 }) | ||
t.end() | ||
}) | ||
t.end() | ||
}) | ||
} | ||
if(!module.parent) | ||
module.exports(require('./options')) | ||
if (!module.parent) { module.exports(require('./options')) } |
@@ -1,13 +0,13 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
var test = require('tape') | ||
const test = require('tape') | ||
test('partial replication', function (t) { | ||
var tick = createSimulator(0, true, options) | ||
const tick = createSimulator(0, true, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var charlie = network['charlie'] = tick.createPeer('charlie') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const charlie = network.charlie = tick.createPeer('charlie') | ||
@@ -18,8 +18,8 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
//alice.store['alice'] = alice.store['alice'].slice(1) | ||
// alice.store['alice'] = alice.store['alice'].slice(1) | ||
alice.follow('alice') | ||
@@ -34,3 +34,3 @@ bob.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -43,8 +43,8 @@ // alice sends her whole feed to bob | ||
// lets assume that instead bob had done a partial replication with alice | ||
bob.store['alice'] = bob.store['alice'].slice(1) | ||
bob.store.alice = bob.store.alice.slice(1) | ||
bob.connect(charlie) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
// charlie is not able to get alices feed from bob | ||
@@ -54,9 +54,9 @@ t.deepEqual({}, charlie.store) | ||
charlie.connect(alice) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
// charlie should now have alices feed | ||
t.deepEqual(alice.store, charlie.store) | ||
t.end() | ||
}) |
@@ -1,5 +0,5 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
var test = require('tape') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
const test = require('tape') | ||
@@ -14,16 +14,15 @@ function count (output) { | ||
return output.reduce(function (a, b) { | ||
if(b.msg) return a | ||
for(var k in b.value) | ||
a[b.from][k] = options.getSequence(b.value[k]) | ||
if (b.msg) return a | ||
for (const k in b.value) { a[b.from][k] = options.getSequence(b.value[k]) } | ||
return a | ||
}, {alice: {}, bob: {}}) | ||
}, { alice: {}, bob: {} }) | ||
} | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
@@ -33,6 +32,6 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
@@ -46,13 +45,13 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
alice.disconnect(bob) | ||
//should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), {alice: {alice: 3, bob: 0}, bob: {alice: 0, bob: 1}}) | ||
// should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), { alice: { alice: 3, bob: 0 }, bob: { alice: 0, bob: 1 } }) | ||
t.equal(count(tick.output), 2) | ||
bob.append({author: 'bob', sequence: 2, content: {}}) | ||
bob.append({ author: 'bob', sequence: 2, content: {} }) | ||
console.log('1', tick.output) | ||
tick.output.splice(0, tick.output.length) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -62,6 +61,6 @@ console.log('2', tick.output) | ||
alice.connect(bob) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
console.log('3', tick.output) | ||
t.deepEqual(flatten(tick.output), {alice: {alice: 3, bob: 1}, bob: {alice: 3, bob: 2}}) | ||
t.deepEqual(flatten(tick.output), { alice: { alice: 3, bob: 1 }, bob: { alice: 3, bob: 2 } }) | ||
t.equal(count(tick.output), 3) | ||
@@ -72,3 +71,3 @@ tick.output.splice(0, tick.output.length) | ||
alice.connect(bob) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -79,6 +78,5 @@ t.deepEqual(bob.store, alice.store) | ||
function isComplete (peer, name) { | ||
var prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name +' is complete') | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name + ' is complete') | ||
} | ||
@@ -93,8 +91,3 @@ | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { for (let i = 0; i < 100; i++) createTest(i) } else createTest(+seed, true) |
@@ -1,13 +0,13 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
@@ -17,5 +17,5 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
@@ -27,5 +27,5 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
@@ -37,7 +37,5 @@ t.deepEqual(bob.store, alice.store) | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) | ||
createTest(i) | ||
else | ||
createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { | ||
for (let i = 0; i < 100; i++) { createTest(i) } | ||
} else { createTest(+seed, true) } |
@@ -1,45 +0,49 @@ | ||
var RNG = require('rng') | ||
/* eslint-disable camelcase */ | ||
const RNG = require('rng') | ||
var log | ||
let log | ||
module.exports = function (seed, _log, _events) { | ||
if(!_events) _events = require('../events')(require('../v3')) | ||
if (!_events) _events = require('../events')(require('../v3')) | ||
log = _log | ||
var rng = new RNG.MT(seed || 0) | ||
const rng = new RNG.MT(seed || 0) | ||
var events = {} | ||
const events = {} | ||
for(var k in _events) (function (fn, k) { | ||
events[k] = function (state, value) { | ||
if(log) console.log(k.toUpperCase()+'('+state.id+')', value) | ||
return fn(state, value) | ||
} | ||
})(_events[k],k) | ||
for (const k in _events) { | ||
(function (fn, k) { | ||
events[k] = function (state, value) { | ||
if (log) console.log(k.toUpperCase() + '(' + state.id + ')', value) | ||
return fn(state, value) | ||
} | ||
})(_events[k], k) | ||
} | ||
var output = [] | ||
var ts = 0 | ||
const output = [] | ||
let ts = 0 | ||
function createPeer(id, validate) { | ||
function createPeer (id, validate) { | ||
validate = validate || function () {} | ||
var store = {}, state = events.initialize(id), self | ||
var ts = 0 | ||
var pClock = {} | ||
return self = { | ||
id: id, | ||
let store = {} | ||
let state = events.initialize(id) | ||
let ts = 0 | ||
const pClock = {} | ||
const self = { | ||
id, | ||
clocks: pClock, | ||
store: store, | ||
state: state, | ||
store, | ||
state, | ||
retriving: [], | ||
init: function (_store) { | ||
self.store = store = _store | ||
var clock = {} | ||
for(var k in store) | ||
clock[k] = store[k].length | ||
const clock = {} | ||
for (const k in store) { clock[k] = store[k].length } | ||
state = events.clock(state, clock) | ||
}, | ||
connect: function (other) { | ||
state = events.connect(state, {id: other.id, ts: ++ts, client: true}) | ||
state = events.peerClock(state, {id: other.id, value: pClock[other.id] || {}, ts: ++ts}) | ||
other.state = events.connect(other.state, {id: this.id, ts: ++ts, client: false}) | ||
other.state = events.peerClock(other.state, {id: id, value: other.clocks[id] || {}, ts: ++ts}) | ||
state = events.connect(state, { id: other.id, ts: ++ts, client: true }) | ||
state = events.peerClock(state, { id: other.id, value: pClock[other.id] || {}, ts: ++ts }) | ||
other.state = events.connect(other.state, { id: this.id, ts: ++ts, client: false }) | ||
other.state = events.peerClock(other.state, { id, value: other.clocks[id] || {}, ts: ++ts }) | ||
}, | ||
@@ -50,12 +54,12 @@ disconnect: function (other) { | ||
state = events.disconnect(state, {id: other.id, ts: ++ts}) | ||
other.state = events.disconnect(other.state, {id: this.id, ts: ++ts}) | ||
state = events.disconnect(state, { id: other.id, ts: ++ts }) | ||
other.state = events.disconnect(other.state, { id: this.id, ts: ++ts }) | ||
}, | ||
follow: function (peer, value) { | ||
state = events.follow(state, {id: peer, value: value !== false, ts: ++ts}) | ||
state = events.follow(state, { id: peer, value: value !== false, ts: ++ts }) | ||
}, | ||
append: function (msg) { | ||
var ary = store[msg.author] = store[msg.author] || [] | ||
if(msg.sequence === ary.length + 1) { | ||
validate (store[msg.author], msg) | ||
const ary = store[msg.author] = store[msg.author] || [] | ||
if (msg.sequence === ary.length + 1) { | ||
validate(store[msg.author], msg) | ||
ary.push(msg) | ||
@@ -66,8 +70,10 @@ state = events.append(state, msg) | ||
} | ||
return self | ||
} | ||
function shuffle (ary) { | ||
for(var i = 0; i < ary.length; i++) { | ||
var j = ~~(rng.random()*ary.length) | ||
var tmp = ary[i] | ||
for (let i = 0; i < ary.length; i++) { | ||
const j = ~~(rng.random() * ary.length) | ||
const tmp = ary[i] | ||
ary[i] = ary[j] | ||
@@ -79,9 +85,8 @@ ary[j] = tmp | ||
function randomFind(obj, iter) { | ||
if(!iter) iter = function (key, fn) { return fn() } | ||
if(!obj) throw new Error('obj not provided') | ||
function randomFind (obj, iter) { | ||
if (!iter) iter = function (key, fn) { return fn() } | ||
if (!obj) throw new Error('obj not provided') | ||
var keys = shuffle(Object.keys(obj)) | ||
for(var i = 0; i < keys.length; i++) | ||
if(iter(keys[i], obj[keys[i]])) return true | ||
const keys = shuffle(Object.keys(obj)) | ||
for (let i = 0; i < keys.length; i++) { if (iter(keys[i], obj[keys[i]])) return true } | ||
@@ -93,10 +98,10 @@ return false | ||
return randomFind(network, function (id, peer) { | ||
//database ops | ||
if(peer.state.stalled) return | ||
// database ops | ||
if (peer.state.stalled) return | ||
return randomFind([function () { | ||
//append(receive), retrive, retrive_cb | ||
// append(receive), retrive, retrive_cb | ||
return randomFind([function () { | ||
return randomFind(peer.state.peers, function (key, p2p) { | ||
if(!p2p.clock) { | ||
peer.state = events.peerClock(peer.state, {id: key, value: {}, ts: ++ts}) | ||
if (!p2p.clock) { | ||
peer.state = events.peerClock(peer.state, { id: key, value: {}, ts: ++ts }) | ||
return true | ||
@@ -106,8 +111,9 @@ } | ||
}, function () { | ||
if(peer.state.receive.length) { | ||
var ev = peer.state.receive.shift() | ||
if (peer.state.receive.length) { | ||
const ev = peer.state.receive.shift() | ||
try { | ||
peer.append(ev.value) | ||
} catch (err) { | ||
return peer.state = events.block(peer.state, {id: ev.value.author, target: ev.id, value: true}) | ||
peer.state = events.block(peer.state, { id: ev.value.author, target: ev.id, value: true }) | ||
return peer.state | ||
} | ||
@@ -118,13 +124,13 @@ return true | ||
return randomFind(peer.state.peers, function (key, p2p) { | ||
//randomly order, to simulate async | ||
// randomly order, to simulate async | ||
p2p.retrive = shuffle(p2p.retrive) | ||
if(p2p.retrive.length) { | ||
var peer_id = p2p.retrive.shift() | ||
//it's possible that two peers need to retrive the same message at the same time | ||
//this may mean that the retrival is queued twice. | ||
var rep = p2p.replicating[peer_id] | ||
if(rep.tx && rep.sent < peer.state.clock[peer_id]) { | ||
var msg = peer.store[peer_id][rep.sent] | ||
if(msg == null) { | ||
throw new Error('null msg!, clock:'+peer.state.clock[peer_id]+ ', id:'+peer_id) | ||
if (p2p.retrive.length) { | ||
const peer_id = p2p.retrive.shift() | ||
// it's possible that two peers need to retrive the same message at the same time | ||
// this may mean that the retrival is queued twice. | ||
const rep = p2p.replicating[peer_id] | ||
if (rep.tx && rep.sent < peer.state.clock[peer_id]) { | ||
const msg = peer.store[peer_id][rep.sent] | ||
if (msg == null) { | ||
throw new Error('null msg!, clock:' + peer.state.clock[peer_id] + ', id:' + peer_id) | ||
} | ||
@@ -137,3 +143,3 @@ peer.retriving.push(msg) | ||
}, function () { | ||
if(peer.retriving.length) { | ||
if (peer.retriving.length) { | ||
peer.retriving = shuffle(peer.retriving) | ||
@@ -144,16 +150,15 @@ peer.state = events.retrive(peer.state, peer.retriving.shift()) | ||
}]) | ||
}, function () { //network ops | ||
}, function () { // network ops | ||
return randomFind(peer.state.peers, function (remote_id, remote) { | ||
if(remote.notes) { | ||
var notes = remote.notes | ||
if (remote.notes) { | ||
const notes = remote.notes | ||
remote.notes = null | ||
network[remote_id].state = | ||
events.notes(network[remote_id].state, {id: id, value: notes, ts: ++ts}) | ||
output.push({from: id, to: remote_id, value: notes, msg: false}) | ||
events.notes(network[remote_id].state, { id, value: notes, ts: ++ts }) | ||
output.push({ from: id, to: remote_id, value: notes, msg: false }) | ||
return true | ||
} | ||
else if(remote.msgs.length) { | ||
output.push({from: id, to: remote_id, value: remote.msgs[0], msg: true}) | ||
} else if (remote.msgs.length) { | ||
output.push({ from: id, to: remote_id, value: remote.msgs[0], msg: true }) | ||
network[remote_id].state = | ||
events.receive(network[remote_id].state, {id: id, value: remote.msgs.shift(), ts: ++ts}) | ||
events.receive(network[remote_id].state, { id, value: remote.msgs.shift(), ts: ++ts }) | ||
return true | ||
@@ -164,3 +169,3 @@ } | ||
}) | ||
//TODO: test random network connections. | ||
// TODO: test random network connections. | ||
} | ||
@@ -174,6 +179,4 @@ | ||
tick.output.map(function (e) { | ||
if(e.msg) | ||
return e.from+'>'+e.to+':'+e.value.author[0]+e.value.sequence | ||
else | ||
return e.from+'>'+e.to+':'+JSON.stringify(e.value) | ||
if (e.msg) return e.from + '>' + e.to + ':' + e.value.author[0] + e.value.sequence | ||
else return e.from + '>' + e.to + ':' + JSON.stringify(e.value) | ||
}).join('\n') | ||
@@ -184,14 +187,14 @@ ) | ||
tick.ts = function (_ts) { | ||
return ts += (_ts|0) | ||
ts += (_ts | 0) | ||
return ts | ||
} | ||
tick.run = function (network) { | ||
var loop = 1, first = true | ||
while(loop) { | ||
let loop = 1; let first = true | ||
while (loop) { | ||
loop = 0 | ||
while(tick(network)) loop ++ | ||
if(loop || first) { | ||
for(var k in network) | ||
network[k].state = events.timeout(network[k].state, {ts: ts++}) | ||
if(first) loop = 1 | ||
while (tick(network)) loop++ | ||
if (loop || first) { | ||
for (const k in network) { network[k].state = events.timeout(network[k].state, { ts: ts++ }) } | ||
if (first) loop = 1 | ||
first = false | ||
@@ -204,4 +207,1 @@ } | ||
} | ||
var createSimulator = require('./simulator') | ||
var _events = require('../events')(require('./options')) | ||
var test = require('tape') | ||
const createSimulator = require('./simulator') | ||
const _events = require('../events')(require('./options')) | ||
const test = require('tape') | ||
var events = {} | ||
for(var k in _events) (function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if(state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
const events = {} | ||
for (const k in _events) { | ||
(function (fn, k) { | ||
events[k] = function (state, ev) { | ||
if (state.stalled) return state | ||
return fn(state, ev) | ||
} | ||
})(_events[k], k) | ||
} | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, events) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, events) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var carl = network['carl'] = tick.createPeer('carl') | ||
var dawn = network['dawn'] = tick.createPeer('dawn') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const carl = network.carl = tick.createPeer('carl') | ||
const dawn = network.dawn = tick.createPeer('dawn') | ||
@@ -31,10 +32,10 @@ alice.state.timeout = bob.state.timeout = dawn.state.timeout = 1 | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
bob.append({author: 'alice', sequence: 1, content: {}}) | ||
carl.append({author: 'alice', sequence: 1, content: {}}) | ||
dawn.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
bob.append({ author: 'alice', sequence: 1, content: {} }) | ||
carl.append({ author: 'alice', sequence: 1, content: {} }) | ||
dawn.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
@@ -57,20 +58,19 @@ alice.follow('alice') | ||
while(( | ||
while (( | ||
(!dawn.store.alice || dawn.store.alice.length < 2) | ||
// && | ||
// (!bob.store.alice || bob.store.alice.length < 2) | ||
// && | ||
// (!bob.store.alice || bob.store.alice.length < 2) | ||
) && tick(network)) | ||
; | ||
carl.state.stalled = true | ||
// bob.state.peers.alice.replicating.alice.rx = false | ||
// dawn.state.peers.bob.replicating.alice.rx = false | ||
// bob.state.peers.carl.replicating.alice.rx = true | ||
// dawn.state.peers.carl.replicating.alice.rx = true | ||
// bob.state.peers.alice.replicating.alice.rx = false | ||
// dawn.state.peers.bob.replicating.alice.rx = false | ||
// bob.state.peers.carl.replicating.alice.rx = true | ||
// dawn.state.peers.carl.replicating.alice.rx = true | ||
// bob.state.peers.alice.notes = null | ||
// dawn.state.peers.bob.notes = null | ||
// bob.state.peers.alice.notes = null | ||
// dawn.state.peers.bob.notes = null | ||
//then continue running the simulation, including timeout | ||
// then continue running the simulation, including timeout | ||
tick.log() | ||
@@ -80,12 +80,12 @@ tick.output.splice(0, tick.output.length) | ||
console.log(JSON.stringify(dawn.state, null, 2)) | ||
// console.log(tick.ts()) | ||
// console.log("CONTINUE") | ||
// return t.end() | ||
// console.log(tick.ts()) | ||
// console.log("CONTINUE") | ||
// return t.end() | ||
tick.run(network) | ||
// while(tick(network)); | ||
// while(tick(network)); | ||
tick.log() | ||
// return t.end() | ||
// return t.end() | ||
@@ -99,10 +99,3 @@ t.deepEqual(dawn.store, alice.store, 'dawn matches alice') | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) | ||
for(var i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) { for (let i = 0; i < 100; i++) createTest(i) } else createTest(+seed, true) |
@@ -1,12 +0,10 @@ | ||
var createPeer = require('../') | ||
var test = require('tape') | ||
const createPeer = require('../') | ||
const test = require('tape') | ||
function create (id) { | ||
var store = {} | ||
const store = {} | ||
function append (msg, cb) { | ||
store[msg.author] = store[msg.author] || [] | ||
if(msg.sequence - 1 != store[msg.author].length) | ||
cb(new Error('out of order')) | ||
else { | ||
if (msg.sequence - 1 !== store[msg.author].length) { cb(new Error('out of order')) } else { | ||
store[msg.author].push(msg) | ||
@@ -18,4 +16,4 @@ p.onAppend(msg) | ||
var p = createPeer({ | ||
id: id, | ||
const p = createPeer({ | ||
id, | ||
getClock: function (id, cb) { | ||
@@ -26,6 +24,6 @@ cb(null, {}) | ||
getAt: function (pair, cb) { | ||
if(!store[pair.id] || !store[pair.id][pair.sequence]) cb(new Error('not found')) | ||
if (!store[pair.id] || !store[pair.id][pair.sequence]) cb(new Error('not found')) | ||
else cb(null, store[pair.id][pair.sequence]) | ||
}, | ||
append: append | ||
append | ||
}) | ||
@@ -38,6 +36,5 @@ p.store = store | ||
test('a<->b', function (t) { | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
alice.request('alice', true) | ||
@@ -48,30 +45,27 @@ alice.request('bob', true) | ||
var as = alice.createStream('bob', 3, false) | ||
var bs = bob.createStream('alice', 3, true) | ||
const as = alice.createStream('bob', 3, false) | ||
const bs = bob.createStream('alice', 3, true) | ||
console.log('initial.alice:',alice.progress()) | ||
console.log('initial.bob :',bob.progress()) | ||
console.log('initial.alice:', alice.progress()) | ||
console.log('initial.bob :', bob.progress()) | ||
as.pipe(bs).pipe(as) | ||
alice.append({ author: 'alice', sequence: 1, content: 'hello' }, function () {}) | ||
bob.append({ author: 'bob', sequence: 1, content: 'hello' }, function () {}) | ||
alice.append({author: 'alice', sequence: 1, content: 'hello'}, function () {}) | ||
bob.append({author: 'bob', sequence: 1, content: 'hello'}, function () {}) | ||
console.log(bob.store) | ||
console.log(alice.store) | ||
console.log('final.alice:',alice.progress()) | ||
console.log('final.bob :',bob.progress()) | ||
console.log('final.alice:', alice.progress()) | ||
console.log('final.bob :', bob.progress()) | ||
t.deepEqual(alice.store, bob.store) | ||
t.end() | ||
}) | ||
test('a<->b,b', function (t) { | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
alice.request('alice', true) | ||
@@ -82,12 +76,12 @@ alice.request('bob', true) | ||
var as = alice.createStream('bob', 3, true) | ||
var bs = bob.createStream('alice', 3, false) | ||
const as = alice.createStream('bob', 3, true) | ||
const bs = bob.createStream('alice', 3, false) | ||
console.log('initial.alice:',alice.progress()) | ||
console.log('initial.bob :',bob.progress()) | ||
console.log('initial.alice:', alice.progress()) | ||
console.log('initial.bob :', bob.progress()) | ||
as.pipe(bs).pipe(as) | ||
alice.append({author: 'alice', sequence: 1, content: 'hello'}, function () {}) | ||
bob.append({author: 'bob', sequence: 1, content: 'hello'}, function () {}) | ||
alice.append({ author: 'alice', sequence: 1, content: 'hello' }, function () {}) | ||
bob.append({ author: 'bob', sequence: 1, content: 'hello' }, function () {}) | ||
@@ -97,4 +91,4 @@ console.log(bob.store) | ||
console.log('final.alice:',alice.progress()) | ||
console.log('final.bob :',bob.progress()) | ||
console.log('final.alice:', alice.progress()) | ||
console.log('final.bob :', bob.progress()) | ||
@@ -106,9 +100,7 @@ t.deepEqual(alice.store, bob.store) | ||
test('a3<->b3<->c2', function (t) { | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
const charles = create('charles') | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
var charles = create('charles') | ||
alice.request('alice', true) | ||
@@ -121,10 +113,10 @@ alice.request('bob', true) | ||
var as3 = alice.createStream('bob', 3, true) | ||
var bs3 = bob.createStream('alice', 3, false) | ||
var bs2 = bob.createStream('charles', 3, false) | ||
var cs2 = charles.createStream('bob', 3, true) | ||
const as3 = alice.createStream('bob', 3, true) | ||
const bs3 = bob.createStream('alice', 3, false) | ||
const bs2 = bob.createStream('charles', 3, false) | ||
const cs2 = charles.createStream('bob', 3, true) | ||
console.log('initial.alice:',alice.progress()) | ||
console.log('initial.bob :',bob.progress()) | ||
console.log('initial.charles :',charles.progress()) | ||
console.log('initial.alice:', alice.progress()) | ||
console.log('initial.bob :', bob.progress()) | ||
console.log('initial.charles :', charles.progress()) | ||
@@ -134,11 +126,10 @@ as3.pipe(bs3).pipe(as3) | ||
alice.append({ author: 'alice', sequence: 1, content: 'hello' }, function () {}) | ||
bob.append({ author: 'bob', sequence: 1, content: 'hello' }, function () {}) | ||
alice.append({author: 'alice', sequence: 1, content: 'hello'}, function () {}) | ||
bob.append({author: 'bob', sequence: 1, content: 'hello'}, function () {}) | ||
console.log(bob.store) | ||
console.log(alice.store) | ||
console.log('final.alice:',alice.progress()) | ||
console.log('final.bob :',bob.progress()) | ||
console.log('final.alice:', alice.progress()) | ||
console.log('final.bob :', bob.progress()) | ||
@@ -148,8 +139,7 @@ t.deepEqual(alice.store, bob.store) | ||
t.end() | ||
}) | ||
test('a<-!>b', function (t) { | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
@@ -162,4 +152,4 @@ alice.request('alice', true) | ||
var as = alice.createStream('bob', 3, false) | ||
var bs = bob.createStream('alice', 3, true) | ||
const as = alice.createStream('bob', 3, false) | ||
const bs = bob.createStream('alice', 3, true) | ||
@@ -174,4 +164,4 @@ as.pipe(bs).pipe(as) | ||
test('a<->b...!', function (t) { | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
@@ -183,4 +173,4 @@ alice.request('alice', true) | ||
var as = alice.createStream('bob', 3, false) | ||
var bs = bob.createStream('alice', 3, true) | ||
const as = alice.createStream('bob', 3, false) | ||
const bs = bob.createStream('alice', 3, true) | ||
@@ -200,4 +190,4 @@ as.pipe(bs).pipe(as) | ||
test('b<-!->a', function (t) { | ||
var alice = create('alice') | ||
var bob = create('bob') | ||
const alice = create('alice') | ||
const bob = create('bob') | ||
@@ -210,4 +200,4 @@ alice.request('alice', true) | ||
var as = alice.createStream('bob', 3, true) | ||
var bs = bob.createStream('alice', 3, false) | ||
const as = alice.createStream('bob', 3, true) | ||
const bs = bob.createStream('alice', 3, false) | ||
@@ -220,11 +210,1 @@ as.pipe(bs).pipe(as) | ||
}) | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var charles = network['charles'] = tick.createPeer('charles') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const charles = network.charles = tick.createPeer('charles') | ||
@@ -20,13 +20,13 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
bob.append({author: 'bob', sequence: 2, content: {}}) | ||
bob.append({author: 'bob', sequence: 3, content: {}}) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
bob.append({ author: 'bob', sequence: 2, content: {} }) | ||
bob.append({ author: 'bob', sequence: 3, content: {} }) | ||
charles.append({author: 'charles', sequence: 1, content: {}}) | ||
charles.append({author: 'charles', sequence: 2, content: {}}) | ||
charles.append({author: 'charles', sequence: 3, content: {}}) | ||
charles.append({ author: 'charles', sequence: 1, content: {} }) | ||
charles.append({ author: 'charles', sequence: 2, content: {} }) | ||
charles.append({ author: 'charles', sequence: 3, content: {} }) | ||
@@ -48,5 +48,5 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
@@ -58,6 +58,6 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
alice.append({author: 'alice', sequence: 4, content: {}}) | ||
alice.append({author: 'alice', sequence: 5, content: {}}) | ||
alice.append({ author: 'alice', sequence: 4, content: {} }) | ||
alice.append({ author: 'alice', sequence: 5, content: {} }) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -69,5 +69,5 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
alice.append({author: 'alice', sequence: 6, content: {}}) | ||
alice.append({ author: 'alice', sequence: 6, content: {} }) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -77,3 +77,3 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
if(log) tick.log() | ||
if (log) tick.log() | ||
@@ -84,12 +84,4 @@ t.end() | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) for(var i = 0; i < 100; i++) createTest(i) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) for (let i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
var test = require('tape') | ||
var events = require('../events')(require('./options')) | ||
const test = require('tape') | ||
const events = require('../events')(require('./options')) | ||
test('switch peers if timeout exceeded', function (t) { | ||
var state = { | ||
let state = { | ||
id: 'alice', | ||
clock: {bob: 5, charles: 6, dawn: 3}, | ||
clock: { bob: 5, charles: 6, dawn: 3 }, | ||
retrive: [], | ||
follows: {bob: true}, blocks: {}, | ||
follows: { bob: true }, | ||
blocks: {}, | ||
timeout: 1000, | ||
peers: { | ||
bob: { | ||
clock: {bob: 7}, | ||
clock: { bob: 7 }, | ||
notes: null, | ||
replicating: { bob: {rx: true, tx: false, sent: -1 }}, | ||
replicating: { bob: { rx: true, tx: false, sent: -1 } }, | ||
ts: 3000 | ||
}, | ||
charles: { | ||
clock: {bob: 10}, | ||
clock: { bob: 10 }, | ||
notes: null, | ||
replicating: { bob: {rx: false, tx: false, sent: -1 }} | ||
replicating: { bob: { rx: false, tx: false, sent: -1 } } | ||
}, | ||
dawn: { | ||
clock: {bob: 9}, | ||
clock: { bob: 9 }, | ||
notes: null, | ||
replicating: { bob: {rx: false, tx: false, sent: -1 }} | ||
replicating: { bob: { rx: false, tx: false, sent: -1 } } | ||
} | ||
@@ -32,3 +33,3 @@ } | ||
state = events.timeout(state, {ts: 5000}) | ||
state = events.timeout(state, { ts: 5000 }) | ||
@@ -40,3 +41,3 @@ t.equal(state.peers.bob.replicating.bob.rx, false) | ||
state = events.timeout(state, {ts: 10000}) | ||
state = events.timeout(state, { ts: 10000 }) | ||
@@ -46,3 +47,3 @@ t.equal(state.peers.charles.replicating.bob.rx, false) | ||
state = events.timeout(state, {ts: 15000}) | ||
state = events.timeout(state, { ts: 15000 }) | ||
@@ -53,11 +54,10 @@ t.equal(state.peers.dawn.replicating.bob.rx, false) | ||
t.end() | ||
}) | ||
test('if up to latest message by peer, swich if another peer claims newer', function (t) { | ||
var state = { | ||
let state = { | ||
id: 'alice', | ||
clock: {bob: 7, charles: 6, dawn: 3}, | ||
clock: { bob: 7, charles: 6, dawn: 3 }, | ||
retrive: [], | ||
follows: {bob: true}, | ||
follows: { bob: true }, | ||
blocks: {}, | ||
@@ -67,16 +67,16 @@ timeout: 1000, | ||
bob: { | ||
clock: {bob: 7}, | ||
clock: { bob: 7 }, | ||
notes: null, | ||
replicating: { bob: {rx: true, tx: false, sent: -1 }}, | ||
replicating: { bob: { rx: true, tx: false, sent: -1 } }, | ||
ts: 3000 | ||
}, | ||
charles: { | ||
clock: {bob: 10}, | ||
clock: { bob: 10 }, | ||
notes: null, | ||
replicating: { bob: {rx: false, tx: false, sent: -1 }} | ||
replicating: { bob: { rx: false, tx: false, sent: -1 } } | ||
}, | ||
dawn: { | ||
clock: {bob: 9}, | ||
clock: { bob: 9 }, | ||
notes: null, | ||
replicating: { bob: {rx: false, tx: false, sent: -1 }} | ||
replicating: { bob: { rx: false, tx: false, sent: -1 } } | ||
} | ||
@@ -86,3 +86,3 @@ } | ||
state = events.timeout(state, {ts: 5000}) | ||
state = events.timeout(state, { ts: 5000 }) | ||
@@ -92,9 +92,8 @@ t.equal(state.peers.bob.replicating.bob.rx, false) | ||
state = events.timeout(state, { ts: 10000 }) | ||
state = events.timeout(state, {ts: 10000}) | ||
t.equal(state.peers.charles.replicating.bob.rx, false) | ||
t.equal(state.peers.dawn.replicating.bob.rx, true) | ||
state = events.timeout(state, {ts: 15000}) | ||
state = events.timeout(state, { ts: 15000 }) | ||
@@ -104,9 +103,6 @@ console.log(JSON.stringify(state, null, 2)) | ||
t.equal(state.peers.dawn.replicating.bob.rx, false) | ||
// t.equal(state.peers.charles.replicating.bob.rx, true) | ||
// t.equal(state.peers.charles.replicating.bob.rx, true) | ||
t.equal(state.peers.bob.replicating.bob.rx, true) | ||
t.end() | ||
}) | ||
@@ -1,15 +0,15 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
var test = require('tape') | ||
const test = require('tape') | ||
function createTest (seed, log) { | ||
test('simple test with seed:'+seed, function (t) { | ||
var tick = createSimulator(seed, log, options) | ||
test('simple test with seed:' + seed, function (t) { | ||
const tick = createSimulator(seed, log, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
var charles = network['charles'] = tick.createPeer('charles') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
const charles = network.charles = tick.createPeer('charles') | ||
@@ -20,5 +20,5 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
@@ -32,5 +32,5 @@ alice.follow('alice') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
//should have set up peer.replicatings to tx/rx alice | ||
// should have set up peer.replicatings to tx/rx alice | ||
@@ -42,6 +42,6 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
alice.append({author: 'alice', sequence: 4, content: {}}) | ||
alice.append({author: 'alice', sequence: 5, content: {}}) | ||
alice.append({ author: 'alice', sequence: 4, content: {} }) | ||
alice.append({ author: 'alice', sequence: 5, content: {} }) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -53,5 +53,5 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
alice.append({author: 'alice', sequence: 6, content: {}}) | ||
alice.append({ author: 'alice', sequence: 6, content: {} }) | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
@@ -61,13 +61,13 @@ t.deepEqual(bob.store, alice.store, 'alice<->bob') | ||
var totals = tick.output.reduce(function (a, b) { | ||
if(!a) a = [0,0,0]; a[0] ++; a[1 + (+b.msg)] ++ | ||
const totals = tick.output.reduce(function (a, b) { | ||
if (!a) a = [0, 0, 0]; a[0]++; a[1 + (+b.msg)]++ | ||
return a | ||
}, null) | ||
t.equal(totals[1], 3*2, 'number of handshakes sent is connections*2') | ||
t.equal(totals[2], 6*(3-1), 'number of msgs sent is msgs*(peers-1)') | ||
t.equal(totals[1], 3 * 2, 'number of handshakes sent is connections*2') | ||
t.equal(totals[2], 6 * (3 - 1), 'number of msgs sent is msgs*(peers-1)') | ||
var prog = progress(alice.state) | ||
const prog = progress(alice.state) | ||
t.equal(prog.current, prog.target) | ||
var prog2 = progress(bob.state) | ||
const prog2 = progress(bob.state) | ||
t.equal(prog2.current, prog2.target) | ||
@@ -77,11 +77,9 @@ | ||
if(log) | ||
if (log) { | ||
console.log( | ||
tick.output.map(function (e) { | ||
if(e.msg) | ||
return e.from+'>'+e.to+':'+e.value.sequence | ||
else | ||
return e.from+'>'+e.to+':'+JSON.stringify(e.value) | ||
if (e.msg) { return e.from + '>' + e.to + ':' + e.value.sequence } else { return e.from + '>' + e.to + ':' + JSON.stringify(e.value) } | ||
}).join('\n') | ||
) | ||
} | ||
@@ -92,8 +90,4 @@ t.end() | ||
var seed = process.argv[2] | ||
if(isNaN(seed)) for(var i = 0; i < 100; i++) createTest(i) | ||
const seed = process.argv[2] | ||
if (isNaN(seed)) for (let i = 0; i < 100; i++) createTest(i) | ||
else createTest(+seed, true) | ||
@@ -1,5 +0,5 @@ | ||
var createSimulator = require('./simulator') | ||
var options = require('./options') | ||
var progress = require('../progress') | ||
var test = require('tape') | ||
const createSimulator = require('./simulator') | ||
const options = require('./options') | ||
const progress = require('../progress') | ||
const test = require('tape') | ||
@@ -14,20 +14,19 @@ function count (output) { | ||
return output.reduce(function (a, b) { | ||
if(b.msg) return a | ||
for(var k in b.value) | ||
a[b.from][k] = options.getSequence(b.value[k]) | ||
if (b.msg) return a | ||
for (const k in b.value) { a[b.from][k] = options.getSequence(b.value[k]) } | ||
return a | ||
}, {alice: {}, bob: {}}) | ||
}, { alice: {}, bob: {} }) | ||
} | ||
function isComplete (peer, name, t) { | ||
var prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name +' is complete') | ||
const prog = progress(peer.state) | ||
t.equal(prog.current, prog.target, name + ' is complete') | ||
} | ||
test('write error', function (t) { | ||
var tick = createSimulator(0, true, options) | ||
const tick = createSimulator(0, true, options) | ||
var network = {} | ||
var alice = network['alice'] = tick.createPeer('alice') | ||
var bob = network['bob'] = tick.createPeer('bob') | ||
const network = {} | ||
const alice = network.alice = tick.createPeer('alice') | ||
const bob = network.bob = tick.createPeer('bob') | ||
@@ -37,7 +36,7 @@ alice.init({}) | ||
alice.append({author: 'alice', sequence: 1, content: {}}) | ||
alice.append({author: 'alice', sequence: 2, content: {}}) | ||
alice.append({author: 'alice', sequence: 3, content: {}}) | ||
bob.append({author: 'bob', sequence: 1, content: {}}) | ||
bob.append({author: 'bob', sequence: 2, content: {}}) | ||
alice.append({ author: 'alice', sequence: 1, content: {} }) | ||
alice.append({ author: 'alice', sequence: 2, content: {} }) | ||
alice.append({ author: 'alice', sequence: 3, content: {} }) | ||
bob.append({ author: 'bob', sequence: 1, content: {} }) | ||
bob.append({ author: 'bob', sequence: 2, content: {} }) | ||
@@ -51,11 +50,11 @@ alice.follow('bob') | ||
while(tick(network)) ; | ||
while (tick(network)) ; | ||
const bobPeerState = alice.state.peers.bob | ||
console.log("bob peer state", bobPeerState) | ||
console.log('bob peer state', bobPeerState) | ||
alice.disconnect(bob) | ||
//should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), {alice: {alice: 3, bob: 0}, bob: {alice: 0, bob: 2}}) | ||
// should have set up peer.replicatings to tx/rx alice | ||
t.deepEqual(flatten(tick.output), { alice: { alice: 3, bob: 0 }, bob: { alice: 0, bob: 2 } }) | ||
t.equal(count(tick.output), 2) | ||
@@ -65,4 +64,4 @@ | ||
console.log("alice store", alice.store) | ||
console.log("bob store", bob.store) | ||
console.log('alice store', alice.store) | ||
console.log('bob store', bob.store) | ||
@@ -72,11 +71,11 @@ isComplete(alice, 'alice', t) | ||
console.log("===========START OVER===========") | ||
console.log('===========START OVER===========') | ||
// bob has a write error | ||
bob.store.alice = bob.store.alice.slice(0,2) | ||
bob.store.alice = bob.store.alice.slice(0, 2) | ||
bob.clocks.alice.alice = 2 | ||
bob.state.clock.alice = 2 | ||
alice.append({author: 'alice', sequence: 4, content: {}}) | ||
alice.append({ author: 'alice', sequence: 4, content: {} }) | ||
@@ -87,8 +86,8 @@ alice.connect(bob) | ||
alice.state.peers.bob.clock = { alice: 3, bob: 2 } | ||
while(tick(network)) ; | ||
t.equal(bob.store.alice.length, 4, "bob has all alices messages") | ||
while (tick(network)) ; | ||
t.equal(bob.store.alice.length, 4, 'bob has all alices messages') | ||
t.end() | ||
}) |
@@ -1,15 +0,15 @@ | ||
exports.note = function note(seq, rx) { | ||
exports.note = function note (seq, rx) { | ||
return seq === -1 ? -1 : seq << 1 | !rx | ||
} | ||
exports.getSequence = function getSequence(seq) { | ||
exports.getSequence = function getSequence (seq) { | ||
return !Number.isInteger(seq) ? -1 : seq >> 1 | ||
} | ||
exports.getReplicate = function getReplicate(seq) { | ||
exports.getReplicate = function getReplicate (seq) { | ||
return seq !== -1 | ||
} | ||
exports.getReceive = function getReceive(seq) { | ||
exports.getReceive = function getReceive (seq) { | ||
return !(seq & 1) | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
108749
5
33
2403
1