add timeouts for nostr extension calls

This commit is contained in:
keyan 2023-12-19 16:01:48 -06:00
parent efd48afd61
commit 9455847484
4 changed files with 32 additions and 16 deletions

View File

@ -15,6 +15,7 @@ import { useMe } from './me'
import useCrossposter from './use-crossposter'
import { useToast } from './toast'
import { ItemButtonBar } from './post'
import { callWithTimeout } from '../lib/nostr'
export function DiscussionForm ({
item, sub, editThreshold, titleLabel = 'title',
@ -53,10 +54,12 @@ export function DiscussionForm ({
const onSubmit = useCallback(
async ({ boost, crosspost, ...values }) => {
try {
if (crosspost && !(await window.nostr.getPublicKey())) {
throw new Error('not available')
if (crosspost) {
const pubkey = await callWithTimeout(() => window.nostr.getPublicKey(), 5000)
if (!pubkey) throw new Error('failed to get pubkey')
}
} catch (e) {
console.log(e)
throw new Error(`Nostr extension error: ${e.message}`)
}
@ -81,18 +84,18 @@ export function DiscussionForm ({
if (crosspost && discussionId) {
const crosspostResult = await crossposter({ ...values, id: discussionId })
noteId = crosspostResult?.noteId
if (noteId) {
await updateNoteId({
variables: {
id: discussionId,
noteId
}
})
}
}
} catch (e) {
console.error(e)
}
if (noteId) {
await updateNoteId({
variables: {
id: discussionId,
noteId
}
})
toaster.danger('Error crossposting to Nostr', e.message)
}
if (item) {
@ -122,7 +125,7 @@ export function DiscussionForm ({
initial={{
title: item?.title || shareTitle || '',
text: item?.text || '',
crosspost: me?.privates?.nostrCrossposting,
crosspost: item ? !!item.noteId : me?.privates?.nostrCrossposting,
...AdvPostInitial({ forward: normalizeForwards(item?.forwards), boost: item?.boost }),
...SubSelectInitial({ sub: item?.subName || sub?.name })
}}

View File

@ -8,6 +8,7 @@ import { useRouter } from 'next/router'
import AccordianItem from './accordian-item'
import BackIcon from '../svgs/arrow-left-line.svg'
import styles from './lightning-auth.module.css'
import { callWithTimeout } from '../lib/nostr'
function ExtensionError ({ message, details }) {
return (
@ -94,12 +95,12 @@ export function NostrAuth ({ text, callbackUrl }) {
// have them sign a message with the challenge
let event
try {
event = await window.nostr.signEvent({
event = await callWithTimeout(() => window.nostr.signEvent({
kind: 22242,
created_at: Math.floor(Date.now() / 1000),
tags: [['challenge', k1]],
content: 'Stacker News Authentication'
})
}), 5000)
if (!event) throw new Error('extension returned empty event')
} catch (e) {
if (e.message === 'window.nostr call already executing' || !mounted) return

View File

@ -6,6 +6,7 @@ import { useMutation, gql } from '@apollo/client'
import { useMe } from './me'
import { useToast } from './toast'
import { SSR } from '../lib/constants'
import { callWithTimeout } from '../lib/nostr'
const getShareUrl = (item, me) => {
const path = `/items/${item?.id}${me ? `/r/${me.name}` : ''}`
@ -77,7 +78,8 @@ export default function Share ({ item }) {
<Dropdown.Item
onClick={async () => {
try {
if (!(await window.nostr?.getPublicKey())) {
const pubkey = await callWithTimeout(() => window.nostr.getPublicKey(), 5000)
if (!pubkey) {
throw new Error('not available')
}
} catch (e) {

View File

@ -82,7 +82,7 @@ async function publishNostrEvent (signedEvent, relay) {
export async function crosspost (event, relays = DEFAULT_CROSSPOSTING_RELAYS) {
try {
const signedEvent = await window.nostr.signEvent(event)
const signedEvent = await callWithTimeout(() => window.nostr.signEvent(event), 5000)
if (!signedEvent) throw new Error('failed to sign event')
const promises = relays.map(r => publishNostrEvent(signedEvent, r))
@ -106,3 +106,13 @@ export async function crosspost (event, relays = DEFAULT_CROSSPOSTING_RELAYS) {
return { error }
}
}
export function callWithTimeout (targetFunction, timeoutMs) {
return new Promise((resolve, reject) => {
Promise.race([
targetFunction(),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('timeouted after ' + timeoutMs + ' ms waiting for extension')), timeoutMs))
]).then(resolve)
.catch(reject)
})
}