Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt listMembers to exclusion and test it #95

Merged
merged 38 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fe81368
Add failing listMembers exclusion test and getPickedEpoch
Powersource Apr 18, 2023
fe01c0e
Use epoch functions to fix listMembers
Powersource Apr 19, 2023
6350e08
Remove .only
Powersource Apr 19, 2023
1c5ee7b
Move listMembers exclude tests to listMembers file
Powersource Apr 19, 2023
78f2931
Start to integrate getGroupInfoUpdates
Powersource Apr 20, 2023
23f87f6
Merge branch 'master' of github.com:ssbc/ssb-tribes2 into listmembers…
Powersource Apr 20, 2023
df4556d
Use new box2 version
Powersource Apr 21, 2023
362fa2d
Make getPickedEpoch a stream
Powersource Apr 22, 2023
f54684d
Try to make live listMembers work
Powersource Apr 22, 2023
929c279
Use new getMemberUpdates stream in listMembers instead
Powersource Apr 24, 2023
d1ce6c1
Fix getting empty excluded group object
Powersource Apr 24, 2023
3482198
Test listMembers live with exclude
Powersource Apr 24, 2023
d37c83a
Update listMembers readme for live exclude
Powersource Apr 24, 2023
c6ec4ec
Remove comment
Powersource Apr 24, 2023
bcea87e
Remove .only
Powersource Apr 24, 2023
4d7f63f
Merge branch 'master' of github.com:ssbc/ssb-tribes2 into listmembers…
Powersource May 2, 2023
68b262d
Test adding person to new epoch and checking live list
Powersource May 2, 2023
e309902
Fix small review suggestions
Powersource May 2, 2023
4758a34
Stop live stream in stream to fix switching between epochs
Powersource May 2, 2023
19c2b19
refactor epochs to consolidate getPreferredEpoch
mixmix May 3, 2023
145f853
tests passing
mixmix May 3, 2023
3c75122
Merge branch 'master' of github.com:ssbc/ssb-tribes2 into refactor_epoch
mixmix May 10, 2023
b68fc0f
Merge branch 'master' of github.com:ssbc/ssb-tribes2 into listmembers…
mixmix May 10, 2023
5288576
updates listMembers output, README
mixmix May 10, 2023
366dbf5
listen for new epochs
mixmix May 10, 2023
70cbecf
remove logs
mixmix May 10, 2023
fa49579
Merge branch 'listmembers-exclusion' of github.com:ssbc/ssb-tribes2 i…
mixmix May 10, 2023
833ad63
only log listener errors if ssb is still "open"
mixmix May 10, 2023
850e1c2
add err handler on listener drain
mixmix May 10, 2023
1bd9446
add timeout on bob close
mixmix May 10, 2023
3b6d921
extract ./listeners
mixmix May 11, 2023
430cae7
Merge pull request #104 from ssbc/refactor_epoch
mixmix May 11, 2023
25bdbce
Apply suggestions from code review
mixmix May 11, 2023
a67f6ee
test fixes: safer ssb.close, explicit t.end
mixmix May 11, 2023
bbc964d
Merge branch 'listmembers-exclusion' of github.com:ssbc/ssb-tribes2 i…
mixmix May 11, 2023
d613a48
preferredEpoch (live) now emits on membership updates
mixmix May 11, 2023
5d451ba
Merge pull request #112 from ssbc/listmembers-exclusions-fixes
Powersource May 11, 2023
2fd0c34
Update box2
Powersource May 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,22 @@ Publishes any kind of message encrypted to the group. The function wraps `ssb.db

### `ssb.tribes2.listMembers(groupId, { live }) => source`

Returns a pull stream source listing every known member of the group with id `groupId`. Note: lists members whether or not they've accepted the invite. If `live` is true, then it keeps the stream open and also outputs new members.
Returns a pull stream source listing the root feed id of every member of the
group with id `groupId`. Note: lists members whether or not they've accepted the
invite.

If `live` is true, then it keeps the stream open and also outputs updates to
membership as new members are added / excluded.

Each update emitted from the source is the updated complete state for the
current preferred epoch of the group in the format:

```js
{
added: [feedId, feedId, ...],
toExclude: [feedId, ...]
}
```

### `ssb.tribes2.listInvites() => source`

Expand Down
165 changes: 47 additions & 118 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ const { promisify } = require('util')
const pull = require('pull-stream')
const paraMap = require('pull-paramap')
const pullMany = require('pull-many')
const pullFlatMerge = require('pull-flat-merge')
const pullAbortable = require('pull-abortable')
const pullDefer = require('pull-defer')
const chunk = require('lodash.chunk')
const clarify = require('clarify-error')
const {
where,
and,
or,
isDecrypted,
type,
live,
toPullStream,
} = require('ssb-db2/operators')
const {
Expand All @@ -30,12 +32,14 @@ const {
} = require('private-group-spec')
const { SecretKey } = require('ssb-private-group-keys')
const { fromMessageSigil, isBendyButtV1FeedSSBURI } = require('ssb-uri2')

const startListeners = require('./listeners')
const buildGroupId = require('./lib/build-group-id')
const addTangles = require('./lib/tangles/add-tangles')
const publishAndPrune = require('./lib/prune-publish')
const MetaFeedHelpers = require('./lib/meta-feed-helpers')
const Epochs = require('./lib/epochs')
const { groupRecp } = require('./lib/operators')
// const Epochs = require('./lib/epochs')

module.exports = {
name: 'tribes2',
Expand All @@ -60,7 +64,7 @@ module.exports = {
findOrCreateGroupWithoutMembers,
getRootFeedIdFromMsgId,
} = MetaFeedHelpers(ssb)
// const { getEpochs } = Epochs(ssb)
const { getPreferredEpoch, getMembers } = Epochs(ssb)

function create(opts = {}, cb) {
if (cb === undefined) return promisify(create)(opts)
Expand Down Expand Up @@ -208,6 +212,8 @@ module.exports = {

pull(
listMembers(groupId),
pull.map((info) => info.added),
pull.flatten(),
pull.collect((err, beforeMembers) => {
// prettier-ignore
if (err) return cb(clarify(err, "Couldn't get old member list when excluding members"))
Expand Down Expand Up @@ -319,43 +325,54 @@ module.exports = {
}

function listMembers(groupId, opts = {}) {
const deferedSource = pullDefer.source()
const { live } = opts
const deferredSource = pullDefer.source()

get(groupId, (err, group) => {
// prettier-ignore
if (err) return deferedSource.abort(clarify(err, 'Failed to get group info when listing members'))
if (err) return deferredSource.abort(clarify(err, 'Failed to get group info when listing members'))
// prettier-ignore
if (group.excluded) return deferedSource.abort( new Error("We're excluded from this group, can't list members"))
if (group.excluded) return deferredSource.abort( new Error("We're excluded from this group, can't list members"))

if (!live) {
getPreferredEpoch(groupId, (err, epoch) => {
// prettier-ignore
if (err) return deferredSource.abort(clarify(err, 'failed to load preferred epoch'))

getMembers(epoch.id, (err, res) => {
// prettier-ignore
if (err) return deferredSource.abort(clarify(err, 'error getting members'))

const source = pull.once(res)
deferredSource.resolve(source)
})
})
return
}

let abortable = pullAbortable()
const source = pull(
ssb.db.query(
where(
and(
isDecrypted('box2'),
type('group/add-member'),
groupRecp(groupId)
)
),
opts.live ? live({ old: true }) : null,
toPullStream()
),
pull.map((msg) => msg.value.content.recps.slice(1)),
pull.flatten(),
pull.unique()
)
getPreferredEpoch.stream(groupId, { live }),
pull.map((epoch) => {
abortable.abort()
abortable = pullAbortable()

deferedSource.resolve(source)
return pull(getMembers.stream(epoch.id, { live }), abortable)
}),
pullFlatMerge()
)
deferredSource.resolve(source)
})

return deferedSource
return deferredSource
}

function listInvites() {
const deferedSource = pullDefer.source()
const deferredSource = pullDefer.source()

getMyGroups((err, myGroups) => {
// prettier-ignore
if (err) return deferedSource.abort(clarify(err, 'Failed to list group IDs when listing invites'))
if (err) return deferredSource.abort(clarify(err, 'Failed to list group IDs when listing invites'))

const source = pull(
// get all the groupIds we've heard of from invites
Expand All @@ -374,17 +391,18 @@ module.exports = {
pull.asyncMap(getGroupInviteData)
)

deferedSource.resolve(source)
deferredSource.resolve(source)
})

return deferedSource
return deferredSource

// listInvites helpers

function getMyGroups(cb) {
const myGroups = new Set()

pull(
// TODO replace with pull.values (unless want "round-robbin" sampling)
pullMany([
ssb.box2.listGroupIds(),
ssb.box2.listGroupIds({ excluded: true }),
Expand Down Expand Up @@ -481,97 +499,8 @@ module.exports = {
findOrCreateAdditionsFeed((err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error finding or creating additions feed when starting ssb-tribes2'))
return cb()
})

ssb.metafeeds.findOrCreate((err, myRoot) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error getting own root in start()'))

// check if we've been excluded
pull(
ssb.db.query(
where(and(isDecrypted('box2'), type('group/exclude-member'))),
live({ old: true }),
toPullStream()
),
pull.filter(isExcludeMember),
pull.filter((msg) =>
// it's an exclusion of us
msg.value.content.excludes.includes(myRoot.id)
),
pull.drain(
(msg) => {
const groupId = msg.value.content.recps[0]
ssb.box2.excludeGroupInfo(groupId, (err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error on excluding group info after finding exclusion of ourselves'))
})
},
(err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error on looking for exclude messages excluding us'))
}
)
)

// look for new epochs that we're added to
pull(
ssb.db.query(
where(and(isDecrypted('box2'), type('group/add-member'))),
live({ old: true }),
toPullStream()
),
pull.filter(isAddMember),
// groups/epochs we're added to
pull.filter((msg) => {
return msg.value.content.recps.includes(myRoot.id)
}),
// to find new epochs we only check groups we've accepted the invite to
paraMap((msg, cb) => {
pull(
ssb.box2.listGroupIds(),
pull.filter((groupId) => groupId === msg.value.content.recps[0]),
pull.take(1),
pull.collect((err, groupIds) => {
// prettier-ignore
if (err) return cb(clarify(err, "Error getting groups we're already in when looking for new epochs"))
cb(null, groupIds.length ? msg : null)
})
)
}, 4),
pull.filter(Boolean),
pull.drain(
(msg) => {
const groupId = msg.value.content.recps[0]

const newKey = Buffer.from(msg.value.content.groupKey, 'base64')
ssb.box2.addGroupInfo(groupId, { key: newKey }, (err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error adding new epoch key that we found'))

const newKeyPick = {
key: newKey,
scheme: keySchemes.private_group,
}
// TODO: naively guessing that this is the latest key for now
ssb.box2.pickGroupWriteKey(groupId, newKeyPick, (err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Error switching to new epoch key that we found'))

ssb.db.reindexEncrypted((err) => {
// prettier-ignore
if (err) cb(clarify(err, 'Error reindexing after finding new epoch'))
})
})
})
},
(err) => {
// prettier-ignore
if (err) return cb(clarify(err, "Error finding new epochs we've been added to"))
}
)
)
cb(null)
startListeners(ssb, getPreferredEpoch, console.error)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BOOM, look at this cute lil guy. Tidies up a whole mess.
Also takes an error-handler at the end, so we can easily decide what we wanna do with those errors later and change this in one place

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

woo nice

})
}

Expand Down
Loading
Loading