mirror of https://codeberg.org/pzp/pzp-sync.git
update to support msg-v2
This commit is contained in:
parent
37bdc344f3
commit
32c5b903b1
|
@ -1,5 +1,5 @@
|
||||||
const { BloomFilter } = require('bloom-filters')
|
const { BloomFilter } = require('bloom-filters')
|
||||||
const FeedV1 = require('ppppp-db/feed-v1')
|
const MsgV2 = require('ppppp-db/msg-v2')
|
||||||
const p = require('util').promisify
|
const p = require('util').promisify
|
||||||
const { isEmptyRange, estimateMsgCount } = require('./range')
|
const { isEmptyRange, estimateMsgCount } = require('./range')
|
||||||
const { parseGoal } = require('./goal')
|
const { parseGoal } = require('./goal')
|
||||||
|
@ -31,7 +31,7 @@ class Algorithm {
|
||||||
let minDepth = Number.MAX_SAFE_INTEGER
|
let minDepth = Number.MAX_SAFE_INTEGER
|
||||||
let maxDepth = 0
|
let maxDepth = 0
|
||||||
for (const rec of this.#peer.db.records()) {
|
for (const rec of this.#peer.db.records()) {
|
||||||
if (!rec.msg?.content) continue
|
if (!rec.msg?.data) continue
|
||||||
const tangles = rec.msg.metadata.tangles
|
const tangles = rec.msg.metadata.tangles
|
||||||
if (rec.hash === rootMsgHash) {
|
if (rec.hash === rootMsgHash) {
|
||||||
minDepth = 0
|
minDepth = 0
|
||||||
|
@ -105,7 +105,7 @@ class Algorithm {
|
||||||
const filter = BloomFilter.create(2 * filterSize, 0.00001)
|
const filter = BloomFilter.create(2 * filterSize, 0.00001)
|
||||||
if (!isEmptyRange(range)) {
|
if (!isEmptyRange(range)) {
|
||||||
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
|
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
|
||||||
filter.add('' + round + FeedV1.getMsgHash(msg))
|
filter.add('' + round + MsgV2.getMsgHash(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const msgId of extraIds) {
|
for (const msgId of extraIds) {
|
||||||
|
@ -119,7 +119,7 @@ class Algorithm {
|
||||||
const remoteFilter = BloomFilter.fromJSON(remoteBloomJSON)
|
const remoteFilter = BloomFilter.fromJSON(remoteBloomJSON)
|
||||||
const missing = []
|
const missing = []
|
||||||
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
|
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
|
||||||
const msgHash = FeedV1.getMsgHash(msg)
|
const msgHash = MsgV2.getMsgHash(msg)
|
||||||
if (!remoteFilter.has('' + round + msgHash)) {
|
if (!remoteFilter.has('' + round + msgHash)) {
|
||||||
missing.push(msgHash)
|
missing.push(msgHash)
|
||||||
}
|
}
|
||||||
|
@ -161,16 +161,19 @@ class Algorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
async commit(rootMsgHash, newMsgs, goal, myWantRange) {
|
async commit(rootMsgHash, newMsgs, goal, myWantRange) {
|
||||||
// Filter out contentful newMsgs that are not in my want-range
|
// Filter out dataful newMsgs that are not in my want-range
|
||||||
const [minWant, maxWant] = myWantRange
|
const [minWant, maxWant] = myWantRange
|
||||||
const validNewMsgs = newMsgs
|
const validNewMsgs = newMsgs
|
||||||
.filter((msg) => {
|
.filter((msg) => {
|
||||||
if (!msg.content) return true // contentless messages are always valid
|
|
||||||
const depth = msg.metadata.tangles[rootMsgHash]?.depth ?? 0
|
const depth = msg.metadata.tangles[rootMsgHash]?.depth ?? 0
|
||||||
if (depth === 0 && FeedV1.getMsgHash(msg) !== rootMsgHash) {
|
if (depth === 0 && MsgV2.getMsgHash(msg) !== rootMsgHash) {
|
||||||
return false // the rootMsg is the only acceptable depth-zero msg
|
return false // the rootMsg is the only acceptable depth-zero msg
|
||||||
}
|
}
|
||||||
|
if (!msg.data) {
|
||||||
|
return depth < minWant
|
||||||
|
} else {
|
||||||
return minWant <= depth && depth <= maxWant
|
return minWant <= depth && depth <= maxWant
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const aDepth = a.metadata.tangles[rootMsgHash]?.depth ?? 0
|
const aDepth = a.metadata.tangles[rootMsgHash]?.depth ?? 0
|
||||||
|
@ -178,14 +181,11 @@ class Algorithm {
|
||||||
return aDepth - bDepth
|
return aDepth - bDepth
|
||||||
})
|
})
|
||||||
|
|
||||||
// Simulate adding this whole tangle, and check if it's valid
|
// TODO: Simulate adding this whole tangle, and check if it's valid
|
||||||
let err
|
|
||||||
if ((err = this.#peer.db.validateTangle(rootMsgHash, validNewMsgs))) {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new messages TODO: optimize perf, avoiding await / try / catch
|
// Add new messages
|
||||||
for (const msg of newMsgs) {
|
// TODO: optimize perf, avoiding await / try / catch
|
||||||
|
for (const msg of validNewMsgs) {
|
||||||
try {
|
try {
|
||||||
await p(this.#peer.db.add)(msg, rootMsgHash)
|
await p(this.#peer.db.add)(msg, rootMsgHash)
|
||||||
} catch {}
|
} catch {}
|
||||||
|
@ -222,7 +222,7 @@ class Algorithm {
|
||||||
const msg = this.#peer.db.get(msgHash)
|
const msg = this.#peer.db.get(msgHash)
|
||||||
if (!msg) continue
|
if (!msg) continue
|
||||||
if (isErasable) {
|
if (isErasable) {
|
||||||
msgs.push({ ...msg, content: null })
|
msgs.push({ ...msg, data: null })
|
||||||
} else {
|
} else {
|
||||||
msgs.push(msg)
|
msgs.push(msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const toPull = require('push-stream-to-pull-stream')
|
const toPull = require('push-stream-to-pull-stream')
|
||||||
const pull = require('pull-stream')
|
const pull = require('pull-stream')
|
||||||
const FeedV1 = require('ppppp-db/feed-v1')
|
|
||||||
const makeDebug = require('debug')
|
const makeDebug = require('debug')
|
||||||
const getSeverity = require('ssb-network-errors')
|
const getSeverity = require('ssb-network-errors')
|
||||||
const Algorithm = require('./algorithm')
|
const Algorithm = require('./algorithm')
|
||||||
|
@ -75,11 +74,6 @@ module.exports = {
|
||||||
goals.set(tangleId, goal)
|
goals.set(tangleId, goal)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFeedGoal(author, type, goal = 'all') {
|
|
||||||
const tangleId = FeedV1.getFeedRootHash(author, type)
|
|
||||||
goals.set(tangleId, goal)
|
|
||||||
}
|
|
||||||
|
|
||||||
function initiate() {
|
function initiate() {
|
||||||
for (const stream of streams) {
|
for (const stream of streams) {
|
||||||
stream.initiate()
|
stream.initiate()
|
||||||
|
@ -89,7 +83,6 @@ module.exports = {
|
||||||
return {
|
return {
|
||||||
connect,
|
connect,
|
||||||
setGoal,
|
setGoal,
|
||||||
setFeedGoal,
|
|
||||||
initiate,
|
initiate,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bs58": "^5.0.0",
|
"bs58": "^5.0.0",
|
||||||
"c8": "7",
|
"c8": "7",
|
||||||
"ppppp-db": "github:staltz/ppppp-db",
|
"ppppp-db": "github:staltz/ppppp-db#msgv2",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"rimraf": "^4.4.0",
|
"rimraf": "^4.4.0",
|
||||||
|
|
|
@ -4,7 +4,7 @@ const os = require('os')
|
||||||
const rimraf = require('rimraf')
|
const rimraf = require('rimraf')
|
||||||
const SecretStack = require('secret-stack')
|
const SecretStack = require('secret-stack')
|
||||||
const caps = require('ssb-caps')
|
const caps = require('ssb-caps')
|
||||||
const FeedV1 = require('ppppp-db/feed-v1')
|
const MsgV2 = require('ppppp-db/msg-v2')
|
||||||
const p = require('util').promisify
|
const p = require('util').promisify
|
||||||
const Algorithm = require('../lib/algorithm')
|
const Algorithm = require('../lib/algorithm')
|
||||||
const { generateKeypair } = require('./util')
|
const { generateKeypair } = require('./util')
|
||||||
|
@ -34,34 +34,45 @@ test('sync a feed with goal=all', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
await bob.db.loaded()
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
const carolKeys = generateKeypair('carol')
|
const carolKeys = generateKeypair('carol')
|
||||||
|
const carolGroupMsg0 = MsgV2.createGroup(carolKeys, 'carol')
|
||||||
|
const carolId = MsgV2.getMsgHash(carolGroupMsg0)
|
||||||
|
await p(alice.db.add)(carolGroupMsg0, carolId)
|
||||||
|
await p(bob.db.add)(carolGroupMsg0, carolId)
|
||||||
|
|
||||||
const carolMsgs = []
|
const carolMsgs = []
|
||||||
const carolID = carolKeys.id
|
|
||||||
const carolID_b58 = FeedV1.stripAuthor(carolID)
|
|
||||||
for (let i = 1; i <= 10; i++) {
|
for (let i = 1; i <= 10; i++) {
|
||||||
const rec = await p(alice.db.create)({
|
const rec = await p(alice.db.feed.publish)({
|
||||||
|
group: carolId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'm' + i },
|
data: { text: 'm' + i },
|
||||||
keys: carolKeys,
|
keys: carolKeys,
|
||||||
})
|
})
|
||||||
carolMsgs.push(rec.msg)
|
carolMsgs.push(rec.msg)
|
||||||
}
|
}
|
||||||
t.pass('alice has msgs 1..10 from carol')
|
t.pass('alice has msgs 1..10 from carol')
|
||||||
|
|
||||||
const carolRootHash = alice.db.getFeedRoot(carolID, 'post')
|
const carolPostsRootHash = alice.db.feed.getRoot(carolId, 'post')
|
||||||
const carolRootMsg = alice.db.get(carolRootHash)
|
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
|
||||||
|
|
||||||
await p(bob.db.add)(carolRootMsg, carolRootHash)
|
await p(bob.db.add)(carolPostsRootMsg, carolPostsRootHash)
|
||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
await p(bob.db.add)(carolMsgs[i], carolRootHash)
|
await p(bob.db.add)(carolMsgs[i], carolPostsRootHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7'],
|
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7'],
|
||||||
|
@ -69,8 +80,8 @@ test('sync a feed with goal=all', async (t) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bob.tangleSync.setGoal(carolRootHash, 'all')
|
bob.tangleSync.setGoal(carolPostsRootHash, 'all')
|
||||||
alice.tangleSync.setGoal(carolRootHash, 'all')
|
alice.tangleSync.setGoal(carolPostsRootHash, 'all')
|
||||||
|
|
||||||
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
||||||
t.pass('bob connected to alice')
|
t.pass('bob connected to alice')
|
||||||
|
@ -81,8 +92,8 @@ test('sync a feed with goal=all', async (t) => {
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9', 'm10'],
|
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9', 'm10'],
|
||||||
|
@ -110,34 +121,45 @@ test('sync a feed with goal=newest', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
await bob.db.loaded()
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
const carolKeys = generateKeypair('carol')
|
const carolKeys = generateKeypair('carol')
|
||||||
|
const carolGroupMsg0 = MsgV2.createGroup(carolKeys, 'carol')
|
||||||
|
const carolId = MsgV2.getMsgHash(carolGroupMsg0)
|
||||||
|
await p(alice.db.add)(carolGroupMsg0, carolId)
|
||||||
|
await p(bob.db.add)(carolGroupMsg0, carolId)
|
||||||
|
|
||||||
const carolMsgs = []
|
const carolMsgs = []
|
||||||
const carolID = carolKeys.id
|
|
||||||
const carolID_b58 = FeedV1.stripAuthor(carolID)
|
|
||||||
for (let i = 1; i <= 10; i++) {
|
for (let i = 1; i <= 10; i++) {
|
||||||
const rec = await p(alice.db.create)({
|
const rec = await p(alice.db.feed.publish)({
|
||||||
|
group: carolId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'm' + i },
|
data: { text: 'm' + i },
|
||||||
keys: carolKeys,
|
keys: carolKeys,
|
||||||
})
|
})
|
||||||
carolMsgs.push(rec.msg)
|
carolMsgs.push(rec.msg)
|
||||||
}
|
}
|
||||||
t.pass('alice has msgs 1..10 from carol')
|
t.pass('alice has msgs 1..10 from carol')
|
||||||
|
|
||||||
const carolRootHash = alice.db.getFeedRoot(carolID, 'post')
|
const carolPostsRootHash = alice.db.feed.getRoot(carolId, 'post')
|
||||||
const carolRootMsg = alice.db.get(carolRootHash)
|
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
|
||||||
|
|
||||||
await p(bob.db.add)(carolRootMsg, carolRootHash)
|
await p(bob.db.add)(carolPostsRootMsg, carolPostsRootHash)
|
||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
await p(bob.db.add)(carolMsgs[i], carolRootHash)
|
await p(bob.db.add)(carolMsgs[i], carolPostsRootHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7'],
|
['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7'],
|
||||||
|
@ -145,8 +167,8 @@ test('sync a feed with goal=newest', async (t) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bob.tangleSync.setGoal(carolRootHash, 'newest-5')
|
bob.tangleSync.setGoal(carolPostsRootHash, 'newest-5')
|
||||||
alice.tangleSync.setGoal(carolRootHash, 'all')
|
alice.tangleSync.setGoal(carolPostsRootHash, 'all')
|
||||||
|
|
||||||
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
||||||
t.pass('bob connected to alice')
|
t.pass('bob connected to alice')
|
||||||
|
@ -157,8 +179,8 @@ test('sync a feed with goal=newest', async (t) => {
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m6', 'm7', 'm8', 'm9', 'm10'],
|
['m6', 'm7', 'm8', 'm9', 'm10'],
|
||||||
|
@ -186,30 +208,41 @@ test('sync a feed with goal=newest but too far behind', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
await bob.db.loaded()
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
const carolKeys = generateKeypair('carol')
|
const carolKeys = generateKeypair('carol')
|
||||||
|
const carolGroupMsg0 = MsgV2.createGroup(carolKeys, 'carol')
|
||||||
|
const carolId = MsgV2.getMsgHash(carolGroupMsg0)
|
||||||
|
await p(alice.db.add)(carolGroupMsg0, carolId)
|
||||||
|
await p(bob.db.add)(carolGroupMsg0, carolId)
|
||||||
|
|
||||||
const carolMsgs = []
|
const carolMsgs = []
|
||||||
const carolID = carolKeys.id
|
|
||||||
const carolID_b58 = FeedV1.stripAuthor(carolID)
|
|
||||||
for (let i = 1; i <= 10; i++) {
|
for (let i = 1; i <= 10; i++) {
|
||||||
const rec = await p(alice.db.create)({
|
const rec = await p(alice.db.feed.publish)({
|
||||||
|
group: carolId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'm' + i },
|
data: { text: 'm' + i },
|
||||||
keys: carolKeys,
|
keys: carolKeys,
|
||||||
})
|
})
|
||||||
carolMsgs.push(rec.msg)
|
carolMsgs.push(rec.msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
const carolRootHash = alice.db.getFeedRoot(carolID, 'post')
|
const carolPostsRootHash = alice.db.feed.getRoot(carolId, 'post')
|
||||||
const carolRootMsg = alice.db.get(carolRootHash)
|
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
|
||||||
|
|
||||||
const algo = new Algorithm(alice)
|
const algo = new Algorithm(alice)
|
||||||
await algo.pruneNewest(carolRootHash, 5)
|
await algo.pruneNewest(carolPostsRootHash, 5)
|
||||||
{
|
{
|
||||||
const arr = [...alice.db.msgs()]
|
const arr = [...alice.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m6', 'm7', 'm8', 'm9', 'm10'],
|
['m6', 'm7', 'm8', 'm9', 'm10'],
|
||||||
|
@ -217,20 +250,20 @@ test('sync a feed with goal=newest but too far behind', async (t) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await p(bob.db.add)(carolRootMsg, carolRootHash)
|
await p(bob.db.add)(carolPostsRootMsg, carolPostsRootHash)
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
await p(bob.db.add)(carolMsgs[i], carolRootHash)
|
await p(bob.db.add)(carolMsgs[i], carolPostsRootHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(arr, ['m1', 'm2'], 'bob has msgs 1..2 from carol')
|
t.deepEquals(arr, ['m1', 'm2'], 'bob has msgs 1..2 from carol')
|
||||||
}
|
}
|
||||||
|
|
||||||
alice.tangleSync.setFeedGoal(carolID, 'post', 'newest-5')
|
alice.tangleSync.setGoal(carolPostsRootHash, 'newest-5')
|
||||||
bob.tangleSync.setFeedGoal(carolID, 'post', 'newest-5')
|
bob.tangleSync.setGoal(carolPostsRootHash, 'newest-5')
|
||||||
|
|
||||||
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
const remoteAlice = await p(bob.connect)(alice.getAddress())
|
||||||
t.pass('bob connected to alice')
|
t.pass('bob connected to alice')
|
||||||
|
@ -241,8 +274,8 @@ test('sync a feed with goal=newest but too far behind', async (t) => {
|
||||||
|
|
||||||
{
|
{
|
||||||
const arr = [...bob.db.msgs()]
|
const arr = [...bob.db.msgs()]
|
||||||
.filter((msg) => msg.metadata.who === carolID_b58 && msg.content)
|
.filter((msg) => msg.metadata.group === carolId && msg.data)
|
||||||
.map((msg) => msg.content.text)
|
.map((msg) => msg.data.text)
|
||||||
t.deepEquals(
|
t.deepEquals(
|
||||||
arr,
|
arr,
|
||||||
['m6', 'm7', 'm8', 'm9', 'm10'],
|
['m6', 'm7', 'm8', 'm9', 'm10'],
|
||||||
|
|
|
@ -4,6 +4,7 @@ const os = require('os')
|
||||||
const rimraf = require('rimraf')
|
const rimraf = require('rimraf')
|
||||||
const SecretStack = require('secret-stack')
|
const SecretStack = require('secret-stack')
|
||||||
const caps = require('ssb-caps')
|
const caps = require('ssb-caps')
|
||||||
|
const MsgV2 = require('ppppp-db/msg-v2')
|
||||||
const p = require('util').promisify
|
const p = require('util').promisify
|
||||||
const { generateKeypair } = require('./util')
|
const { generateKeypair } = require('./util')
|
||||||
|
|
||||||
|
@ -18,7 +19,9 @@ const aliceKeys = generateKeypair('alice')
|
||||||
const bobKeys = generateKeypair('bob')
|
const bobKeys = generateKeypair('bob')
|
||||||
|
|
||||||
function getTexts(iter) {
|
function getTexts(iter) {
|
||||||
return [...iter].filter((msg) => msg.content).map((msg) => msg.content.text)
|
return [...iter]
|
||||||
|
.filter((msg) => msg.metadata.group && msg.data)
|
||||||
|
.map((msg) => msg.data.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -72,56 +75,80 @@ test('sync a thread where both peers have portions', async (t) => {
|
||||||
path: BOB_DIR,
|
path: BOB_DIR,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await alice.db.loaded()
|
||||||
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
const carolKeys = generateKeypair('carol')
|
const carolKeys = generateKeypair('carol')
|
||||||
const carolID = carolKeys.id
|
const carolGroupMsg0 = MsgV2.createGroup(carolKeys, 'carol')
|
||||||
|
const carolId = MsgV2.getMsgHash(carolGroupMsg0)
|
||||||
|
|
||||||
const daveKeys = generateKeypair('dave')
|
const daveKeys = generateKeypair('dave')
|
||||||
const daveID = daveKeys.id
|
const daveGroupMsg0 = MsgV2.createGroup(daveKeys, 'dave')
|
||||||
|
const daveId = MsgV2.getMsgHash(daveGroupMsg0)
|
||||||
|
|
||||||
await alice.db.loaded()
|
// Alice knows Bob, Carol, and Dave
|
||||||
await bob.db.loaded()
|
await p(alice.db.add)(bobGroupMsg0, bobId)
|
||||||
|
await p(alice.db.add)(carolGroupMsg0, carolId)
|
||||||
|
await p(alice.db.add)(daveGroupMsg0, daveId)
|
||||||
|
|
||||||
const startA = await p(alice.db.create)({
|
// Bob knows Alice, Carol, and Dave
|
||||||
|
await p(bob.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
await p(bob.db.add)(carolGroupMsg0, carolId)
|
||||||
|
await p(bob.db.add)(daveGroupMsg0, daveId)
|
||||||
|
|
||||||
|
const startA = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A' },
|
data: { text: 'A' },
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
const rootHashA = alice.db.getFeedRoot(aliceKeys.id, 'post')
|
const rootHashA = alice.db.feed.getRoot(aliceId, 'post')
|
||||||
const rootMsgA = alice.db.get(rootHashA)
|
const rootMsgA = alice.db.get(rootHashA)
|
||||||
|
|
||||||
await p(bob.db.add)(rootMsgA, rootHashA)
|
await p(bob.db.add)(rootMsgA, rootHashA)
|
||||||
await p(bob.db.add)(startA.msg, rootHashA)
|
await p(bob.db.add)(startA.msg, rootHashA)
|
||||||
|
|
||||||
const replyB1 = await p(bob.db.create)({
|
const replyB1 = await p(bob.db.feed.publish)({
|
||||||
|
group: bobId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'B1' },
|
data: { text: 'B1' },
|
||||||
tangles: [startA.hash],
|
tangles: [startA.hash],
|
||||||
keys: bobKeys,
|
keys: bobKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyB2 = await p(bob.db.create)({
|
const replyB2 = await p(bob.db.feed.publish)({
|
||||||
|
group: bobId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'B2' },
|
data: { text: 'B2' },
|
||||||
tangles: [startA.hash],
|
tangles: [startA.hash],
|
||||||
keys: bobKeys,
|
keys: bobKeys,
|
||||||
})
|
})
|
||||||
const rootHashB = bob.db.getFeedRoot(bobKeys.id, 'post')
|
const rootHashB = bob.db.feed.getRoot(bobId, 'post')
|
||||||
const rootMsgB = bob.db.get(rootHashB)
|
const rootMsgB = bob.db.get(rootHashB)
|
||||||
|
|
||||||
await p(alice.db.add)(rootMsgB, rootHashB)
|
await p(alice.db.add)(rootMsgB, rootHashB)
|
||||||
await p(alice.db.add)(replyB1.msg, rootHashB)
|
await p(alice.db.add)(replyB1.msg, rootHashB)
|
||||||
await p(alice.db.add)(replyB2.msg, rootHashB)
|
await p(alice.db.add)(replyB2.msg, rootHashB)
|
||||||
|
|
||||||
const replyC1 = await p(alice.db.create)({
|
const replyC1 = await p(alice.db.feed.publish)({
|
||||||
|
group: carolId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'C1' },
|
data: { text: 'C1' },
|
||||||
tangles: [startA.hash],
|
tangles: [startA.hash],
|
||||||
keys: carolKeys,
|
keys: carolKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyD1 = await p(bob.db.create)({
|
const replyD1 = await p(bob.db.feed.publish)({
|
||||||
|
group: daveId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'D1' },
|
data: { text: 'D1' },
|
||||||
tangles: [startA.hash],
|
tangles: [startA.hash],
|
||||||
keys: daveKeys,
|
keys: daveKeys,
|
||||||
})
|
})
|
||||||
|
@ -180,24 +207,40 @@ test('sync a thread where initiator does not have the root', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
await bob.db.loaded()
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
const rootA = await p(alice.db.create)({
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
|
// Alice knows Bob
|
||||||
|
await p(alice.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
|
// Bob knows Alice
|
||||||
|
await p(bob.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
|
const rootA = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A' },
|
data: { text: 'A' },
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA1 = await p(alice.db.create)({
|
const replyA1 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A1' },
|
data: { text: 'A1' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA2 = await p(alice.db.create)({
|
const replyA2 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A2' },
|
data: { text: 'A2' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
@ -247,24 +290,40 @@ test('sync a thread where receiver does not have the root', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
await bob.db.loaded()
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
const rootA = await p(alice.db.create)({
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
|
// Alice knows Bob
|
||||||
|
await p(alice.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
|
// Bob knows Alice
|
||||||
|
await p(bob.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
|
const rootA = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A' },
|
data: { text: 'A' },
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA1 = await p(alice.db.create)({
|
const replyA1 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A1' },
|
data: { text: 'A1' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA2 = await p(alice.db.create)({
|
const replyA2 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A2' },
|
data: { text: 'A2' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
@ -313,31 +372,48 @@ test('sync a thread with reactions too', async (t) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
await alice.db.loaded()
|
await alice.db.loaded()
|
||||||
|
const aliceGroupMsg0 = MsgV2.createGroup(aliceKeys, 'alice')
|
||||||
|
const aliceId = MsgV2.getMsgHash(aliceGroupMsg0)
|
||||||
|
await p(alice.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
await bob.db.loaded()
|
await bob.db.loaded()
|
||||||
|
const bobGroupMsg0 = MsgV2.createGroup(bobKeys, 'bob')
|
||||||
|
const bobId = MsgV2.getMsgHash(bobGroupMsg0)
|
||||||
|
await p(bob.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
const rootA = await p(alice.db.create)({
|
// Alice knows Bob
|
||||||
|
await p(alice.db.add)(bobGroupMsg0, bobId)
|
||||||
|
|
||||||
|
// Bob knows Alice
|
||||||
|
await p(bob.db.add)(aliceGroupMsg0, aliceId)
|
||||||
|
|
||||||
|
const rootA = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A' },
|
data: { text: 'A' },
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA1 = await p(alice.db.create)({
|
const replyA1 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A1' },
|
data: { text: 'A1' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const replyA2 = await p(alice.db.create)({
|
const replyA2 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'post',
|
type: 'post',
|
||||||
content: { text: 'A2' },
|
data: { text: 'A2' },
|
||||||
tangles: [rootA.hash],
|
tangles: [rootA.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
||||||
const reactionA3 = await p(alice.db.create)({
|
const reactionA3 = await p(alice.db.feed.publish)({
|
||||||
|
group: aliceId,
|
||||||
type: 'reaction',
|
type: 'reaction',
|
||||||
content: { text: 'yes', link: replyA1.hash },
|
data: { text: 'yes', link: replyA1.hash },
|
||||||
tangles: [rootA.hash, replyA1.hash],
|
tangles: [rootA.hash, replyA1.hash],
|
||||||
keys: aliceKeys,
|
keys: aliceKeys,
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@ const base58 = require('bs58')
|
||||||
function generateKeypair(seed) {
|
function generateKeypair(seed) {
|
||||||
const keys = ssbKeys.generate('ed25519', seed, 'buttwoo-v1')
|
const keys = ssbKeys.generate('ed25519', seed, 'buttwoo-v1')
|
||||||
const { data } = SSBURI.decompose(keys.id)
|
const { data } = SSBURI.decompose(keys.id)
|
||||||
keys.id = `ppppp:feed/v1/${base58.encode(Buffer.from(data, 'base64'))}`
|
keys.id = base58.encode(Buffer.from(data, 'base64'))
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue