diff --git a/src/screens/Messages/Conversation/MessageListFirehoseError.tsx b/src/screens/Messages/Conversation/MessageListFirehoseError.tsx
new file mode 100644
index 0000000000..63b06c413e
--- /dev/null
+++ b/src/screens/Messages/Conversation/MessageListFirehoseError.tsx
@@ -0,0 +1,54 @@
+import React from 'react'
+import {View} from 'react-native'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {ConvoItem} from '#/state/messages/convo/types'
+import {atoms as a, useTheme} from '#/alf'
+import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
+import {InlineLinkText} from '#/components/Link'
+import {Text} from '#/components/Typography'
+
+export function MessageListFirehoseError({
+ item,
+}: {
+ item: ConvoItem & {type: 'firehose-error'}
+}) {
+ const t = useTheme()
+ const {_} = useLingui()
+
+ return (
+
+
+
+
+
+ {_(msg`This chat was disconnected`)} ·{' '}
+ {item.retry && (
+ {
+ e.preventDefault()
+ item.retry?.()
+ return false
+ }}>
+ {_(msg`Reconnect`)}
+
+ )}
+
+
+
+ )
+}
diff --git a/src/screens/Messages/Conversation/MessagesList.tsx b/src/screens/Messages/Conversation/MessagesList.tsx
index bb65567a27..2fb848cc7b 100644
--- a/src/screens/Messages/Conversation/MessagesList.tsx
+++ b/src/screens/Messages/Conversation/MessagesList.tsx
@@ -15,6 +15,7 @@ import {isWeb} from 'platform/detection'
import {List} from 'view/com/util/List'
import {MessageInput} from '#/screens/Messages/Conversation/MessageInput'
import {MessageListError} from '#/screens/Messages/Conversation/MessageListError'
+import {MessageListFirehoseError} from '#/screens/Messages/Conversation/MessageListFirehoseError'
import {atoms as a} from '#/alf'
import {MessageItem} from '#/components/dms/MessageItem'
import {Loader} from '#/components/Loader'
@@ -41,6 +42,8 @@ function renderItem({item}: {item: ConvoItem}) {
return Deleted message
} else if (item.type === 'error') {
return
+ } else if (item.type === 'firehose-error') {
+ return
}
return null
diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts
index 679de8b700..a0ea7fc18b 100644
--- a/src/state/messages/convo/agent.ts
+++ b/src/state/messages/convo/agent.ts
@@ -21,6 +21,7 @@ import {
import {
ConvoDispatch,
ConvoDispatchEvent,
+ ConvoError,
ConvoErrorCode,
ConvoEvent,
ConvoItem,
@@ -55,13 +56,7 @@ export class Convo {
private senderUserDid: string
private status: ConvoStatus = ConvoStatus.Uninitialized
- private error:
- | {
- code: ConvoErrorCode
- exception?: Error
- retry: () => void
- }
- | undefined
+ private error: ConvoError | undefined
private oldestRev: string | undefined | null = undefined
private isFetchingHistory = false
private latestRev: string | undefined = undefined
@@ -79,7 +74,6 @@ export class Convo {
{id: string; message: ChatBskyConvoSendMessage.InputSchema['message']}
> = new Map()
private deletedMessages: Set = new Set()
- private footerItems: Map = new Map()
private headerItems: Map = new Map()
private isProcessingPendingMessages = false
@@ -180,7 +174,7 @@ export class Convo {
status: ConvoStatus.Error,
items: [],
convo: undefined,
- error: this.error,
+ error: this.error!,
sender: undefined,
recipients: undefined,
isFetchingHistory: false,
@@ -288,7 +282,7 @@ export class Convo {
if (this.convo) {
this.status = ConvoStatus.Ready
this.refreshConvo()
- this.attemptCleanup()
+ this.maybeRecoverFromNetworkError()
} else {
this.status = ConvoStatus.Initializing
this.setup()
@@ -386,7 +380,6 @@ export class Convo {
this.newMessages = new Map()
this.pendingMessages = new Map()
this.deletedMessages = new Set()
- this.footerItems = new Map()
this.headerItems = new Map()
this.pendingMessageFailure = null
@@ -394,10 +387,14 @@ export class Convo {
this.dispatch({event: ConvoDispatchEvent.Init})
}
- private attemptCleanup() {
- // override what's here in case remote convo state has changed
- this.pendingMessageFailure = 'recoverable'
- this.batchRetryPendingMessages()
+ maybeRecoverFromNetworkError() {
+ if (this.firehoseError) {
+ this.firehoseError.retry()
+ this.firehoseError = undefined
+ this.commit()
+ } else {
+ this.batchRetryPendingMessages()
+ }
}
private async setup() {
@@ -643,22 +640,16 @@ export class Convo {
)
}
+ private firehoseError: MessagesEventBusError | undefined
+
onFirehoseConnect() {
- this.footerItems.delete(ConvoItemError.FirehoseFailed)
+ this.firehoseError = undefined
+ this.batchRetryPendingMessages()
this.commit()
}
onFirehoseError(error?: MessagesEventBusError) {
- this.footerItems.set(ConvoItemError.FirehoseFailed, {
- type: 'error',
- key: ConvoItemError.FirehoseFailed,
- code: ConvoItemError.FirehoseFailed,
- retry: () => {
- this.footerItems.delete(ConvoItemError.FirehoseFailed)
- this.commit()
- error?.retry()
- },
- })
+ this.firehoseError = error
this.commit()
}
@@ -852,18 +843,14 @@ export class Convo {
}
async batchRetryPendingMessages() {
- if (this.pendingMessageFailure === 'unrecoverable') return
-
- // reset if present, and recoverable
- if (this.pendingMessageFailure === 'recoverable') {
- this.pendingMessageFailure = null
- this.commit()
- }
+ if (this.pendingMessageFailure === null) return
const messageArray = Array.from(this.pendingMessages.values())
-
if (messageArray.length === 0) return
+ this.pendingMessageFailure = null
+ this.commit()
+
logger.debug(
`Convo: batch retrying ${this.pendingMessages.size} pending messages`,
{},
@@ -1012,15 +999,21 @@ export class Convo {
retry:
this.pendingMessageFailure === 'recoverable'
? () => {
- this.batchRetryPendingMessages()
+ this.maybeRecoverFromNetworkError()
}
: undefined,
})
})
- this.footerItems.forEach(item => {
- items.push(item)
- })
+ if (this.firehoseError) {
+ items.push({
+ type: 'firehose-error',
+ key: 'firehose-error',
+ retry: () => {
+ this.firehoseError?.retry()
+ },
+ })
+ }
return items
.filter(item => {
diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts
index 2305c952f7..01b24a2a17 100644
--- a/src/state/messages/convo/types.ts
+++ b/src/state/messages/convo/types.ts
@@ -123,6 +123,14 @@ export type ConvoItem =
*/
retry?: () => void
}
+ | {
+ type: 'firehose-error'
+ key: string
+ /**
+ * If present, error is recoverable.
+ */
+ retry?: () => void
+ }
type DeleteMessage = (messageId: string) => Promise
type SendMessage = (
@@ -194,7 +202,7 @@ export type ConvoStateError = {
status: ConvoStatus.Error
items: []
convo: undefined
- error: any
+ error: ConvoError
sender: undefined
recipients: undefined
isFetchingHistory: false