[MM-48926] Fetch new thread posts on websocket reconnect (#6844)
This commit is contained in:
parent
d019f06c0b
commit
7f7bfd7b72
6 changed files with 97 additions and 18 deletions
|
|
@ -79,11 +79,19 @@ export const switchToThread = async (serverUrl: string, rootId: string, isFromNo
|
|||
const teamId = channel.teamId || currentTeamId;
|
||||
|
||||
let switchingTeams = false;
|
||||
if (currentTeamId !== teamId) {
|
||||
if (currentTeamId === teamId) {
|
||||
const models = await prepareCommonSystemValues(operator, {
|
||||
currentChannelId: channel.id,
|
||||
});
|
||||
if (models.length) {
|
||||
await operator.batchRecords(models);
|
||||
}
|
||||
} else {
|
||||
const modelPromises: Array<Promise<Model[]>> = [];
|
||||
switchingTeams = true;
|
||||
modelPromises.push(addTeamToTeamHistory(operator, teamId, true));
|
||||
const commonValues: PrepareCommonSystemValuesArgs = {
|
||||
currentChannelId: channel.id,
|
||||
currentTeamId: teamId,
|
||||
};
|
||||
modelPromises.push(prepareCommonSystemValues(operator, commonValues));
|
||||
|
|
|
|||
|
|
@ -534,6 +534,10 @@ export async function handleEntryAfterLoadNavigation(
|
|||
|
||||
const currentTeamIdAfterLoad = await getCurrentTeamId(database);
|
||||
const currentChannelIdAfterLoad = await getCurrentChannelId(database);
|
||||
const mountedScreens = NavigationStore.getScreensInStack();
|
||||
const isChannelScreenMounted = mountedScreens.includes(Screens.CHANNEL);
|
||||
const isThreadsMounted = mountedScreens.includes(Screens.THREAD);
|
||||
const tabletDevice = await isTablet();
|
||||
|
||||
if (currentTeamIdAfterLoad !== currentTeamId) {
|
||||
// Switched teams while loading
|
||||
|
|
@ -545,18 +549,14 @@ export async function handleEntryAfterLoadNavigation(
|
|||
} else if (currentChannelIdAfterLoad !== currentChannelId) {
|
||||
// Switched channels while loading
|
||||
if (!channelMembers.find((m) => m.channel_id === currentChannelIdAfterLoad)) {
|
||||
const tabletDevice = await isTablet();
|
||||
const navComponents = NavigationStore.getScreensInStack();
|
||||
if (tabletDevice || navComponents.includes(Screens.CHANNEL) || navComponents.includes(Screens.THREAD)) {
|
||||
if (tabletDevice || isChannelScreenMounted || isThreadsMounted) {
|
||||
await handleKickFromChannel(serverUrl, currentChannelIdAfterLoad);
|
||||
} else {
|
||||
await setCurrentTeamAndChannelId(operator, initialTeamId, initialChannelId);
|
||||
}
|
||||
}
|
||||
} else if (currentChannelIdAfterLoad !== initialChannelId) {
|
||||
const tabletDevice = await isTablet();
|
||||
const navComponents = NavigationStore.getScreensInStack();
|
||||
if (tabletDevice || navComponents.includes(Screens.CHANNEL) || navComponents.includes(Screens.THREAD)) {
|
||||
} else if (currentChannelIdAfterLoad && currentChannelIdAfterLoad !== initialChannelId) {
|
||||
if (tabletDevice || isChannelScreenMounted || isThreadsMounted) {
|
||||
await handleKickFromChannel(serverUrl, currentChannelIdAfterLoad);
|
||||
} else {
|
||||
await setCurrentTeamAndChannelId(operator, initialTeamId, initialChannelId);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@
|
|||
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {markChannelAsViewed} from '@actions/local/channel';
|
||||
import {markChannelAsRead} from '@actions/remote/channel';
|
||||
import {handleEntryAfterLoadNavigation} from '@actions/remote/entry/common';
|
||||
import {deferredAppEntryActions, entry} from '@actions/remote/entry/gql_common';
|
||||
import {fetchPostsForChannel, fetchPostThread} from '@actions/remote/post';
|
||||
import {fetchStatusByIds} from '@actions/remote/user';
|
||||
import {loadConfigAndCalls} from '@calls/actions/calls';
|
||||
import {
|
||||
|
|
@ -27,22 +30,28 @@ import {
|
|||
handleCallUserVoiceOn,
|
||||
} from '@calls/connection/websocket_event_handlers';
|
||||
import {isSupportedServerCalls} from '@calls/utils';
|
||||
import {Events, WebsocketEvents} from '@constants';
|
||||
import {Events, Screens, WebsocketEvents} from '@constants';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import AppsManager from '@managers/apps_manager';
|
||||
import {getActiveServerUrl} from '@queries/app/servers';
|
||||
import {getCurrentChannel} from '@queries/servers/channel';
|
||||
import {getLastPostInThread} from '@queries/servers/post';
|
||||
import {
|
||||
getConfig,
|
||||
getCurrentChannelId,
|
||||
getCurrentUserId,
|
||||
getLicense,
|
||||
getWebSocketLastDisconnected,
|
||||
resetWebSocketLastDisconnected,
|
||||
} from '@queries/servers/system';
|
||||
import {getCurrentTeam} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {logInfo} from '@utils/log';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug, logInfo} from '@utils/log';
|
||||
|
||||
import {handleCategoryCreatedEvent, handleCategoryDeletedEvent, handleCategoryOrderUpdatedEvent, handleCategoryUpdatedEvent} from './category';
|
||||
import {handleChannelConvertedEvent, handleChannelCreatedEvent,
|
||||
|
|
@ -151,6 +160,8 @@ async function doReconnect(serverUrl: string) {
|
|||
await operator.batchRecords(models);
|
||||
logInfo('WEBSOCKET RECONNECT MODELS BATCHING TOOK', `${Date.now() - dt}ms`);
|
||||
|
||||
await fetchPostDataIfNeeded(serverUrl);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(database))!;
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
|
@ -398,3 +409,41 @@ export async function handleEvent(serverUrl: string, msg: WebSocketMessage) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchPostDataIfNeeded(serverUrl: string) {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const currentChannelId = await getCurrentChannelId(database);
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const mountedScreens = NavigationStore.getScreensInStack();
|
||||
const isChannelScreenMounted = mountedScreens.includes(Screens.CHANNEL);
|
||||
const isThreadScreenMounted = mountedScreens.includes(Screens.THREAD);
|
||||
const tabletDevice = await isTablet();
|
||||
|
||||
if (isCRTEnabled && isThreadScreenMounted) {
|
||||
// Fetch new posts in the thread only when CRT is enabled,
|
||||
// for non-CRT fetchPostsForChannel includes posts in the thread
|
||||
const rootId = EphemeralStore.getCurrentThreadId();
|
||||
if (rootId) {
|
||||
const lastPost = await getLastPostInThread(database, rootId);
|
||||
if (lastPost) {
|
||||
if (lastPost) {
|
||||
const options: FetchPaginatedThreadOptions = {};
|
||||
options.fromCreateAt = lastPost.createAt;
|
||||
options.fromPost = lastPost.id;
|
||||
options.direction = 'down';
|
||||
await fetchPostThread(serverUrl, rootId, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentChannelId && (isChannelScreenMounted || tabletDevice)) {
|
||||
await fetchPostsForChannel(serverUrl, currentChannelId);
|
||||
markChannelAsRead(serverUrl, currentChannelId);
|
||||
markChannelAsViewed(serverUrl, currentChannelId);
|
||||
}
|
||||
} catch (error) {
|
||||
logDebug('could not fetch needed post after WS reconnect', error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,20 @@ export const getRecentPostsInThread = async (database: Database, rootId: string)
|
|||
return [];
|
||||
};
|
||||
|
||||
export const queryPostsChunk = (database: Database, id: string, earliest: number, latest: number, inThread = false, includeDeleted = false) => {
|
||||
export const getLastPostInThread = async (database: Database, rootId: string) => {
|
||||
const chunks = await queryPostsInThread(database, rootId, true, true).fetch();
|
||||
if (chunks.length) {
|
||||
const recent = chunks[0];
|
||||
const post = await getPostById(database, rootId);
|
||||
if (post) {
|
||||
const posts = await queryPostsChunk(database, rootId, recent.earliest, recent.latest, true, true, 1).fetch();
|
||||
return posts[0];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const queryPostsChunk = (database: Database, id: string, earliest: number, latest: number, inThread = false, includeDeleted = false, limit = 0) => {
|
||||
const conditions: Q.Condition[] = [Q.where('create_at', Q.between(earliest, latest))];
|
||||
if (inThread) {
|
||||
conditions.push(Q.where('root_id', id));
|
||||
|
|
@ -138,12 +151,18 @@ export const queryPostsChunk = (database: Database, id: string, earliest: number
|
|||
conditions.push(Q.where('delete_at', Q.eq(0)));
|
||||
}
|
||||
|
||||
return database.get<PostModel>(POST).query(
|
||||
const clauses: Q.Clause[] = [
|
||||
Q.and(
|
||||
...conditions,
|
||||
),
|
||||
Q.sortBy('create_at', Q.desc),
|
||||
);
|
||||
];
|
||||
|
||||
if (limit) {
|
||||
clauses.push(Q.take(limit));
|
||||
}
|
||||
|
||||
return database.get<PostModel>(POST).query(...clauses);
|
||||
};
|
||||
|
||||
export const getRecentPostsInChannel = async (database: Database, channelId: string, includeDeleted = false) => {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ const enhanced = withObservables(['tab', 'teamId', 'forceQueryAfterAppState'], (
|
|||
teammateNameDisplay: observeTeammateNameDisplay(database),
|
||||
threads: teamThreadsSyncObserver.pipe(
|
||||
switchMap((teamThreadsSync) => {
|
||||
const earliest = teamThreadsSync?.[0]?.earliest;
|
||||
const earliest = tab === 'all' ? teamThreadsSync?.[0]?.earliest : 0;
|
||||
return queryThreadsInTeam(database, teamId, getOnlyUnreads, false, true, true, earliest).observe();
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ const alpha = {
|
|||
};
|
||||
|
||||
export function registerNavigationListeners() {
|
||||
Navigation.events().registerScreenPoppedListener(screenPoppedListener);
|
||||
Navigation.events().registerCommandListener(registerCommandListener);
|
||||
Navigation.events().registerScreenPoppedListener(onPoppedListener);
|
||||
Navigation.events().registerCommandListener(onCommandListener);
|
||||
}
|
||||
|
||||
function registerCommandListener(name: string, params: any) {
|
||||
function onCommandListener(name: string, params: any) {
|
||||
switch (name) {
|
||||
case 'setRoot':
|
||||
NavigationStore.clearScreensFromStack();
|
||||
|
|
@ -63,9 +63,12 @@ function registerCommandListener(name: string, params: any) {
|
|||
}
|
||||
}
|
||||
|
||||
function screenPoppedListener({componentId}: ScreenPoppedEvent) {
|
||||
function onPoppedListener({componentId}: ScreenPoppedEvent) {
|
||||
// screen pop does not trigger registerCommandListener, but does trigger screenPoppedListener
|
||||
NavigationStore.removeScreenFromStack(componentId);
|
||||
if (NavigationStore.getVisibleScreen() === Screens.HOME) {
|
||||
DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true);
|
||||
}
|
||||
}
|
||||
|
||||
export const loginAnimationOptions = () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue