Skip to content

Commit

Permalink
Refactor formats a bit and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
arj03 committed Sep 6, 2021
1 parent 89285a4 commit 1c37be2
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 25 deletions.
56 changes: 31 additions & 25 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,62 +47,67 @@ function cleanClock (clock, isFeed) {
exports.init = function (sbot, config) {
const formats = {
'classic': {
// used in sbot.post & in ebt:stream to distinguish between
// messages and notes
isMsg(m) {
return Number.isInteger(m.sequence) && m.sequence > 0 &&
typeof m.author == 'string' && m.content
},
// used in request, block, cleanClock
// used in request, block, cleanClock, sbot.post
isFeed: ref.isFeed,
// used in getAt
fromDB(msg) {
return msg ? msg.value : null
},
// used in append
toDB(msgVal) {
return msgVal
},

// used in ebt:stream to distinguish between messages and notes
isMsg(msgVal) {
return Number.isInteger(msgVal.sequence) && msgVal.sequence > 0 &&
typeof msgVal.author == 'string' && msgVal.content
},
// used in ebt:events
getMsgAuthor(msg) {
return msg.author
getMsgAuthor(msgVal) {
return msgVal.author
},
// used in ebt:events
getMsgSequence(msg) {
return msg.sequence
getMsgSequence(msgVal) {
return msgVal.sequence
},
// used in getAt
getAtTransform(msg) {
return msg ? msg.value : null
}
}
}

const ebts = {}
function addEBT(formatName) {
const dirName = 'ebt' + (formatName === 'classic') ? '' : formatName
const dirName = 'ebt' + (formatName === 'classic' ? '' : formatName)
const dir = config.path ? path.join(config.path, dirName) : null
const store = Store(dir, null, toUrlFriendly)

const isFeed = formats[formatName].isFeed
const format = formats[formatName]

const ebt = EBT(Object.assign({
format: formatName,
logging: config.ebt && config.ebt.logging,
id: sbot.id,
getClock (id, cb) {
store.ensure(id, function () {
const clock = store.get(id) || {}
cleanClock(clock, isFeed)
cleanClock(clock, format.isFeed)
cb(null, clock)
})
},
setClock (id, clock) {
cleanClock(clock, isFeed)
cleanClock(clock, format.isFeed)
store.set(id, clock)
},
getAt (pair, cb) {
sbot.getAtSequence([pair.id, pair.sequence], (err, data) => {
cb(err, formats[formatName].getAtTransform(data))
sbot.getAtSequence([pair.id, pair.sequence], (err, msg) => {
cb(err, format.fromDB(msg))
})
},
append (msg, cb) {
sbot.add(msg, (err, msg) => {
append (msgVal, cb) {
sbot.add(format.toDB(msgVal), (err, msg) => {
cb(err && err.fatal ? err : null, msg)
})
}
}, formats[formatName]))
}, format))

ebts[formatName] = ebt
}
Expand Down Expand Up @@ -132,8 +137,9 @@ exports.init = function (sbot, config) {

sbot.post((msg) => {
for (let format in ebts) {
if (formats[format].isMsg(msg.value))
if (formats[format].isFeed(msg.value.author)) {
ebts[format].onAppend(msg.value)
}
}
})

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@
"rimraf": "^2.7.1",
"rng": "^0.2.2",
"secret-stack": "^6.4.0",
"ssb-bendy-butt": "^0.12.2",
"ssb-client": "^4.9.0",
"ssb-db": "^19.2.0",
"ssb-db2": "github:ssb-ngi-pointer/ssb-db2#support-bendy-butt",
"ssb-generate": "^1.0.1",
"ssb-keys": "^8.1.0",
"ssb-uri2": "^1.5.2",
"ssb-validate": "^4.1.4",
"standardx": "^7.0.0",
"tap-spec": "^5.0.0",
Expand Down
187 changes: 187 additions & 0 deletions test/formats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
const tape = require('tape')
const crypto = require('crypto')
const SecretStack = require('secret-stack')
const sleep = require('util').promisify(setTimeout)
const pify = require('promisify-4loc')
const u = require('./misc/util')

const caps = require('ssb-caps')
const rimraf = require('rimraf')
const mkdirp = require('mkdirp')
const ssbKeys = require('ssb-keys')
const SSBURI = require('ssb-uri2')
const bendyButt = require('ssb-bendy-butt')

function createSsbServer() {
return SecretStack({ appKey: caps.shs })
.use(require('ssb-db2'))
.use(require('ssb-db2/compat/ebt'))
.use(require('../'))
}

const CONNECTION_TIMEOUT = 500 // ms
const REPLICATION_TIMEOUT = 2 * CONNECTION_TIMEOUT

const aliceDir = '/tmp/test-format-alice'
rimraf.sync(aliceDir)
mkdirp.sync(aliceDir)

const alice = createSsbServer().call(null, {
path: aliceDir,
timeout: CONNECTION_TIMEOUT,
keys: u.keysFor('alice'),
ebt: {
logging: false
}
})

const bobDir = '/tmp/test-format-bob'
rimraf.sync(bobDir)
mkdirp.sync(bobDir)

const bob = createSsbServer().call(null, {
path: bobDir,
timeout: CONNECTION_TIMEOUT,
keys: u.keysFor('bob')
})

console.log("alice", alice.id)
console.log("bob", bob.id)

tape('multiple formats', async (t) => {
const bendyButtMethods = {
// used in request, block, cleanClock, sbot.post
isFeed: SSBURI.isBendyButtV1FeedSSBURI,
// used in getAt
fromDB(msg) {
return msg ? bendyButt.encode(msg.value) : null
},
// used in append
toDB(msgVal) {
return bendyButt.decode(msgVal)
},

// used in ebt:stream to distinguish between messages and notes
isMsg(bbVal) {
if (!Buffer.isBuffer(bbVal)) return false

const msgVal = bendyButt.decode(bbVal)
return msgVal &&
Number.isInteger(msgVal.sequence) && msgVal.sequence > 0 &&
typeof msgVal.author == 'string' && msgVal.content
},
// used in ebt:events
getMsgAuthor(bbVal) {
//console.log("bb getMsgAuthor", Buffer.isBuffer(bbVal))
if (Buffer.isBuffer(bbVal))
return bendyButt.decode(bbVal).author
else
return bbVal.author
},
// used in ebt:events
getMsgSequence(bbVal) {
//console.log("bb getMsgSequence", Buffer.isBuffer(bbVal))
if (Buffer.isBuffer(bbVal))
return bendyButt.decode(bbVal).sequence
else
return bbVal.sequence
}
}

alice.ebt.registerFormat('bendybutt', bendyButtMethods)
bob.ebt.registerFormat('bendybutt', bendyButtMethods)

// self replicate
alice.ebt.request(alice.id, true)
bob.ebt.request(bob.id, true)

// publish normal messages
await Promise.all([
pify(alice.db.publish)({ type: 'post', text: 'hello' }),
pify(bob.db.publish)({ type: 'post', text: 'hello' })
])

function getBBMsg(mainKeys) {
// fake some keys
const mfKeys = ssbKeys.generate()
const classicUri = SSBURI.fromFeedSigil(mfKeys.id)
const { type, /* format, */ data } = SSBURI.decompose(classicUri)
const bendybuttUri = SSBURI.compose({ type, format: 'bendybutt-v1', data })
mfKeys.id = bendybuttUri

const content = {
type: "metafeed/add",
feedpurpose: "main",
subfeed: mainKeys.id,
metafeed: mfKeys.id,
tangles: {
metafeed: {
root: null,
previous: null
}
}
}

const bbmsg = bendyButt.encodeNew(
content,
mainKeys,
mfKeys,
1,
null,
Date.now(),
null
)

return bendyButt.decode(bbmsg)
}

const aliceBBMsg = getBBMsg(alice.config.keys)
const bobBBMsg = getBBMsg(bob.config.keys)

const aliceMFId = aliceBBMsg.author
const bobMFId = bobBBMsg.author

// self replicate
alice.ebt.request(aliceMFId, true, 'bendybutt')
bob.ebt.request(bobMFId, true, 'bendybutt')

await Promise.all([
pify(alice.add)(aliceBBMsg),
pify(bob.add)(bobBBMsg)
])

alice.ebt.request(bob.id, true)
alice.ebt.request(bobMFId, true, 'bendybutt')

bob.ebt.request(alice.id, true)
bob.ebt.request(aliceMFId, true, 'bendybutt')

await pify(bob.connect)(alice.getAddress())

await sleep(REPLICATION_TIMEOUT)
t.pass('wait for replication to complete')

const clockAlice = await pify(alice.ebt.clock)('classic')
const bbClockAlice = await pify(alice.ebt.clock)('bendybutt')

t.equal(clockAlice[alice.id], 1, 'clock ok')
t.equal(clockAlice[bob.id], 1, 'clock ok')

t.equal(bbClockAlice[aliceMFId], 1, 'clock ok')
t.equal(bbClockAlice[bobMFId], 1, 'clock ok')

const clockBob = await pify(bob.ebt.clock)('classic')
const bbClockBob = await pify(bob.ebt.clock)('bendybutt')

t.equal(clockBob[alice.id], 1, 'clock ok')
t.equal(clockBob[bob.id], 1, 'clock ok')

t.equal(bbClockBob[aliceMFId], 1, 'clock ok')
t.equal(bbClockBob[bobMFId], 1, 'clock ok')

await Promise.all([
pify(alice.close)(true),
pify(bob.close)(true)
])
t.end()
})

0 comments on commit 1c37be2

Please sign in to comment.