getMsgPurpose returns also details alongside purpose tag

This commit is contained in:
Andre Staltz 2023-10-26 11:14:02 +03:00
parent e14fd87658
commit c4fd63239f
No known key found for this signature in database
GPG Key ID: 9EDE23EA7E8A4890
2 changed files with 31 additions and 18 deletions

View File

@ -13,6 +13,7 @@ const Obz = require('obz')
* @typedef {'none'|'all'|'newest'|'record'|'set'} GoalType * @typedef {'none'|'all'|'newest'|'record'|'set'} GoalType
* @typedef {[number, number]} Range * @typedef {[number, number]} Range
* @typedef {{ id: string, type: GoalType, count: number }} Goal * @typedef {{ id: string, type: GoalType, count: number }} Goal
* @typedef {{ tangleID: MsgID, span: number }} GhostDetails
*/ */
/** /**
@ -39,7 +40,11 @@ const Obz = require('obz')
* These tags are ordered, "none" < "ghost" < "trail" < "goal", meaning that a * These tags are ordered, "none" < "ghost" < "trail" < "goal", meaning that a
* msg with purpose "goal" may *also* fulfill the purpose of "trail", and a * msg with purpose "goal" may *also* fulfill the purpose of "trail", and a
* "trail" also prevents accidental re-request like "ghost" does. * "trail" also prevents accidental re-request like "ghost" does.
* @typedef {'none' | 'ghost' | 'trail' | 'goal'} Purpose * @typedef {['none']
* | ['ghost', GhostDetails]
* | ['trail']
* | ['goal']
* } PurposeWithDetails
*/ */
/** /**
@ -194,7 +199,7 @@ function initGoals(peer, config) {
* @public * @public
* @param {MsgID} msgID * @param {MsgID} msgID
* @param {Msg} msg * @param {Msg} msg
* @returns {Purpose} * @returns {PurposeWithDetails}
*/ */
function getMsgPurpose(msgID, msg) { function getMsgPurpose(msgID, msg) {
assertDBPlugin(peer) assertDBPlugin(peer)
@ -208,7 +213,7 @@ function initGoals(peer, config) {
if (!tangle) break asRoot if (!tangle) break asRoot
const [min, max] = crossGoalWithTangle(goal, tangle) const [min, max] = crossGoalWithTangle(goal, tangle)
if (min > max) break asRoot if (min > max) break asRoot
if (min === 0) return 'goal' if (min === 0) return ['goal']
if (min > 0) servesAsTrail = true if (min > 0) servesAsTrail = true
} }
@ -229,11 +234,11 @@ function initGoals(peer, config) {
} }
// (Loop over once without heavy computations and maybe return early:) // (Loop over once without heavy computations and maybe return early:)
for (const [, min, max, recDepth] of validTangles) { for (const [, min, max, recDepth] of validTangles) {
if (min <= recDepth && recDepth <= max) return 'goal' if (min <= recDepth && recDepth <= max) return ['goal']
} }
// At this point we know that the record *cannot* serve as 'goal', // At this point we know that the record *cannot* serve as 'goal',
// so if it serves as trail, that'll do: // so if it serves as trail, that'll do:
if (servesAsTrail) return 'trail' if (servesAsTrail) return ['trail']
// Check whether this record is a trail affix of some tangle: // Check whether this record is a trail affix of some tangle:
// (Loop again with heavy computations now that it's inevitable:) // (Loop again with heavy computations now that it's inevitable:)
for (const [tangle, min] of validTangles) { for (const [tangle, min] of validTangles) {
@ -241,20 +246,21 @@ function initGoals(peer, config) {
.topoSort() .topoSort()
.filter((msgID) => tangle.getDepth(msgID) === min) .filter((msgID) => tangle.getDepth(msgID) === min)
const { erasables } = tangle.getDeletablesAndErasables(...minMsgIDs) const { erasables } = tangle.getDeletablesAndErasables(...minMsgIDs)
if (erasables.has(msgID)) return 'trail' if (erasables.has(msgID)) return ['trail']
} }
// Check whether this record is a ghost affix of some tangle: // Check whether this record is a ghost affix of some tangle:
for (const [tangle, , , , goalType] of validTangles) { for (const [tangle, , , , goalType] of validTangles) {
if (goalType === 'record') { if (goalType === 'record') {
assertRecordPlugin(peer) assertRecordPlugin(peer)
const span = peer.record.getGhostSpan()
if (peer.record.isGhostable(msgID, tangle.id)) { if (peer.record.isGhostable(msgID, tangle.id)) {
return 'ghost' return ['ghost', {tangleID: tangle.id, span }]
} }
} }
} }
return 'none' return ['none']
} }
/** /**

View File

@ -34,7 +34,10 @@ test('set, getByID, list, listen', async (t) => {
} }
{ {
const purpose = alice.goals.getMsgPurpose(aliceAccountRoot.id, aliceAccountRoot.msg) const [purpose] = alice.goals.getMsgPurpose(
aliceAccountRoot.id,
aliceAccountRoot.msg
)
assert.equal(purpose, 'goal', 'rec purpose is "goal"') assert.equal(purpose, 'goal', 'rec purpose is "goal"')
} }
@ -91,19 +94,19 @@ test('getMsgPurpose', async (t) => {
const gottenGoal = alice.goals.get(feedID) const gottenGoal = alice.goals.get(feedID)
assert.strictEqual(gottenGoal.id, feedID, 'gotten goal id is correct') assert.strictEqual(gottenGoal.id, feedID, 'gotten goal id is correct')
const purpose = alice.goals.getMsgPurpose(post2.id, post2.msg) const [purpose] = alice.goals.getMsgPurpose(post2.id, post2.msg)
assert.equal(purpose, 'goal', 'purpose is "goal"') assert.equal(purpose, 'goal', 'purpose is "goal"')
alice.goals.set(feedID, 'newest-1') alice.goals.set(feedID, 'newest-1')
assert('set goal to newest-1') assert('set goal to newest-1')
const purpose2 = alice.goals.getMsgPurpose(post2.id, post2.msg) const [purpose2] = alice.goals.getMsgPurpose(post2.id, post2.msg)
assert.equal(purpose2, 'none', 'purpose2 is "none"') assert.equal(purpose2, 'none', 'purpose2 is "none"')
await p(alice.close)(true) await p(alice.close)(true)
}) })
test('getMsgPurpose ghost', async (t) => { test('getMsgPurpose ghost', async (t) => {
const alice = createPeer({ name: 'alice', record: {ghostSpan: 3} }) const alice = createPeer({ name: 'alice', record: { ghostSpan: 3 } })
await alice.db.loaded() await alice.db.loaded()
const aliceID = await p(alice.db.account.create)({ const aliceID = await p(alice.db.account.create)({
@ -123,14 +126,18 @@ test('getMsgPurpose ghost', async (t) => {
const msgIDs = tangle.topoSort() const msgIDs = tangle.topoSort()
assert.equal(msgIDs.length, 6, 'tangle has root+5 messages') assert.equal(msgIDs.length, 6, 'tangle has root+5 messages')
const recs = msgIDs.map(id => alice.db.getRecord(id)) const recs = msgIDs.map((id) => alice.db.getRecord(id))
alice.goals.set(feedID, 'record') alice.goals.set(feedID, 'record')
assert.equal(alice.goals.getMsgPurpose(recs[1].id, recs[1].msg), 'none') assert.equal(alice.goals.getMsgPurpose(recs[1].id, recs[1].msg)[0], 'none')
assert.equal(alice.goals.getMsgPurpose(recs[2].id, recs[2].msg), 'ghost') assert.equal(alice.goals.getMsgPurpose(recs[2].id, recs[2].msg)[0], 'ghost')
assert.equal(alice.goals.getMsgPurpose(recs[3].id, recs[3].msg), 'trail') assert.equal(alice.goals.getMsgPurpose(recs[3].id, recs[3].msg)[0], 'trail')
assert.equal(alice.goals.getMsgPurpose(recs[4].id, recs[4].msg), 'trail') assert.equal(alice.goals.getMsgPurpose(recs[4].id, recs[4].msg)[0], 'trail')
assert.equal(alice.goals.getMsgPurpose(recs[5].id, recs[5].msg), 'goal') assert.equal(alice.goals.getMsgPurpose(recs[5].id, recs[5].msg)[0], 'goal')
const [purpose, details] = alice.goals.getMsgPurpose(recs[2].id, recs[2].msg)
assert.equal(purpose, 'ghost')
assert.deepEqual(details, { tangleID: feedID, span: 3 })
await p(alice.close)(true) await p(alice.close)(true)
}) })