add timeouts for nostr extension calls
This commit is contained in:
parent
efd48afd61
commit
9455847484
|
@ -15,6 +15,7 @@ import { useMe } from './me'
|
||||||
import useCrossposter from './use-crossposter'
|
import useCrossposter from './use-crossposter'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { ItemButtonBar } from './post'
|
import { ItemButtonBar } from './post'
|
||||||
|
import { callWithTimeout } from '../lib/nostr'
|
||||||
|
|
||||||
export function DiscussionForm ({
|
export function DiscussionForm ({
|
||||||
item, sub, editThreshold, titleLabel = 'title',
|
item, sub, editThreshold, titleLabel = 'title',
|
||||||
|
@ -53,10 +54,12 @@ export function DiscussionForm ({
|
||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
async ({ boost, crosspost, ...values }) => {
|
async ({ boost, crosspost, ...values }) => {
|
||||||
try {
|
try {
|
||||||
if (crosspost && !(await window.nostr.getPublicKey())) {
|
if (crosspost) {
|
||||||
throw new Error('not available')
|
const pubkey = await callWithTimeout(() => window.nostr.getPublicKey(), 5000)
|
||||||
|
if (!pubkey) throw new Error('failed to get pubkey')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
throw new Error(`Nostr extension error: ${e.message}`)
|
throw new Error(`Nostr extension error: ${e.message}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,18 +84,18 @@ export function DiscussionForm ({
|
||||||
if (crosspost && discussionId) {
|
if (crosspost && discussionId) {
|
||||||
const crosspostResult = await crossposter({ ...values, id: discussionId })
|
const crosspostResult = await crossposter({ ...values, id: discussionId })
|
||||||
noteId = crosspostResult?.noteId
|
noteId = crosspostResult?.noteId
|
||||||
|
if (noteId) {
|
||||||
|
await updateNoteId({
|
||||||
|
variables: {
|
||||||
|
id: discussionId,
|
||||||
|
noteId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
toaster.danger('Error crossposting to Nostr', e.message)
|
||||||
|
|
||||||
if (noteId) {
|
|
||||||
await updateNoteId({
|
|
||||||
variables: {
|
|
||||||
id: discussionId,
|
|
||||||
noteId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -122,7 +125,7 @@ export function DiscussionForm ({
|
||||||
initial={{
|
initial={{
|
||||||
title: item?.title || shareTitle || '',
|
title: item?.title || shareTitle || '',
|
||||||
text: item?.text || '',
|
text: item?.text || '',
|
||||||
crosspost: me?.privates?.nostrCrossposting,
|
crosspost: item ? !!item.noteId : me?.privates?.nostrCrossposting,
|
||||||
...AdvPostInitial({ forward: normalizeForwards(item?.forwards), boost: item?.boost }),
|
...AdvPostInitial({ forward: normalizeForwards(item?.forwards), boost: item?.boost }),
|
||||||
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { useRouter } from 'next/router'
|
||||||
import AccordianItem from './accordian-item'
|
import AccordianItem from './accordian-item'
|
||||||
import BackIcon from '../svgs/arrow-left-line.svg'
|
import BackIcon from '../svgs/arrow-left-line.svg'
|
||||||
import styles from './lightning-auth.module.css'
|
import styles from './lightning-auth.module.css'
|
||||||
|
import { callWithTimeout } from '../lib/nostr'
|
||||||
|
|
||||||
function ExtensionError ({ message, details }) {
|
function ExtensionError ({ message, details }) {
|
||||||
return (
|
return (
|
||||||
|
@ -94,12 +95,12 @@ export function NostrAuth ({ text, callbackUrl }) {
|
||||||
// have them sign a message with the challenge
|
// have them sign a message with the challenge
|
||||||
let event
|
let event
|
||||||
try {
|
try {
|
||||||
event = await window.nostr.signEvent({
|
event = await callWithTimeout(() => window.nostr.signEvent({
|
||||||
kind: 22242,
|
kind: 22242,
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
tags: [['challenge', k1]],
|
tags: [['challenge', k1]],
|
||||||
content: 'Stacker News Authentication'
|
content: 'Stacker News Authentication'
|
||||||
})
|
}), 5000)
|
||||||
if (!event) throw new Error('extension returned empty event')
|
if (!event) throw new Error('extension returned empty event')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === 'window.nostr call already executing' || !mounted) return
|
if (e.message === 'window.nostr call already executing' || !mounted) return
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { useMutation, gql } from '@apollo/client'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { useToast } from './toast'
|
import { useToast } from './toast'
|
||||||
import { SSR } from '../lib/constants'
|
import { SSR } from '../lib/constants'
|
||||||
|
import { callWithTimeout } from '../lib/nostr'
|
||||||
|
|
||||||
const getShareUrl = (item, me) => {
|
const getShareUrl = (item, me) => {
|
||||||
const path = `/items/${item?.id}${me ? `/r/${me.name}` : ''}`
|
const path = `/items/${item?.id}${me ? `/r/${me.name}` : ''}`
|
||||||
|
@ -77,7 +78,8 @@ export default function Share ({ item }) {
|
||||||
<Dropdown.Item
|
<Dropdown.Item
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
if (!(await window.nostr?.getPublicKey())) {
|
const pubkey = await callWithTimeout(() => window.nostr.getPublicKey(), 5000)
|
||||||
|
if (!pubkey) {
|
||||||
throw new Error('not available')
|
throw new Error('not available')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
12
lib/nostr.js
12
lib/nostr.js
|
@ -82,7 +82,7 @@ async function publishNostrEvent (signedEvent, relay) {
|
||||||
|
|
||||||
export async function crosspost (event, relays = DEFAULT_CROSSPOSTING_RELAYS) {
|
export async function crosspost (event, relays = DEFAULT_CROSSPOSTING_RELAYS) {
|
||||||
try {
|
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')
|
if (!signedEvent) throw new Error('failed to sign event')
|
||||||
|
|
||||||
const promises = relays.map(r => publishNostrEvent(signedEvent, r))
|
const promises = relays.map(r => publishNostrEvent(signedEvent, r))
|
||||||
|
@ -106,3 +106,13 @@ export async function crosspost (event, relays = DEFAULT_CROSSPOSTING_RELAYS) {
|
||||||
return { error }
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue