diff --git a/public/locales/en/notify.json b/public/locales/en/notify.json index 4fd150685..e7e8bee3a 100644 --- a/public/locales/en/notify.json +++ b/public/locales/en/notify.json @@ -7,6 +7,7 @@ "ipfsPinFailReason": "Unable to set pinning at {serviceName}: {errorMsg}", "ipfsPinSucceedReason": "Successfully pinned at {serviceName}", "ipfsUnpinSucceedReason": "Successfully unpinned from {serviceName}", + "ipnsPublishFailReason": "Unable to publish to IPNS under key {keyName}: {errorMsg}", "ipfsIsBack": "Normal IPFS service has resumed. Enjoy!", "folderExists": "An item with that name already exists. Please choose another.", "filesFetchFailed": "Failed to get those files. Please check the path and try again.", diff --git a/src/bundles/ipns.js b/src/bundles/ipns.js index 86c3459b8..deafe82ac 100644 --- a/src/bundles/ipns.js +++ b/src/bundles/ipns.js @@ -59,9 +59,18 @@ const ipnsBundle = { store.doFetchIpnsKeys() }, - doPublishIpnsKey: (cid, key) => async ({ getIpfs, store }) => { + doPublishIpnsKey: (cid, key) => async ({ getIpfs, dispatch }) => { const ipfs = getIpfs() - await ipfs.name.publish(cid, { key }) + + try { + await ipfs.name.publish(cid, { key }) + } catch (err) { + // Surface the RPC failure as a toast and re-throw so the publish modal + // leaves its progress state instead of hanging on a finished-looking bar. + console.error(`unexpected error publishing IPNS record for ${cid} (key: ${key})`, err) + dispatch({ type: 'IPNS_PUBLISH_FAILED', msgArgs: { keyName: key, errorMsg: err.toString() } }) + throw err + } // Trigger background provide operation for the published CID dispatchAsyncProvide(cid, ipfs, 'IPNS') diff --git a/src/bundles/notify.js b/src/bundles/notify.js index 7bd7ca256..d4021ec37 100644 --- a/src/bundles/notify.js +++ b/src/bundles/notify.js @@ -100,6 +100,16 @@ const notify = { } } + if (action.type === 'IPNS_PUBLISH_FAILED') { + return { + ...state, + show: true, + error: true, + msgArgs: action.msgArgs, + eventId: action.type + } + } + if (action.type === 'IPFS_CONNECT_FAILED') { return { ...state, @@ -159,6 +169,9 @@ const notify = { if (eventId === 'IPFS_UNPIN_SUCCEED') { return 'ipfsUnpinSucceedReason' } + if (eventId === 'IPNS_PUBLISH_FAILED') { + return 'ipnsPublishFailReason' + } if (eventId === 'FILES_EVENT_FAILED') { const type = code ? code.replace(/^(ERR_)/, '') : '' diff --git a/src/bundles/notify.test.js b/src/bundles/notify.test.js index f879a09b9..675fcdf6c 100644 --- a/src/bundles/notify.test.js +++ b/src/bundles/notify.test.js @@ -87,3 +87,17 @@ it('should notify about file errors', async () => { expect(store.selectNotifyI18nKey()).toEqual('filesEventFailed') store.dispatch({ type: 'FILES_WRITE_FINISHED' }) }) + +it('should notify about IPNS publish errors with the original message', async () => { + const store = composeBundlesRaw( + appTimeBundle, + ipfsBundle(), + notifyBundle + )() + expect(store.selectNotify().show).toEqual(false) + store.dispatch({ type: 'IPNS_PUBLISH_FAILED', msgArgs: { keyName: 'self', errorMsg: 'Error: Internal Server Error' } }) + expect(store.selectNotify().show).toEqual(true) + expect(store.selectNotify().error).toEqual(true) + expect(store.selectNotify().msgArgs).toEqual({ keyName: 'self', errorMsg: 'Error: Internal Server Error' }) + expect(store.selectNotifyI18nKey()).toEqual('ipnsPublishFailReason') +}) diff --git a/src/files/modals/publish-modal/PublishModal.js b/src/files/modals/publish-modal/PublishModal.js index 2421e9199..810e1ec36 100644 --- a/src/files/modals/publish-modal/PublishModal.js +++ b/src/files/modals/publish-modal/PublishModal.js @@ -45,6 +45,7 @@ export const PublishModal = ({ t, tReady, onLeave, onSubmit, file, ipnsKeys, pub try { const startTs = new Date().getTime() setStart(startTs) + setError(null) await onSubmit(selectedKey.name) setLink(`${publicGateway}/ipns/${selectedKey.id}`) @@ -53,6 +54,8 @@ export const PublishModal = ({ t, tReady, onLeave, onSubmit, file, ipnsKeys, pub const endTs = new Date().getTime() doUpdateExpectedPublishTime((endTs - startTs) / 1000) } catch (err) { + // Leave the progress state so the error renders and Publish re-enables for a retry. + setStart(null) setError(err) } }