poll for messages on chat push notification
stop polling entirely in the background (resume already triggers an immediate catch-up poll), and force an immediate poll when a chat push notification arrives while foregrounded via a new pollNow() on the event bus. APP-2415 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
|||||||
import {logger as notyLogger} from '#/lib/notifications/util'
|
import {logger as notyLogger} from '#/lib/notifications/util'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {useCurrentConvoId} from '#/state/messages/current-convo-id'
|
import {useCurrentConvoId} from '#/state/messages/current-convo-id'
|
||||||
|
import {useMaybeMessagesEventBus} from '#/state/messages/events'
|
||||||
import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'
|
import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'
|
||||||
import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread'
|
import {invalidateCachedUnreadPage} from '#/state/queries/notifications/unread'
|
||||||
import {truncateAndInvalidate} from '#/state/queries/util'
|
import {truncateAndInvalidate} from '#/state/queries/util'
|
||||||
@@ -114,6 +115,7 @@ export function useNotificationsHandler() {
|
|||||||
const {onPressSwitchAccount} = useAccountSwitcher()
|
const {onPressSwitchAccount} = useAccountSwitcher()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {currentConvoId} = useCurrentConvoId()
|
const {currentConvoId} = useCurrentConvoId()
|
||||||
|
const messagesBus = useMaybeMessagesEventBus()
|
||||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
const closeAllActiveElements = useCloseAllActiveElements()
|
const closeAllActiveElements = useCloseAllActiveElements()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -316,6 +318,11 @@ export function useNotificationsHandler() {
|
|||||||
isChatNotificationPayload(payload) &&
|
isChatNotificationPayload(payload) &&
|
||||||
payload.recipientDid === currentAccount?.did
|
payload.recipientDid === currentAccount?.did
|
||||||
) {
|
) {
|
||||||
|
// A chat push means new events probably exist - force an immediate
|
||||||
|
// poll so the convo list / open convo update without waiting for the
|
||||||
|
// next scheduled tick. No-op unless the bus is actively polling.
|
||||||
|
messagesBus?.pollNow()
|
||||||
|
|
||||||
// chat-removed-from-group / chat-join-request-rejected always alert,
|
// chat-removed-from-group / chat-join-request-rejected always alert,
|
||||||
// even if the recipient is currently viewing the affected convo -
|
// even if the recipient is currently viewing the affected convo -
|
||||||
// they need to know they were removed/rejected.
|
// they need to know they were removed/rejected.
|
||||||
@@ -425,6 +432,7 @@ export function useNotificationsHandler() {
|
|||||||
navigation,
|
navigation,
|
||||||
onPressSwitchAccount,
|
onPressSwitchAccount,
|
||||||
setShowLoggedOut,
|
setShowLoggedOut,
|
||||||
|
messagesBus,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ import {
|
|||||||
isNetworkError,
|
isNetworkError,
|
||||||
} from '#/lib/strings/errors'
|
} from '#/lib/strings/errors'
|
||||||
import {Logger} from '#/logger'
|
import {Logger} from '#/logger'
|
||||||
import {
|
import {DEFAULT_POLL_INTERVAL} from '#/state/messages/events/const'
|
||||||
BACKGROUND_POLL_INTERVAL,
|
|
||||||
DEFAULT_POLL_INTERVAL,
|
|
||||||
} from '#/state/messages/events/const'
|
|
||||||
import {
|
import {
|
||||||
type MessagesEventBusDispatch,
|
type MessagesEventBusDispatch,
|
||||||
MessagesEventBusDispatchEvent,
|
MessagesEventBusDispatchEvent,
|
||||||
@@ -56,6 +53,17 @@ export class MessagesEventBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force an immediate poll and restart the interval clock from now. Only has
|
||||||
|
* an effect while we're actively polling (Ready) - the dispatched UpdatePoll
|
||||||
|
* is a no-op in other states (init/resume will poll on their own). Used when
|
||||||
|
* an external signal (a chat push notification) tells us new events probably
|
||||||
|
* exist and we don't want to wait for the next scheduled tick.
|
||||||
|
*/
|
||||||
|
pollNow() {
|
||||||
|
this.dispatch({event: MessagesEventBusDispatchEvent.UpdatePoll})
|
||||||
|
}
|
||||||
|
|
||||||
getLatestRev() {
|
getLatestRev() {
|
||||||
return this.latestRev
|
return this.latestRev
|
||||||
}
|
}
|
||||||
@@ -122,7 +130,7 @@ export class MessagesEventBus {
|
|||||||
}
|
}
|
||||||
case MessagesEventBusDispatchEvent.Background: {
|
case MessagesEventBusDispatchEvent.Background: {
|
||||||
this.status = MessagesEventBusStatus.Backgrounded
|
this.status = MessagesEventBusStatus.Backgrounded
|
||||||
this.resetPoll()
|
this.stopPoll()
|
||||||
this.emitter.emit('event', {type: 'connect'})
|
this.emitter.emit('event', {type: 'connect'})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -142,7 +150,7 @@ export class MessagesEventBus {
|
|||||||
switch (action.event) {
|
switch (action.event) {
|
||||||
case MessagesEventBusDispatchEvent.Background: {
|
case MessagesEventBusDispatchEvent.Background: {
|
||||||
this.status = MessagesEventBusStatus.Backgrounded
|
this.status = MessagesEventBusStatus.Backgrounded
|
||||||
this.resetPoll()
|
this.stopPoll()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case MessagesEventBusDispatchEvent.Suspend: {
|
case MessagesEventBusDispatchEvent.Suspend: {
|
||||||
@@ -181,10 +189,6 @@ export class MessagesEventBus {
|
|||||||
this.emitter.emit('event', {type: 'error', error: action.payload})
|
this.emitter.emit('event', {type: 'error', error: action.payload})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case MessagesEventBusDispatchEvent.UpdatePoll: {
|
|
||||||
this.resetPoll()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -197,7 +201,7 @@ export class MessagesEventBus {
|
|||||||
}
|
}
|
||||||
case MessagesEventBusDispatchEvent.Background: {
|
case MessagesEventBusDispatchEvent.Background: {
|
||||||
this.status = MessagesEventBusStatus.Backgrounded
|
this.status = MessagesEventBusStatus.Backgrounded
|
||||||
this.resetPoll()
|
this.stopPoll()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case MessagesEventBusDispatchEvent.Error: {
|
case MessagesEventBusDispatchEvent.Error: {
|
||||||
@@ -313,9 +317,6 @@ export class MessagesEventBus {
|
|||||||
const lowest = Math.min(DEFAULT_POLL_INTERVAL, ...requested)
|
const lowest = Math.min(DEFAULT_POLL_INTERVAL, ...requested)
|
||||||
return lowest
|
return lowest
|
||||||
}
|
}
|
||||||
case MessagesEventBusStatus.Backgrounded: {
|
|
||||||
return BACKGROUND_POLL_INTERVAL
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return DEFAULT_POLL_INTERVAL
|
return DEFAULT_POLL_INTERVAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export const DEFAULT_POLL_INTERVAL = 60e3
|
export const DEFAULT_POLL_INTERVAL = 60e3
|
||||||
export const BACKGROUND_POLL_INTERVAL = 60e3 * 5
|
|
||||||
|
|||||||
@@ -17,6 +17,15 @@ export function useMessagesEventBus() {
|
|||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like useMessagesEventBus, but returns null instead of throwing when there's
|
||||||
|
* no bus (e.g. when logged out, where the provider supplies a null value).
|
||||||
|
* Use this from always-mounted consumers that may run without a session.
|
||||||
|
*/
|
||||||
|
export function useMaybeMessagesEventBus() {
|
||||||
|
return useContext(MessagesEventBusContext)
|
||||||
|
}
|
||||||
|
|
||||||
export function MessagesEventBusProvider({
|
export function MessagesEventBusProvider({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
Reference in New Issue
Block a user