Optimize repository-derived stores and make repository updates atomic

This commit is contained in:
Jon Staab 2024-06-06 09:25:50 -07:00
parent 516e7bfcad
commit bc372eedd7
7 changed files with 36 additions and 50 deletions

View File

@ -4,6 +4,7 @@
isScopeFeed,
isRelayFeed,
isListFeed,
isLabelFeed,
isAddressFeed,
isDVMFeed,
isKindFeed,
@ -48,6 +49,8 @@
On {args.length === 1 ? displayRelayUrl(args[0]) : `${args.length} relays`}
{:else if isListFeed(feed)}
From {quantify(getFeedArgs(feed).length, "list")}
{:else if isLabelFeed(feed)}
From {quantify(getFeedArgs(feed).length, "collection")}
{:else if isAddressFeed(feed) || isIDFeed(feed)}
{quantify(getFeedArgs(feed).length, "event")}
{:else if isDVMFeed(feed)}

View File

@ -21,15 +21,6 @@
<div class="py-2">
<Media url={url} onClose={close} />
</div>
{:else if value.isMedia}
<Anchor
modal
stopPropagation
class="overflow-hidden text-ellipsis whitespace-nowrap underline"
externalHref={url}
href={router.at("media").of(url).toString()}>
{displayUrl(url)}
</Anchor>
{:else if isShareableRelayUrl(url)}
<Anchor
modal
@ -40,10 +31,11 @@
</Anchor>
{:else}
<Anchor
external
modal
stopPropagation
class="overflow-hidden text-ellipsis whitespace-nowrap underline"
href={url}>
externalHref={url}
href={router.at("media").of(url).toString()}>
{displayUrl(url)}
</Anchor>
{/if}

View File

@ -26,10 +26,7 @@
if (!$joined) {
actions.push({
onClick: () => {
joinRelay(url)
broadcastUserData([url])
},
onClick: () => joinRelay(url),
label: "Join",
icon: "right-to-bracket",
})

View File

@ -107,10 +107,8 @@
let customRelay = ""
let currentRelayPolicies = $userRelayPolicies
$: currentRelayPolicies = sortBy(
prop("url"),
uniqBy(prop("url"), $userRelayPolicies.concat(currentRelayPolicies)),
)
$: currentRelayPolicies =
sortBy(prop("url"), uniqBy(prop("url"), $userRelayPolicies.concat(currentRelayPolicies)))
$: ratings = groupBy(e => {
try {

View File

@ -671,7 +671,7 @@ export const updateSingleton = async (kind: number, modifyTags: ModifyTags) => {
}
// Preserve content instead of use encrypted tags because kind 3 content is used for
// relay selections in many places
// relay selections in many places. Content isn't supported for mutes or relays so this is ok
const content = event?.content || ""
const relays = forcePlatformRelays(withIndexers(hints.WriteRelays().getUrls()))
const encrypt = content => nip44.get().encryptAsUser(content, pubkey.get())

View File

@ -1,6 +1,6 @@
import {throttle} from "throttle-debounce"
import {derived} from "svelte/store"
import {identity, partition, first} from "@welshman/lib"
import {identity, batch, partition, first} from "@welshman/lib"
import {Repository, Relay, matchFilters, getIdAndAddress, getIdFilters} from "@welshman/util"
import type {Filter, TrustedEvent} from "@welshman/util"
import {custom} from "src/util/misc"
@ -25,14 +25,14 @@ export const events = {
events._subs.push(f)
if (events._subs.length === 1) {
repository.on("event", events._onUpdate)
repository.on("update", events._onUpdate)
}
return () => {
events._subs = events._subs.filter(x => x !== f)
if (events._subs.length === 0) {
repository.off("event", events._onUpdate)
repository.off("update", events._onUpdate)
}
}
},
@ -49,49 +49,48 @@ export const deriveEventsMapped = <T>({
itemToEvent: (item: T) => TrustedEvent
includeDeleted?: boolean
}) =>
custom<T[]>(
setter => {
let data = setter(
repository.query(filters, {includeDeleted}).map(eventToItem).filter(identity),
)
custom<T[]>(setter => {
let data = repository.query(filters, {includeDeleted}).map(eventToItem).filter(identity)
const onEvent = (event: TrustedEvent) => {
setter(data)
const onUpdate = batch(300, (updates: {added: TrustedEvent[]; removed: Set<string>}[]) => {
const added = updates.flatMap(r => r.added)
const removed = updates.reduce((r, {removed}) => r.union(removed), new Set<string>())
let dirty = false
for (const event of added) {
if (matchFilters(filters, event)) {
const item = eventToItem(event)
if (item) {
data = setter([...data, item])
dirty = true
data.push(item)
}
}
}
const onDelete = (values: Set<string>) => {
if (!includeDeleted && removed.size > 0) {
const [deleted, ok] = partition(
(item: T) => getIdAndAddress(itemToEvent(item)).some(id => values.has(id)),
(item: T) => getIdAndAddress(itemToEvent(item)).some(id => removed.has(id)),
data,
)
if (deleted.length > 0) {
data = setter(ok)
dirty = true
data = ok
}
}
repository.on("event", onEvent)
if (!includeDeleted) {
repository.on("delete", onDelete)
if (dirty) {
setter(data)
}
})
return () => {
repository.off("event", onEvent)
repository.on("update", onUpdate)
if (!includeDeleted) {
repository.off("delete", onDelete)
}
}
},
{throttle: 300},
)
return () => repository.off("update", onUpdate)
})
export const deriveEvents = (opts: {filters: Filter[]; includeDeleted?: boolean}) =>
deriveEventsMapped<TrustedEvent>({...opts, eventToItem: identity, itemToEvent: identity})

View File

@ -407,9 +407,8 @@ export const getter = <T>(store: Readable<T>) => {
}
type Stop = () => void
type Setter<T> = (x: T) => T
type Sub<T> = (x: T) => void
type Start<T> = (set: Setter<T>) => Stop
type Start<T> = (set: Sub<T>) => Stop
export const custom = <T>(start: Start<T>, opts: {throttle?: number} = {}) => {
const subs: Sub<T>[] = []
@ -430,8 +429,6 @@ export const custom = <T>(start: Start<T>, opts: {throttle?: number} = {}) => {
}
value = newValue
return newValue
})
}