Suspend subscriptions while modal is open

This commit is contained in:
Jonathan Staab 2022-11-26 16:24:45 -08:00
parent 0e8d0815c4
commit 98313091d1
6 changed files with 103 additions and 86 deletions

View File

@ -9,8 +9,7 @@
export let note
onMount(() => {
return findNotes(
channels.watcher,
const start = findNotes(
[{ids: [note.id]},
{'#e': [note.id]},
// We can't target reaction deletes by e tag, so get them
@ -20,6 +19,8 @@
note = find(propEq('id', note.id), $notes) || note
}
)
return start()
})
</script>

View File

@ -5,41 +5,22 @@
import Anchor from "src/partials/Anchor.svelte"
import Note from "src/partials/Note.svelte"
import {channels, relays} from "src/state/nostr"
import {findNotes, modal} from "src/state/app"
import {findNotesAndWatchModal, modal} from "src/state/app"
let stop
let notes
const createNote = () => {
navigate("/notes/new")
}
const start = () => {
stop = findNotes(channels.watcher, {
since: now() - timedelta(1, 'days'),
onMount(() => {
return findNotesAndWatchModal({
limit: 100,
}, $notes => {
if ($notes.length) {
notes = $notes
}
})
}
onMount(() => {
const unsub = modal.subscribe($modal => {
console.log('modal', $modal)
if ($modal) {
stop && stop()
} else {
setTimeout(start, 600)
}
})
return () => {
stop()
unsub()
}
})
</script>

View File

@ -6,7 +6,7 @@
import Note from "src/partials/Note.svelte"
import {channels} from 'src/state/nostr'
import {user as currentUser} from 'src/state/user'
import {accounts, findNotes} from "src/state/app"
import {accounts, findNotesAndWatchModal, modal} from "src/state/app"
export let pubkey
@ -15,13 +15,14 @@
$: user = $accounts[pubkey]
onMount(async () => {
return findNotes(channels.watcher, {
onMount(() => {
return findNotesAndWatchModal({
authors: [pubkey],
since: now() - timedelta(1, 'days'),
limit: 100,
}, $notes => {
notes = $notes
if ($notes.length) {
notes = $notes
}
})
})
</script>

View File

@ -1,7 +1,7 @@
import {prop, uniq, pluck, sortBy, uniqBy, find, last, groupBy} from 'ramda'
import {prop, uniq, sortBy, uniqBy, find, last, groupBy} from 'ramda'
import {debounce} from 'throttle-debounce'
import {writable, derived, get} from 'svelte/store'
import {switcherFn, ensurePlural} from 'hurdak/lib/hurdak'
import {switcherFn, noop, ensurePlural} from 'hurdak/lib/hurdak'
import {getLocalJson, setLocalJson, now, timedelta} from "src/util/misc"
import {user} from 'src/state/user'
import {channels} from 'src/state/nostr'
@ -56,72 +56,105 @@ export const ensureAccounts = async pubkeys => {
})
}
export const findNotes = (channel, queries, cb) => {
const notes = writable([])
const reactions = writable([])
export const findNotes = (filters, cb) => {
const start = () => {
const notes = writable([])
const reactions = writable([])
let pubkeys = []
let pubkeys = []
const refreshAccounts = debounce(300, () => {
ensureAccounts(uniq(pubkeys))
const refreshAccounts = debounce(300, () => {
ensureAccounts(uniq(pubkeys))
pubkeys = []
})
pubkeys = []
})
const closeRequest = channel.sub({
filter: ensurePlural(queries).map(q => ({kinds: [1, 5, 7], ...q})),
cb: e => {
// Chunk requests to load accounts
pubkeys.push(e.pubkey)
refreshAccounts()
const closeRequest = channels.watcher.sub({
filter: ensurePlural(filters).map(q => ({kinds: [1, 5, 7], ...q})),
cb: e => {
// Chunk requests to load accounts
pubkeys.push(e.pubkey)
refreshAccounts()
switcherFn(e.kind, {
1: () => {
notes.update($xs => uniqBy(prop('id'), $xs.concat(e)))
},
5: () => {
const ids = e.tags.map(t => t[1])
switcherFn(e.kind, {
1: () => {
notes.update($xs => uniqBy(prop('id'), $xs.concat(e)))
},
5: () => {
const ids = e.tags.map(t => t[1])
notes.update($xs => $xs.filter(({id}) => !id.includes(ids)))
reactions.update($xs => $xs.filter(({id}) => !id.includes(ids)))
},
7: () => {
reactions.update($xs => $xs.concat(e))
},
})
},
})
notes.update($xs => $xs.filter(({id}) => !id.includes(ids)))
reactions.update($xs => $xs.filter(({id}) => !id.includes(ids)))
},
7: () => {
reactions.update($xs => $xs.concat(e))
},
})
},
})
const annotatedNotes = derived(
[notes, reactions, accounts],
([$notes, $reactions, $accounts]) => {
const repliesById = groupBy(
n => find(t => last(t) === 'reply', n.tags)[1],
$notes.filter(n => n.tags.map(last).includes('reply'))
)
const annotatedNotes = derived(
[notes, reactions, accounts],
([$notes, $reactions, $accounts]) => {
const repliesById = groupBy(
n => find(t => last(t) === 'reply', n.tags)[1],
$notes.filter(n => n.tags.map(last).includes('reply'))
)
const reactionsById = groupBy(
n => find(t => last(t) === 'reply', n.tags)[1],
$reactions.filter(n => n.tags.map(last).includes('reply'))
)
const reactionsById = groupBy(
n => find(t => last(t) === 'reply', n.tags)[1],
$reactions.filter(n => n.tags.map(last).includes('reply'))
)
const annotate = n => ({
...n,
user: $accounts[n.pubkey],
replies: (repliesById[n.id] || []).map(reply => annotate(reply)),
reactions: (reactionsById[n.id] || []).map(reaction => annotate(reaction)),
})
const annotate = n => ({
...n,
user: $accounts[n.pubkey],
replies: (repliesById[n.id] || []).map(reply => annotate(reply)),
reactions: (reactionsById[n.id] || []).map(reaction => annotate(reaction)),
})
return sortBy(prop('created'), $notes.map(annotate))
return sortBy(prop('created'), $notes.map(annotate))
}
)
const unsubscribe = annotatedNotes.subscribe(debounce(100, cb))
return () => {
unsubscribe()
closeRequest()
}
)
}
const unsubscribe = annotatedNotes.subscribe(debounce(300, cb))
// Allow caller to suspend/restart the subscription
return start
}
export const findNotesAndWatchModal = (filters, cb) => {
const start = findNotes(filters, cb)
let stop = start()
// Suspend our subscription while we have note detail open
// so we can avoid exceeding our concurrent subscription limit
const unsub = modal.subscribe($modal => {
if ($modal) {
stop && stop()
stop = null
} else if (!stop) {
// Wait for animations to complete
setTimeout(
() => {
stop = start()
},
600
)
}
})
return () => {
unsubscribe()
closeRequest()
stop()
unsub()
}
}

View File

@ -20,7 +20,7 @@ dispatch.addMethod("account/init", async (topic, privkey) => {
user.set({name: pubkey.slice(0, 8), privkey, pubkey})
// Attempt to refresh user data from the network
const found = Boolean(await channels.getter.first({authors: [$user.pubkey]}))
const found = Boolean(await channels.getter.first({authors: [pubkey]}))
// Tell the caller whether this user was found
return {found}

View File

@ -1,6 +1,6 @@
import {writable, get} from "svelte/store"
import {writable} from "svelte/store"
import {getLocalJson, setLocalJson} from "src/util/misc"
import {nostr, channels} from 'src/state/nostr'
import {nostr} from 'src/state/nostr'
export const user = writable(getLocalJson("coracle/user"))
@ -10,3 +10,4 @@ user.subscribe($user => {
// Keep nostr in sync
nostr.login($user?.privkey)
})