forked from coracle/flotilla
fix: realtime updates for room members and admins
This commit is contained in:
+92
-60
@@ -8,7 +8,6 @@ import {
|
|||||||
on,
|
on,
|
||||||
gt,
|
gt,
|
||||||
max,
|
max,
|
||||||
find,
|
|
||||||
spec,
|
spec,
|
||||||
call,
|
call,
|
||||||
first,
|
first,
|
||||||
@@ -815,36 +814,63 @@ export const deriveOtherRooms = (url: string) =>
|
|||||||
|
|
||||||
// Space/room memberships
|
// Space/room memberships
|
||||||
|
|
||||||
|
const getMembershipState = ({
|
||||||
|
events,
|
||||||
|
snapshotKind,
|
||||||
|
addKind,
|
||||||
|
removeKind,
|
||||||
|
getSnapshotMembers,
|
||||||
|
}: {
|
||||||
|
events: TrustedEvent[]
|
||||||
|
snapshotKind: number
|
||||||
|
addKind: number
|
||||||
|
removeKind: number
|
||||||
|
getSnapshotMembers: (event: TrustedEvent) => string[]
|
||||||
|
}) => {
|
||||||
|
const members = new Set<string>()
|
||||||
|
|
||||||
|
for (const event of sortEventsAsc(events)) {
|
||||||
|
if (event.kind === snapshotKind) {
|
||||||
|
members.clear()
|
||||||
|
|
||||||
|
for (const pubkey of getSnapshotMembers(event)) {
|
||||||
|
members.add(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const pubkeys = getPubkeyTagValues(event.tags)
|
||||||
|
|
||||||
|
if (event.kind === addKind) {
|
||||||
|
for (const pubkey of pubkeys) {
|
||||||
|
members.add(pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.kind === removeKind) {
|
||||||
|
for (const pubkey of pubkeys) {
|
||||||
|
members.delete(pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
export const deriveSpaceMembers = (url: string) =>
|
export const deriveSpaceMembers = (url: string) =>
|
||||||
derived(
|
derived(
|
||||||
deriveRelaySignedEvents(url, [{kinds: [RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER, RELAY_MEMBERS]}]),
|
deriveRelaySignedEvents(url, [{kinds: [RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER, RELAY_MEMBERS]}]),
|
||||||
$events => {
|
$events =>
|
||||||
const membersEvent = $events.find(spec({kind: RELAY_MEMBERS}))
|
Array.from(
|
||||||
|
getMembershipState({
|
||||||
if (membersEvent) {
|
events: $events,
|
||||||
return uniq(getTagValues("member", membersEvent.tags))
|
snapshotKind: RELAY_MEMBERS,
|
||||||
}
|
addKind: RELAY_ADD_MEMBER,
|
||||||
|
removeKind: RELAY_REMOVE_MEMBER,
|
||||||
const members = new Set<string>()
|
getSnapshotMembers: event => uniq(getTagValues("member", event.tags)),
|
||||||
|
}),
|
||||||
for (const event of sortBy(e => e.created_at, $events)) {
|
),
|
||||||
const pubkeys = getPubkeyTagValues(event.tags)
|
|
||||||
|
|
||||||
if (event.kind === RELAY_ADD_MEMBER) {
|
|
||||||
for (const pubkey of pubkeys) {
|
|
||||||
members.add(pubkey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.kind === RELAY_REMOVE_MEMBER) {
|
|
||||||
for (const pubkey of pubkeys) {
|
|
||||||
members.delete(pubkey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(members)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
export type BannedPubkeyItem = {
|
export type BannedPubkeyItem = {
|
||||||
@@ -871,33 +897,17 @@ export const deriveRoomMembers = (url: string, h: string) => {
|
|||||||
{kinds: [ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER], "#h": [h]},
|
{kinds: [ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER], "#h": [h]},
|
||||||
]
|
]
|
||||||
|
|
||||||
return derived(deriveEventsForUrl(url, filters), $events => {
|
return derived(deriveEventsForUrl(url, filters), $events =>
|
||||||
const membersEvent = find(spec({kind: ROOM_MEMBERS}), $events)
|
Array.from(
|
||||||
|
getMembershipState({
|
||||||
if (membersEvent) {
|
events: $events,
|
||||||
return uniq(getPubkeyTagValues(membersEvent.tags))
|
snapshotKind: ROOM_MEMBERS,
|
||||||
}
|
addKind: ROOM_ADD_MEMBER,
|
||||||
|
removeKind: ROOM_REMOVE_MEMBER,
|
||||||
const members = new Set<string>()
|
getSnapshotMembers: event => uniq(getPubkeyTagValues(event.tags)),
|
||||||
|
}),
|
||||||
for (const event of sortEventsAsc($events)) {
|
),
|
||||||
const pubkeys = getPubkeyTagValues(event.tags)
|
)
|
||||||
|
|
||||||
if (event.kind === ROOM_ADD_MEMBER) {
|
|
||||||
for (const pubkey of pubkeys) {
|
|
||||||
members.add(pubkey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.kind === ROOM_REMOVE_MEMBER) {
|
|
||||||
for (const pubkey of pubkeys) {
|
|
||||||
members.delete(pubkey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(members)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deriveRoomAdmins = (url: string, h: string) => {
|
export const deriveRoomAdmins = (url: string, h: string) => {
|
||||||
@@ -921,7 +931,7 @@ export const deriveSpaceActionItems = (url: string) =>
|
|||||||
derived(
|
derived(
|
||||||
deriveEventsForUrl(url, [
|
deriveEventsForUrl(url, [
|
||||||
{
|
{
|
||||||
kinds: [REPORT, ROOM_JOIN, ROOM_LEAVE, ROOM_MEMBERS],
|
kinds: [REPORT, ROOM_JOIN, ROOM_LEAVE, ROOM_MEMBERS, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER],
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
$events => {
|
$events => {
|
||||||
@@ -936,8 +946,16 @@ export const deriveSpaceActionItems = (url: string) =>
|
|||||||
|
|
||||||
const roomJoins = roomEvents.filter(spec({kind: ROOM_JOIN}))
|
const roomJoins = roomEvents.filter(spec({kind: ROOM_JOIN}))
|
||||||
const roomLeaves = roomEvents.filter(spec({kind: ROOM_LEAVE}))
|
const roomLeaves = roomEvents.filter(spec({kind: ROOM_LEAVE}))
|
||||||
const roomMembersEvent = roomEvents.find(spec({kind: ROOM_MEMBERS}))
|
const roomMembershipEvents = roomEvents.filter(event =>
|
||||||
const roomMembers = getTagValues("p", roomMembersEvent?.tags ?? [])
|
[ROOM_MEMBERS, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER].includes(event.kind),
|
||||||
|
)
|
||||||
|
const roomMembers = getMembershipState({
|
||||||
|
events: roomMembershipEvents,
|
||||||
|
snapshotKind: ROOM_MEMBERS,
|
||||||
|
addKind: ROOM_ADD_MEMBER,
|
||||||
|
removeKind: ROOM_REMOVE_MEMBER,
|
||||||
|
getSnapshotMembers: event => getPubkeyTagValues(event.tags),
|
||||||
|
})
|
||||||
|
|
||||||
pendingJoins.push(
|
pendingJoins.push(
|
||||||
...removeUndefined(
|
...removeUndefined(
|
||||||
@@ -945,8 +963,22 @@ export const deriveSpaceActionItems = (url: string) =>
|
|||||||
.map(sortEventsDesc)
|
.map(sortEventsDesc)
|
||||||
.map(first),
|
.map(first),
|
||||||
).filter(({pubkey, created_at}) => {
|
).filter(({pubkey, created_at}) => {
|
||||||
if (roomMembers.includes(pubkey)) return false
|
if (roomMembers.has(pubkey)) return false
|
||||||
if (gt(roomMembersEvent?.created_at, created_at)) return false
|
if (
|
||||||
|
roomMembershipEvents.some(event => {
|
||||||
|
if (event.created_at <= created_at) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.kind === ROOM_MEMBERS) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPubkeyTagValues(event.tags).includes(pubkey)
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (roomLeaves.some(e => e.pubkey === pubkey && e.created_at > created_at)) return false
|
if (roomLeaves.some(e => e.pubkey === pubkey && e.created_at > created_at)) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
+16
-3
@@ -13,6 +13,8 @@ import {
|
|||||||
ROOM_MEMBERS,
|
ROOM_MEMBERS,
|
||||||
ROOM_ADD_MEMBER,
|
ROOM_ADD_MEMBER,
|
||||||
ROOM_REMOVE_MEMBER,
|
ROOM_REMOVE_MEMBER,
|
||||||
|
ROOM_JOIN,
|
||||||
|
ROOM_LEAVE,
|
||||||
ROOM_CREATE_PERMISSION,
|
ROOM_CREATE_PERMISSION,
|
||||||
RELAY_MEMBERS,
|
RELAY_MEMBERS,
|
||||||
RELAY_ADD_MEMBER,
|
RELAY_ADD_MEMBER,
|
||||||
@@ -278,8 +280,13 @@ const syncSpace = (url: string, rooms: string[]) => {
|
|||||||
url,
|
url,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
filters: [
|
filters: [
|
||||||
|
{kinds: [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS], "#d": [room]},
|
||||||
{kinds: MESSAGE_KINDS, since, "#h": [room]},
|
{kinds: MESSAGE_KINDS, since, "#h": [room]},
|
||||||
makeCommentFilter(CONTENT_KINDS, {since, "#h": [room]}),
|
makeCommentFilter(CONTENT_KINDS, {since, "#h": [room]}),
|
||||||
|
{
|
||||||
|
kinds: [ROOM_DELETE, ROOM_JOIN, ROOM_LEAVE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER],
|
||||||
|
"#h": [room],
|
||||||
|
},
|
||||||
{kinds: [PollResponse], since},
|
{kinds: [PollResponse], since},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -292,7 +299,7 @@ const syncSpace = (url: string, rooms: string[]) => {
|
|||||||
|
|
||||||
const relayKinds = [RELAY_MEMBERS, RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER]
|
const relayKinds = [RELAY_MEMBERS, RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER]
|
||||||
const roomMetaKinds = [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS, LIVEKIT_PARTICIPANTS]
|
const roomMetaKinds = [ROOM_META, ROOM_ADMINS, ROOM_MEMBERS, LIVEKIT_PARTICIPANTS]
|
||||||
const roomMemberKinds = [ROOM_DELETE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER]
|
const roomMemberKinds = [ROOM_DELETE, ROOM_JOIN, ROOM_LEAVE, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER]
|
||||||
|
|
||||||
pullAndListen({
|
pullAndListen({
|
||||||
url,
|
url,
|
||||||
@@ -325,9 +332,10 @@ const syncSpaces = () => {
|
|||||||
|
|
||||||
const unsubscribe = store.subscribe(([$userGroupList, $page]) => {
|
const unsubscribe = store.subscribe(([$userGroupList, $page]) => {
|
||||||
const urls = new Set(getSpaceUrlsFromGroupList($userGroupList))
|
const urls = new Set(getSpaceUrlsFromGroupList($userGroupList))
|
||||||
|
const currentUrl = $page.params.relay ? decodeRelay($page.params.relay) : undefined
|
||||||
|
|
||||||
if ($page.params.relay) {
|
if (currentUrl) {
|
||||||
urls.add(decodeRelay($page.params.relay))
|
urls.add(currentUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop syncing removed spaces
|
// Stop syncing removed spaces
|
||||||
@@ -342,6 +350,11 @@ const syncSpaces = () => {
|
|||||||
// Start or restart syncing for each space
|
// Start or restart syncing for each space
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
const rooms = getSpaceRoomsFromGroupList(url, $userGroupList)
|
const rooms = getSpaceRoomsFromGroupList(url, $userGroupList)
|
||||||
|
|
||||||
|
if (currentUrl === url && $page.params.h && !rooms.includes($page.params.h)) {
|
||||||
|
rooms.push($page.params.h)
|
||||||
|
}
|
||||||
|
|
||||||
const roomsKey = rooms.join(",")
|
const roomsKey = rooms.join(",")
|
||||||
|
|
||||||
if (unsubscribersByUrl.has(url) && roomsByUrl.get(url) === roomsKey) continue
|
if (unsubscribersByUrl.has(url) && roomsByUrl.get(url) === roomsKey) continue
|
||||||
|
|||||||
Reference in New Issue
Block a user