Support rumors in thunks
This commit is contained in:
@@ -12,7 +12,7 @@ export const collection = <T, LoadArgs extends any[]>({
|
|||||||
name: string
|
name: string
|
||||||
store: Readable<T[]>
|
store: Readable<T[]>
|
||||||
getKey: (item: T) => string
|
getKey: (item: T) => string
|
||||||
load: (key: string, ...args: LoadArgs) => Promise<any>
|
load?: (key: string, ...args: LoadArgs) => Promise<any>
|
||||||
}) => {
|
}) => {
|
||||||
const indexStore = withGetter(derived(store, $items => indexBy(getKey, $items)))
|
const indexStore = withGetter(derived(store, $items => indexBy(getKey, $items)))
|
||||||
const pending = new Map<string, Promise<Maybe<T>>>()
|
const pending = new Map<string, Promise<Maybe<T>>>()
|
||||||
@@ -20,6 +20,12 @@ export const collection = <T, LoadArgs extends any[]>({
|
|||||||
|
|
||||||
const loadItem = async (key: string, ...args: LoadArgs) => {
|
const loadItem = async (key: string, ...args: LoadArgs) => {
|
||||||
const stale = indexStore.get().get(key)
|
const stale = indexStore.get().get(key)
|
||||||
|
|
||||||
|
// If we have no loader function, nothing we can do
|
||||||
|
if (!load) {
|
||||||
|
return stale
|
||||||
|
}
|
||||||
|
|
||||||
const freshness = getFreshness(name, key)
|
const freshness = getFreshness(name, key)
|
||||||
|
|
||||||
// If we have an item, reload if it's stale
|
// If we have an item, reload if it's stale
|
||||||
|
|||||||
+49
-26
@@ -1,7 +1,8 @@
|
|||||||
import {writable, get} from 'svelte/store'
|
import {writable, get} from 'svelte/store'
|
||||||
import {Worker, assoc} from '@welshman/lib'
|
import {Worker, assoc} from '@welshman/lib'
|
||||||
import {stamp, own, hash} from "@welshman/signer"
|
import {stamp, own, hash} from "@welshman/signer"
|
||||||
import type {HashedEvent, EventTemplate, SignedEvent} from '@welshman/util'
|
import type {TrustedEvent, HashedEvent, EventTemplate, SignedEvent, StampedEvent, OwnedEvent} from '@welshman/util'
|
||||||
|
import {isStampedEvent, isOwnedEvent, isHashedEvent, isUnwrappedEvent, isSignedEvent} from '@welshman/util'
|
||||||
import {publish, PublishStatus} from "@welshman/net"
|
import {publish, PublishStatus} from "@welshman/net"
|
||||||
import {repository, tracker} from './core'
|
import {repository, tracker} from './core'
|
||||||
import {pubkey, getSession, getSigner} from './session'
|
import {pubkey, getSession, getSigner} from './session'
|
||||||
@@ -20,7 +21,7 @@ export type PublishStatusDataByUrlById = Record<string, PublishStatusDataByUrl>
|
|||||||
export const publishStatusData = writable<PublishStatusDataByUrlById>({})
|
export const publishStatusData = writable<PublishStatusDataByUrlById>({})
|
||||||
|
|
||||||
export type Thunk = {
|
export type Thunk = {
|
||||||
event: HashedEvent
|
event: TrustedEvent
|
||||||
relays: string[]
|
relays: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,31 +32,45 @@ export type ThunkWithResolve = Thunk & {
|
|||||||
export const thunkWorker = new Worker<ThunkWithResolve>()
|
export const thunkWorker = new Worker<ThunkWithResolve>()
|
||||||
|
|
||||||
thunkWorker.addGlobalHandler(async ({event, relays, resolve}: ThunkWithResolve) => {
|
thunkWorker.addGlobalHandler(async ({event, relays, resolve}: ThunkWithResolve) => {
|
||||||
const session = getSession(event.pubkey)
|
// If we were given a wrapped event, make sure to publish the wrapper, not the rumor
|
||||||
|
if (isUnwrappedEvent(event)) {
|
||||||
if (!session) {
|
event = event.wrap
|
||||||
return console.warn(`No session found for ${event.pubkey}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const signedEvent = await getSigner(session)!.sign(event)
|
// If the event was already signed, leave it alone. Otherwise, sign it now. This is to
|
||||||
|
// decrease apparent latency in the UI that results from waiting for remote signers
|
||||||
|
if (!isSignedEvent(event)) {
|
||||||
|
const signer = getSigner(getSession(event.pubkey))
|
||||||
|
|
||||||
|
if (!signer) {
|
||||||
|
return console.warn(`No signer found for ${event.pubkey}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
event = await signer.sign(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're guaranteed to have a signed event at this point
|
||||||
|
const signedEvent = event as SignedEvent
|
||||||
|
const {id, sig} = signedEvent
|
||||||
|
|
||||||
|
// Send it off
|
||||||
const pub = publish({event: signedEvent, relays})
|
const pub = publish({event: signedEvent, relays})
|
||||||
|
|
||||||
// Copy the signature over since we had deferred it
|
// Copy the signature over since we had deferred it
|
||||||
const savedEvent = repository.getEvent(signedEvent.id) as SignedEvent
|
const savedEvent = repository.getEvent(id) as SignedEvent
|
||||||
|
|
||||||
// The event may already be replaced or deleted
|
// The event may already be replaced or deleted
|
||||||
if (savedEvent) {
|
if (savedEvent) {
|
||||||
savedEvent.sig = signedEvent.sig
|
savedEvent.sig = sig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track publish success
|
// Track publish success
|
||||||
const {id} = event
|
|
||||||
const statusByUrl: PublishStatusDataByUrl = {}
|
const statusByUrl: PublishStatusDataByUrl = {}
|
||||||
|
|
||||||
pub.emitter.on("*", (status: PublishStatus, url: string, message: string) => {
|
pub.emitter.on("*", (status: PublishStatus, url: string, message: string) => {
|
||||||
publishStatusData.update(
|
Object.assign(statusByUrl, {[url]: {id, url, status, message}})
|
||||||
assoc(id, Object.assign(statusByUrl, {[url]: {id, url, status, message}})),
|
|
||||||
)
|
publishStatusData.update(assoc(id, statusByUrl))
|
||||||
|
|
||||||
if (status === PublishStatus.Success) {
|
if (status === PublishStatus.Success) {
|
||||||
tracker.track(id, url)
|
tracker.track(id, url)
|
||||||
@@ -70,23 +85,31 @@ thunkWorker.addGlobalHandler(async ({event, relays, resolve}: ThunkWithResolve)
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export type ThunkParams = {
|
export type ThunkEvent = EventTemplate | StampedEvent | OwnedEvent | TrustedEvent
|
||||||
event: EventTemplate
|
|
||||||
relays: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const makeThunk = ({event, relays}: ThunkParams) => {
|
export const prepEvent = (event: ThunkEvent) => {
|
||||||
const $pubkey = get(pubkey)
|
if (!isStampedEvent(event as StampedEvent)) {
|
||||||
|
event = stamp(event)
|
||||||
if (!$pubkey) {
|
|
||||||
throw new Error("Unable to make thunk if no user is logged in")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {event: hash(own(stamp(event), $pubkey)), relays}
|
if (!isOwnedEvent(event as OwnedEvent)) {
|
||||||
|
event = own(event as StampedEvent, get(pubkey)!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHashedEvent(event as HashedEvent)) {
|
||||||
|
event = hash(event as OwnedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return event as TrustedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
export const publishThunk = (thunk: Thunk) =>
|
export const makeThunk = ({event, relays}: {event: ThunkEvent, relays: string[]}) =>
|
||||||
|
({event, relays})
|
||||||
|
|
||||||
|
export const publishThunk = ({event, relays}: Thunk) =>
|
||||||
new Promise<PublishStatusDataByUrl>(resolve => {
|
new Promise<PublishStatusDataByUrl>(resolve => {
|
||||||
thunkWorker.push({...thunk, resolve})
|
event = prepEvent(event)
|
||||||
repository.publish(thunk.event)
|
|
||||||
|
thunkWorker.push({event, relays, resolve})
|
||||||
|
repository.publish(event)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {parseJson, append, nthNe, nthEq} from "@welshman/lib"
|
import {parseJson, append, nthNe, nthEq} from "@welshman/lib"
|
||||||
import {Address} from "./Address"
|
import {Address} from "./Address"
|
||||||
|
import {uniqTags} from "./Tags"
|
||||||
import {isShareableRelayUrl} from "./Relay"
|
import {isShareableRelayUrl} from "./Relay"
|
||||||
import {Encryptable, DecryptedEvent} from "./Encryptable"
|
import {Encryptable, DecryptedEvent} from "./Encryptable"
|
||||||
import type {EncryptableUpdates} from "./Encryptable"
|
import type {EncryptableUpdates} from "./Encryptable"
|
||||||
@@ -63,7 +64,7 @@ export const addToListPublicly = (list: List, tag: string[]) => {
|
|||||||
const template = {
|
const template = {
|
||||||
kind: list.kind,
|
kind: list.kind,
|
||||||
content: list.event?.content || "",
|
content: list.event?.content || "",
|
||||||
tags: append(tag, list.publicTags),
|
tags: uniqTags(append(tag, list.publicTags)),
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Encryptable(template, {})
|
return new Encryptable(template, {})
|
||||||
@@ -76,6 +77,6 @@ export const addToListPrivately = (list: List, tag: string[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Encryptable(template, {
|
return new Encryptable(template, {
|
||||||
content: JSON.stringify(append(tag, list.privateTags)),
|
content: JSON.stringify(uniqTags(append(tag, list.privateTags))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user