API allows determining goals for each domain
This commit is contained in:
parent
5a1b4347de
commit
f539fc3316
42
lib/index.js
42
lib/index.js
|
@ -1,10 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* @typedef {ReturnType<import('ppppp-db').init>} PPPPPDB
|
* @typedef {ReturnType<import('ppppp-db').init>} PPPPPDB
|
||||||
* @typedef {ReturnType<import('ppppp-goals').init>} PPPPPGoal
|
* @typedef {ReturnType<import('ppppp-goals').init>} PPPPPGoal
|
||||||
|
* @typedef {import('ppppp-goals').GoalDSL} GoalDSL
|
||||||
* @typedef {ReturnType<import('ppppp-set').init>} PPPPPSet
|
* @typedef {ReturnType<import('ppppp-set').init>} PPPPPSet
|
||||||
* @typedef {ReturnType<import('ppppp-sync').init>} PPPPPSync
|
* @typedef {ReturnType<import('ppppp-sync').init>} PPPPPSync
|
||||||
* @typedef {ReturnType<import('ppppp-gc').init>} PPPPPGC
|
* @typedef {ReturnType<import('ppppp-gc').init>} PPPPPGC
|
||||||
* @typedef {[Array<string>, Array<string>]} Rules
|
* @typedef {`${string}@${GoalDSL}`} Rule
|
||||||
|
* @typedef {[Array<Rule>, Array<Rule>]} Rules
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* db:PPPPPDB | null,
|
* db:PPPPPDB | null,
|
||||||
* goals: PPPPPGoal | null,
|
* goals: PPPPPGoal | null,
|
||||||
|
@ -54,6 +56,20 @@ function assertSyncPlugin(peer) {
|
||||||
if (!peer.sync) throw new Error('conductor plugin needs ppppp-sync plugin')
|
if (!peer.sync) throw new Error('conductor plugin needs ppppp-sync plugin')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} rule
|
||||||
|
* @returns {[string, GoalDSL]}
|
||||||
|
*/
|
||||||
|
function parseRule(rule) {
|
||||||
|
if (typeof rule !== 'string') throw new Error('rule must be a string')
|
||||||
|
if (!rule) throw new Error('rule must not be empty')
|
||||||
|
if (!rule.includes('@')) throw new Error('rule fit the format "domain@goal"')
|
||||||
|
const splitted = /**@type {[string, GoalDSL]}*/ (rule.split('@'))
|
||||||
|
if (!splitted[0]) throw new Error('rule must fit the format "domain@goal"')
|
||||||
|
if (!splitted[1]) throw new Error('rule must fit the format "domain@goal"')
|
||||||
|
return splitted
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {UnknownPeer} peer
|
* @param {UnknownPeer} peer
|
||||||
* @param {unknown} config
|
* @param {unknown} config
|
||||||
|
@ -72,10 +88,10 @@ function initConductor(peer, config) {
|
||||||
* - Each tangle in the rule
|
* - Each tangle in the rule
|
||||||
*
|
*
|
||||||
* The "rule" is just a list of domains of feeds.
|
* The "rule" is just a list of domains of feeds.
|
||||||
* @param {string} accountID
|
* @param {string} accountID ID of the account to set goals for
|
||||||
* @param {Array<string>} rule
|
* @param {Array<Rule>} rules list of feed domains of interest
|
||||||
*/
|
*/
|
||||||
function setupAccountGoals(accountID, rule) {
|
function setupAccountGoals(accountID, rules) {
|
||||||
assertDBPlugin(peer)
|
assertDBPlugin(peer)
|
||||||
assertSetPlugin(peer)
|
assertSetPlugin(peer)
|
||||||
assertGoalsPlugin(peer)
|
assertGoalsPlugin(peer)
|
||||||
|
@ -86,9 +102,14 @@ function initConductor(peer, config) {
|
||||||
const followFeedID = peer.db.feed.getID(accountID, followDomain)
|
const followFeedID = peer.db.feed.getID(accountID, followDomain)
|
||||||
peer.goals.set(followFeedID, 'set')
|
peer.goals.set(followFeedID, 'set')
|
||||||
|
|
||||||
for (const domain of rule) {
|
const blockDomain = peer.set.getDomain('block')
|
||||||
|
const blockFeedID = peer.db.feed.getID(accountID, blockDomain)
|
||||||
|
peer.goals.set(blockFeedID, 'set')
|
||||||
|
|
||||||
|
for (const rule of rules) {
|
||||||
|
const [domain, goalDSL] = parseRule(rule)
|
||||||
const feedID = peer.db.feed.getID(accountID, domain)
|
const feedID = peer.db.feed.getID(accountID, domain)
|
||||||
peer.goals.set(feedID, 'all') // TODO better goal?
|
peer.goals.set(feedID, goalDSL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +118,7 @@ function initConductor(peer, config) {
|
||||||
* Assumes that PPPPP Set has been loaded with the same accountID.
|
* Assumes that PPPPP Set has been loaded with the same accountID.
|
||||||
*
|
*
|
||||||
* @param {string} myID
|
* @param {string} myID
|
||||||
* @param {Rules} rules
|
* @param {[Array<Rule>, Array<Rule>]} rules
|
||||||
* @param {number} maxBytes
|
* @param {number} maxBytes
|
||||||
*/
|
*/
|
||||||
function start(myID, rules, maxBytes) {
|
function start(myID, rules, maxBytes) {
|
||||||
|
@ -107,20 +128,21 @@ function initConductor(peer, config) {
|
||||||
assertGCPlugin(peer)
|
assertGCPlugin(peer)
|
||||||
assertSyncPlugin(peer)
|
assertSyncPlugin(peer)
|
||||||
|
|
||||||
const [myRule, theirRule] = rules
|
const [myRules, theirRules] = rules
|
||||||
|
|
||||||
// TODO: Figure out goals for each tangle, and sizes according to maxLogBytes
|
// TODO: Figure out goals for each tangle, and sizes according to maxLogBytes
|
||||||
// TODO: Figure out ghost spans for dicts and sets
|
// TODO: Figure out ghost spans for dicts and sets
|
||||||
|
|
||||||
setupAccountGoals(myID, myRule)
|
setupAccountGoals(myID, myRules)
|
||||||
|
|
||||||
// TODO: watch the set for live updates, on add, syncAccount()
|
// TODO: watch the set for live updates, on add, syncAccount()
|
||||||
// TODO: watch the set for live updates, on remove, forgetAccount()
|
// TODO: watch the set for live updates, on remove, forgetAccount()
|
||||||
const followedAccounts = peer.set.values('follow')
|
const followedAccounts = peer.set.values('follow')
|
||||||
for (const theirID of followedAccounts) {
|
for (const theirID of followedAccounts) {
|
||||||
setupAccountGoals(theirID, theirRule)
|
setupAccountGoals(theirID, theirRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peer.gc.stop()
|
||||||
peer.gc.start(maxBytes)
|
peer.gc.start(maxBytes)
|
||||||
peer.sync.start()
|
peer.sync.start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,11 @@
|
||||||
"c8": "7",
|
"c8": "7",
|
||||||
"ppppp-caps": "github:staltz/ppppp-caps",
|
"ppppp-caps": "github:staltz/ppppp-caps",
|
||||||
"ppppp-db": "github:staltz/ppppp-db",
|
"ppppp-db": "github:staltz/ppppp-db",
|
||||||
"ppppp-dict": "github:staltz/ppppp-dict",
|
"ppppp-set": "github:staltz/ppppp-set",
|
||||||
"ppppp-gc": "github:staltz/ppppp-gc",
|
"ppppp-gc": "github:staltz/ppppp-gc",
|
||||||
"ppppp-goals": "github:staltz/ppppp-goals",
|
"ppppp-goals": "github:staltz/ppppp-goals",
|
||||||
"ppppp-keypair": "github:staltz/ppppp-keypair",
|
"ppppp-keypair": "github:staltz/ppppp-keypair",
|
||||||
"ppppp-tangle-sync": "github:staltz/ppppp-tangle-sync",
|
"ppppp-sync": "github:staltz/ppppp-sync",
|
||||||
"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",
|
||||||
|
|
|
@ -65,8 +65,8 @@ test('Replicate selected feeds of followed accounts', async (t) => {
|
||||||
// Alice follows Bob, but not Carol
|
// Alice follows Bob, but not Carol
|
||||||
assert(await p(alice.set.add)('follow', bobID), 'alice follows bob')
|
assert(await p(alice.set.add)('follow', bobID), 'alice follows bob')
|
||||||
|
|
||||||
alice.conductor.start(aliceID, [['post'], ['post']], 64_000_000)
|
alice.conductor.start(aliceID, [['post@all'], ['post@all']], 64_000_000)
|
||||||
bob.conductor.start(bobID, [['post'], ['post']], 64_000_000)
|
bob.conductor.start(bobID, [['post@all'], ['post@all']], 64_000_000)
|
||||||
|
|
||||||
const aliceDialingBob = await p(alice.connect)(bob.getAddress())
|
const aliceDialingBob = await p(alice.connect)(bob.getAddress())
|
||||||
const aliceDialingCarol = await p(alice.connect)(carol.getAddress())
|
const aliceDialingCarol = await p(alice.connect)(carol.getAddress())
|
||||||
|
@ -74,7 +74,7 @@ test('Replicate selected feeds of followed accounts', async (t) => {
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
getTexts([...alice.db.msgs()]),
|
getTexts([...alice.db.msgs()]),
|
||||||
['A0', 'A1', 'A2', 'A3', 'A4', /* */ 'B0', 'B1', 'B2', 'B3', 'B4'],
|
['A0', 'A1', 'A2', 'A3', 'A4', /* */ 'B0', 'B1', 'B2', 'B3', 'B4'],
|
||||||
'alice has alice and bob posts'
|
'alice has alice and bob posts'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -84,3 +84,95 @@ test('Replicate selected feeds of followed accounts', async (t) => {
|
||||||
await p(bob.close)(true)
|
await p(bob.close)(true)
|
||||||
await p(carol.close)(true)
|
await p(carol.close)(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('GC selected feeds of followed accounts', 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 creates a feed of posts
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
await p(alice.db.feed.publish)({
|
||||||
|
account: aliceID,
|
||||||
|
domain: 'post',
|
||||||
|
data: { text: 'A' + i },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bob
|
||||||
|
const bob = createPeer({ name: 'bob' })
|
||||||
|
await bob.db.loaded()
|
||||||
|
// Bob creates his own account
|
||||||
|
const bobID = await p(bob.db.account.create)({
|
||||||
|
subdomain: 'account',
|
||||||
|
_nonce: 'bob',
|
||||||
|
})
|
||||||
|
await p(bob.set.load)(bobID)
|
||||||
|
// Bob creates a feed of posts
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
await p(bob.db.feed.publish)({
|
||||||
|
account: bobID,
|
||||||
|
domain: 'post',
|
||||||
|
data: { text: 'B' + i },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carol
|
||||||
|
const carol = createPeer({ name: 'carol' })
|
||||||
|
await carol.db.loaded()
|
||||||
|
// Carol creates her own account
|
||||||
|
const carolID = await p(carol.db.account.create)({
|
||||||
|
subdomain: 'account',
|
||||||
|
_nonce: 'carol',
|
||||||
|
})
|
||||||
|
await p(carol.set.load)(bobID)
|
||||||
|
// Carol creates a feed of posts
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
await p(carol.db.feed.publish)({
|
||||||
|
account: carolID,
|
||||||
|
domain: 'post',
|
||||||
|
data: { text: 'C' + i },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alice follows Bob, but not Carol
|
||||||
|
assert(await p(alice.set.add)('follow', bobID), 'alice follows bob')
|
||||||
|
|
||||||
|
alice.conductor.start(aliceID, [['post@all'], ['post@all']], 64_000_000)
|
||||||
|
bob.conductor.start(bobID, [['post@all'], ['post@all']], 64_000_000)
|
||||||
|
|
||||||
|
const aliceDialingBob = await p(alice.connect)(bob.getAddress())
|
||||||
|
const aliceDialingCarol = await p(alice.connect)(carol.getAddress())
|
||||||
|
await p(setTimeout)(1000)
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
getTexts([...alice.db.msgs()]),
|
||||||
|
['A0', 'A1', 'A2', 'A3', 'A4', /* */ 'B0', 'B1', 'B2', 'B3', 'B4'],
|
||||||
|
'alice has alice and bob posts'
|
||||||
|
)
|
||||||
|
|
||||||
|
await p(aliceDialingBob.close)(true)
|
||||||
|
await p(aliceDialingCarol.close)(true)
|
||||||
|
|
||||||
|
alice.conductor.start(aliceID, [['post@all'], ['post@newest-2']], 8_000)
|
||||||
|
const aliceDialingBob2 = await p(alice.connect)(bob.getAddress())
|
||||||
|
const aliceDialingCarol2 = await p(alice.connect)(carol.getAddress())
|
||||||
|
await p(setTimeout)(1000)
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
getTexts([...alice.db.msgs()]),
|
||||||
|
['A0', 'A1', 'A2', 'A3', 'A4', /* */ 'B3', 'B4'],
|
||||||
|
'alice has alice and bob posts'
|
||||||
|
)
|
||||||
|
|
||||||
|
await p(aliceDialingBob2.close)(true)
|
||||||
|
await p(aliceDialingCarol2.close)(true)
|
||||||
|
await p(alice.close)(true)
|
||||||
|
await p(bob.close)(true)
|
||||||
|
await p(carol.close)(true)
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue