Fix loop on notifications page caused by mutally referential subscriptions

This commit is contained in:
Jon Staab 2023-11-27 17:24:10 -08:00
parent 455ebc8238
commit 262bf514d7
9 changed files with 42 additions and 19 deletions

1
.env
View File

@ -5,6 +5,7 @@ VITE_DEFAULT_FOLLOWS=1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3
VITE_IMGPROXY_URL=https://imgproxy.coracle.social
VITE_DUFFLEPUD_URL=https://dufflepud.onrender.com
VITE_ENABLE_GROUPS=true
VITE_ENABLE_JUKEBOX=true
VITE_ENABLE_ZAPS=true
VITE_FORCE_RELAYS=
VITE_LOGO_URL=

View File

@ -9,6 +9,8 @@
- [x] Add anonymous posting
- [x] Add note options dialog to replies
- [x] Add support for reposts and cross-posts
- [x] Bump paravel to fix missing tags after normalize (fixes mention notifications)
- [x] Fix throttled notifications derive loop
# 0.3.12

View File

@ -1,7 +1,7 @@
<script lang="ts">
import {fade} from "src/util/transition"
import {getProps} from "src/util/router"
import {canSign} from "src/engine"
import {canSign, env} from "src/engine"
import ForegroundButton from "src/partials/ForegroundButton.svelte"
import ForegroundButtons from "src/partials/ForegroundButtons.svelte"
import MusicPlayer from "src/app/MusicPlayer.svelte"
@ -46,7 +46,7 @@
</ForegroundButton>
</div>
{/if}
{#if showButtons}
{#if showButtons && $env.ENABLE_JUKEBOX}
<div transition:fade|local={{delay: 200, duration: 200}}>
<ForegroundButton theme="secondary" size="small" on:click={showPlayer}>
<i class="fa fa-music" />
@ -62,4 +62,6 @@
{/if}
</ForegroundButtons>
<MusicPlayer bind:isOpen={playerIsOpen} />
{#if $env.ENABLE_JUKEBOX}
<MusicPlayer bind:isOpen={playerIsOpen} />
{/if}

View File

@ -7,10 +7,11 @@
import Rating from "src/partials/Rating.svelte"
import RelayTitle from "src/app/shared/RelayTitle.svelte"
import RelayActions from "src/app/shared/RelayActions.svelte"
import type {DynamicFilter} from "src/engine"
import {deriveRelay, normalizeRelayUrl, displayRelay} from "src/engine"
export let url
export let filter = {kinds: noteKinds, authors: 'network'}
export let filter: DynamicFilter = {kinds: noteKinds, authors: "network"}
let reviews = []
let activeTab = "notes"

View File

@ -1,3 +1,4 @@
import {max, pluck} from "ramda"
import {batch} from "hurdak"
import {Tags} from "paravel"
import {projections} from "src/engine/core/projections"
@ -18,17 +19,20 @@ projections.addGlobalHandler(
})
)
projections.addHandler(EventKind.Delete, e => {
const values = Tags.from(e).type(["a", "e"]).values().all()
projections.addHandler(
EventKind.Delete,
batch(500, (chunk: Event[]) => {
const values = Tags.from(chunk).type(["a", "e"]).values().all()
deletesLastUpdated.update(ts => Math.max(ts, e.created_at))
deletesLastUpdated.update(ts => max(ts, pluck("created_at", chunk).reduce(max)))
deletes.update($deletes => {
values.forEach(v => $deletes.add(v))
deletes.update($deletes => {
values.forEach(v => $deletes.add(v))
return $deletes
return $deletes
})
})
})
)
projections.addHandler(EventKind.GiftWrap, e => {
const session = sessions.get()[Tags.from(e).getValue("p")]

View File

@ -2,7 +2,7 @@ import type {SubscriptionOpts} from "paravel"
import {Subscription, now} from "paravel"
import {assoc, map} from "ramda"
import {updateIn} from "hurdak"
import {LOCAL_RELAY_URL} from 'src/util/nostr'
import {LOCAL_RELAY_URL} from "src/util/nostr"
import type {Event} from "src/engine/events/model"
import {projections} from "src/engine/core/projections"
import {getUrls, getExecutor} from "./executor"
@ -10,6 +10,7 @@ import {Tracker} from "./tracker"
export type SubscribeOpts = typeof SubscriptionOpts & {
tracker?: Tracker
skipCache?: boolean
shouldProject?: boolean
onEvent?: (e: Event) => void
onEose?: (url: string) => void
@ -18,11 +19,12 @@ export type SubscribeOpts = typeof SubscriptionOpts & {
export const subscribe = (opts: SubscribeOpts) => {
const tracker = opts.tracker || new Tracker()
const relays = opts.skipCache ? opts.relays : opts.relays.concat(LOCAL_RELAY_URL)
const sub = new Subscription({
...opts,
hasSeen: tracker.add,
closeOnEose: Boolean(opts.timeout),
executor: getExecutor(getUrls(opts.relays.concat(LOCAL_RELAY_URL))),
executor: getExecutor(getUrls(relays)),
})
sub.on("event", e => {

View File

@ -6,20 +6,21 @@ import {tryJson} from "src/util/misc"
import {events, isEventMuted} from "src/engine/events/derived"
import {derived} from "src/engine/core/utils"
import {groupRequests, groupAlerts} from "src/engine/groups/state"
import {pubkey} from "src/engine/session/state"
import {session} from "src/engine/session/derived"
import {userEvents} from "src/engine/events/derived"
export const notifications = derived(
[session, userEvents.mapStore.throttle(500), events.throttle(500)],
([$session, $userEvents, $events]) => {
if (!$session) {
[pubkey, userEvents.mapStore.throttle(500), events.throttle(500)],
([$pubkey, $userEvents, $events]) => {
if (!$pubkey) {
return []
}
const $isEventMuted = isEventMuted.get()
return $events.filter(e => {
if (e.pubkey === $session.pubkey || $isEventMuted(e)) {
if (e.pubkey === $pubkey || $isEventMuted(e)) {
return false
}
@ -28,7 +29,7 @@ export const notifications = derived(
return (
$userEvents.get(tags.mark("root").getValue()) ||
$userEvents.get(tags.mark("reply").getValue()) ||
tags.pubkeys().has($session.pubkey)
tags.pubkeys().has($pubkey)
)
})
}

View File

@ -55,7 +55,12 @@ export const loadNotifications = () => {
"id",
sortBy(
e => -e.created_at,
events.get().filter(e => e.created_at > cutoff && pubkeys.includes(e.pubkey))
events
.get()
.filter(
e =>
!reactionKinds.includes(e.kind) && e.created_at > cutoff && pubkeys.includes(e.pubkey)
)
).slice(0, 256)
)
@ -68,6 +73,7 @@ export const loadNotifications = () => {
return subscribe({
filters,
timeout: 15000,
skipCache: true,
shouldProject: false,
relays: mergeHints(pubkeys.map(pk => getPubkeyHints(pk, "read"))),
onEvent: onNotificationEvent,
@ -104,6 +110,7 @@ export const listenForNotifications = async () => {
subscribePersistent({
relays,
filters,
skipCache: true,
onEvent: onNotificationEvent,
})
}

View File

@ -60,6 +60,8 @@ const ENABLE_ZAPS = JSON.parse(import.meta.env.VITE_ENABLE_ZAPS)
const ENABLE_GROUPS = JSON.parse(import.meta.env.VITE_ENABLE_GROUPS)
const ENABLE_JUKEBOX = JSON.parse(import.meta.env.VITE_ENABLE_JUKEBOX)
// Prep our env
env.set({
DEFAULT_FOLLOWS,
@ -72,6 +74,7 @@ env.set({
DEFAULT_RELAYS,
ENABLE_ZAPS,
ENABLE_GROUPS,
ENABLE_JUKEBOX,
})
// Throw some hardcoded defaults in there