From 8ebeb0fb12de766fac21f8292121307cf7d1bd1e Mon Sep 17 00:00:00 2001 From: Andre Staltz Date: Wed, 21 Feb 2024 11:31:58 +0200 Subject: [PATCH] fix calculation of dict/set feedIDs --- lib/index.js | 61 +++++++++++++++++++++++---------------- test/follow-feeds.test.js | 42 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 25 deletions(-) diff --git a/lib/index.js b/lib/index.js index 39bdeeb..db49fb2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -118,7 +118,10 @@ function initConductor(peer, config) { * @returns {[Array, Array]} */ function validateRules(rules, numFollowed, maxBytes) { - const [myRules, theirRules] = rules + // prettier-ignore + if (!Array.isArray(rules)) throw new Error('conductor.start expects array of rules') + const myRules = rules[0] ?? [] + const theirRules = rules[1] ?? [] let estimateMsgCount = (1 + numFollowed) * ESTIMATE_FOLLOWS_FEED_SIZE + ESTIMATE_BLOCK_FEED_SIZE @@ -144,10 +147,30 @@ function initConductor(peer, config) { return [myRules, theirRules] } + /** + * @param {string} accountID + * @param {Rule} rule + * @return {[string, GoalDSL]} + */ + function materializeRule(accountID, rule) { + const [subdomain, goalDSL] = parseRule(rule) + // prettier-ignore + if (goalDSL === 'dict' && !peer.dict) throw new Error('Cannot parse dict rule because dict plugin is not installed') + const domain = + goalDSL === 'set' + ? peer.set.getDomain(subdomain) + : goalDSL === 'dict' && peer.dict + ? peer.dict.getDomain(subdomain) + : subdomain + const feedID = peer.db.feed.getID(accountID, domain) + return [feedID, goalDSL] + } + /** * Set replication goals for various tangles of an account: * - Account tangle - * - Follow tangle (a Set) + * - Follows tangle (a Set) + * - Blocks tangle (a Set) * - Each tangle in the rule * * The "rule" is just a list of domains of feeds. @@ -157,47 +180,35 @@ function initConductor(peer, config) { function setupAccountGoals(accountID, rules) { peer.goals.set(accountID, 'all') - const followsDomain = peer.set.getDomain('follows') - const followsFeedID = peer.db.feed.getID(accountID, followsDomain) - peer.goals.set(followsFeedID, 'set') + /** @type {Array} */ + const allRules = ['follows@set', 'blocks@set', ...rules] - const blocksDomain = peer.set.getDomain('blocks') - const blocksFeedID = peer.db.feed.getID(accountID, blocksDomain) - peer.goals.set(blocksFeedID, 'set') - - for (const rule of rules) { - const [domain, goalDSL] = parseRule(rule) - const feedID = peer.db.feed.getID(accountID, domain) + for (const rule of allRules) { + const [feedID, goalDSL] = materializeRule(accountID, rule) peer.goals.set(feedID, goalDSL) } // prettier-ignore - debug('Setup goals for %s@all, %s@set, %s@set, %s', accountID, followsDomain, blocksDomain, rules.join(', ')) + debug('Setup goals for %s@all, %s@set, %s@set, %s', accountID, allRules.join(', ')) } /** * @param {string} accountID - * @param {Array} rules + * @param {Array} rules */ function teardownAccountGoals(accountID, rules) { peer.goals.set(accountID, 'none') - const followsDomain = peer.set.getDomain('follows') - const followsFeedID = peer.db.feed.getID(accountID, followsDomain) - peer.goals.set(followsFeedID, 'none') + /** @type {Array} */ + const allRules = ['follows@set', 'blocks@set', ...rules] - const blocksDomain = peer.set.getDomain('blocks') - const blocksFeedID = peer.db.feed.getID(accountID, blocksDomain) - peer.goals.set(blocksFeedID, 'none') - - for (const rule of rules) { - const [domain] = parseRule(rule) - const feedID = peer.db.feed.getID(accountID, domain) + for (const rule of allRules) { + const [feedID] = materializeRule(accountID, rule) peer.goals.set(feedID, 'none') } // prettier-ignore - debug('Teardown goals for %s@all, %s@set, %s@set, %s', accountID, followsDomain, blocksDomain, rules.join(', ')) + debug('Teardown goals for %s@all, %s@set, %s@set, %s', accountID, allRules.join(', ')) } /** diff --git a/test/follow-feeds.test.js b/test/follow-feeds.test.js index 595bf46..d665b41 100644 --- a/test/follow-feeds.test.js +++ b/test/follow-feeds.test.js @@ -7,6 +7,48 @@ function getTexts(msgs) { return msgs.filter((msg) => msg.data?.text).map((msg) => msg.data.text) } +test('Sets goals according to input rules', async (t) => { + // Alice + const alice = createPeer({ name: 'alice' }) + await alice.db.loaded() + // Alice creates her own account + const aliceID = await p(alice.db.account.create)({ + subdomain: 'account', + _nonce: 'alice', + }) + await p(alice.set.load)(aliceID) + + alice.conductor.start( + aliceID, + [['posts@newest-100', 'hubs@set', 'profile@dict']], + 64_000_000 + ) + + const goals = [...alice.goals.list()] + assert.equal(goals.length, 6, 'alice has 6 goals') + + assert.equal(goals[0].type, 'all') + assert.equal(goals[0].id, aliceID) + + assert.equal(goals[1].type, 'set') + assert.equal(goals[1].id, alice.db.feed.getID(aliceID, alice.set.getDomain('follows'))) + + assert.equal(goals[2].type, 'set') + assert.equal(goals[2].id, alice.db.feed.getID(aliceID, alice.set.getDomain('blocks'))) + + assert.equal(goals[3].type, 'newest') + assert.equal(goals[3].count, 100) + assert.equal(goals[3].id, alice.db.feed.getID(aliceID, 'posts')) + + assert.equal(goals[4].type, 'set') + assert.equal(goals[4].id, alice.db.feed.getID(aliceID, alice.set.getDomain('hubs'))) + + assert.equal(goals[5].type, 'dict') + assert.equal(goals[5].id, alice.db.feed.getID(aliceID, alice.dict.getDomain('profile'))) + + await p(alice.close)(true) +}) + test('Replicate selected feeds of followed accounts', async (t) => { // Alice const alice = createPeer({ name: 'alice' })