feat: require success on one-third of relays to consider publish successful

This commit is contained in:
codytseng
2025-09-30 16:59:14 +08:00
parent bdeee4ec31
commit 687eca821d
2 changed files with 39 additions and 21 deletions

View File

@@ -149,12 +149,14 @@ export default function PostContent({
addReplies([newEvent]) addReplies([newEvent])
close() close()
} catch (error) { } catch (error) {
if (error instanceof AggregateError) { const errors = error instanceof AggregateError ? error.errors : [error]
error.errors.forEach((e) => toast.error(`${t('Failed to post')}: ${e.message}`)) errors.forEach((err) => {
} else if (error instanceof Error) { toast.error(
toast.error(`${t('Failed to post')}: ${error.message}`) `${t('Failed to post')}: ${err instanceof Error ? err.message : String(err)}`,
} { duration: 10_000 }
console.error(error) )
console.error(err)
})
return return
} finally { } finally {
setPosting(false) setPosting(false)

View File

@@ -144,9 +144,12 @@ class ClientService extends EventTarget {
} }
async publishEvent(relayUrls: string[], event: NEvent) { async publishEvent(relayUrls: string[], event: NEvent) {
try {
const uniqueRelayUrls = Array.from(new Set(relayUrls)) const uniqueRelayUrls = Array.from(new Set(relayUrls))
const result = await Promise.any( await new Promise<void>((resolve, reject) => {
let successCount = 0
let finishedCount = 0
const errors: { url: string; error: any }[] = []
Promise.allSettled(
uniqueRelayUrls.map(async (url) => { uniqueRelayUrls.map(async (url) => {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this const that = this
@@ -154,6 +157,10 @@ class ClientService extends EventTarget {
relay.publishTimeout = 10_000 // 10s relay.publishTimeout = 10_000 // 10s
return relay return relay
.publish(event) .publish(event)
.then(() => {
this.trackEventSeenOn(event.id, relay)
successCount++
})
.catch((error) => { .catch((error) => {
if ( if (
error instanceof Error && error instanceof Error &&
@@ -164,23 +171,32 @@ class ClientService extends EventTarget {
.auth((authEvt: EventTemplate) => that.signer!.signEvent(authEvt)) .auth((authEvt: EventTemplate) => that.signer!.signEvent(authEvt))
.then(() => relay.publish(event)) .then(() => relay.publish(event))
} else { } else {
throw error errors.push({ url, error })
} }
}) })
.then((reason) => { .finally(() => {
this.trackEventSeenOn(event.id, relay) // If one third of the relays have accepted the event, consider it a success
return reason const isSuccess = successCount >= uniqueRelayUrls.length / 3
if (isSuccess) {
this.emitNewEvent(event)
resolve()
}
if (++finishedCount >= uniqueRelayUrls.length) {
reject(
new AggregateError(
errors.map(
({ url, error }) =>
new Error(
`${url}: ${error instanceof Error ? error.message : String(error)}`
)
)
)
)
}
}) })
}) })
) )
this.emitNewEvent(event) })
return result
} catch (error) {
if (error instanceof AggregateError) {
throw error.errors[0]
}
throw error
}
} }
emitNewEvent(event: NEvent) { emitNewEvent(event: NEvent) {