RN-379 Get posts since last websocket disconnect when viewing channel (#971)
* RN-379 Added websocket state to device state * Fixed view store blacklist * RN-379 Get posts since last websocket disconnect when viewing channel * Used Date.now instead of new Date().getTime()
This commit is contained in:
parent
c93f04a708
commit
8e526b61ed
6 changed files with 101 additions and 15 deletions
|
|
@ -13,7 +13,7 @@ import {
|
|||
leaveChannel as serviceLeaveChannel,
|
||||
unfavoriteChannel
|
||||
} from 'mattermost-redux/actions/channels';
|
||||
import {getPosts, getPostsWithRetry, getPostsBefore, getPostsSinceWithRetry, getPostThread} from 'mattermost-redux/actions/posts';
|
||||
import {getPosts, getPostsBefore, getPostsSince, getPostThread} from 'mattermost-redux/actions/posts';
|
||||
import {getFilesForPost} from 'mattermost-redux/actions/files';
|
||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||
import {getTeamMembersByIds} from 'mattermost-redux/actions/teams';
|
||||
|
|
@ -31,6 +31,8 @@ import {
|
|||
import {getLastCreateAt} from 'mattermost-redux/utils/post_utils';
|
||||
import {getPreferencesByCategory} from 'mattermost-redux/utils/preference_utils';
|
||||
|
||||
const MAX_POST_TRIES = 3;
|
||||
|
||||
export function loadChannelsIfNecessary(teamId) {
|
||||
return async (dispatch, getState) => {
|
||||
await fetchMyChannelsAndMembers(teamId)(dispatch, getState);
|
||||
|
|
@ -139,25 +141,57 @@ export function loadProfilesAndTeamMembersForDMSidebar(teamId) {
|
|||
}
|
||||
|
||||
export function loadPostsIfNecessaryWithRetry(channelId) {
|
||||
return (dispatch, getState) => {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const {posts, postsInChannel} = state.entities.posts;
|
||||
|
||||
const postsIds = postsInChannel[channelId];
|
||||
|
||||
// Get the first page of posts if it appears we haven't gotten it yet, like the webapp
|
||||
const time = Date.now();
|
||||
|
||||
let received;
|
||||
if (!postsIds || postsIds.length < ViewTypes.POST_VISIBILITY_CHUNK_SIZE) {
|
||||
getPostsWithRetry(channelId)(dispatch, getState);
|
||||
return;
|
||||
// Get the first page of posts if it appears we haven't gotten it yet, like the webapp
|
||||
received = await retryGetPostsAction(getPosts(channelId), dispatch, getState);
|
||||
} else {
|
||||
const {lastConnectAt} = state.device.websocket;
|
||||
const lastGetPosts = state.views.channel.lastGetPosts[channelId];
|
||||
|
||||
let since;
|
||||
if (lastGetPosts && lastGetPosts < lastConnectAt) {
|
||||
// Since the websocket disconnected, we may have missed some posts since then
|
||||
since = lastGetPosts;
|
||||
} else {
|
||||
// Trust that we've received all posts since the last time the websocket disconnected
|
||||
// so just get any that have changed since the latest one we've received
|
||||
const postsForChannel = postsIds.map((id) => posts[id]);
|
||||
since = getLastCreateAt(postsForChannel);
|
||||
}
|
||||
|
||||
received = await retryGetPostsAction(getPostsSince(channelId, since), dispatch, getState);
|
||||
}
|
||||
|
||||
const postsForChannel = postsIds.map((id) => posts[id]);
|
||||
const latestPostTime = getLastCreateAt(postsForChannel);
|
||||
|
||||
getPostsSinceWithRetry(channelId, latestPostTime)(dispatch, getState);
|
||||
if (received) {
|
||||
dispatch({
|
||||
type: ViewTypes.RECEIVED_POSTS_FOR_CHANNEL_AT_TIME,
|
||||
channelId,
|
||||
time
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function retryGetPostsAction(action, dispatch, getState, maxTries = MAX_POST_TRIES) {
|
||||
for (let i = 0; i < maxTries; i++) {
|
||||
const posts = await action(dispatch, getState);
|
||||
|
||||
if (posts) {
|
||||
return posts;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function loadFilesForPostIfNecessary(postId) {
|
||||
return async (dispatch, getState) => {
|
||||
const {files} = getState().entities;
|
||||
|
|
@ -307,7 +341,7 @@ export function closeGMChannel(channel) {
|
|||
|
||||
export function refreshChannelWithRetry(channelId) {
|
||||
return (dispatch, getState) => {
|
||||
getPostsWithRetry(channelId)(dispatch, getState);
|
||||
return retryGetPostsAction(getPosts(channelId), dispatch, getState);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ const ViewTypes = keyMirror({
|
|||
|
||||
INCREASE_POST_VISIBILITY: null,
|
||||
RECEIVED_FOCUSED_POST: null,
|
||||
LOADING_POSTS: null
|
||||
LOADING_POSTS: null,
|
||||
|
||||
RECEIVED_POSTS_FOR_CHANNEL_AT_TIME: null
|
||||
});
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import dimension from './dimension';
|
|||
import isTablet from './is_tablet';
|
||||
import orientation from './orientation';
|
||||
import statusBarHeight from './status_bar';
|
||||
import websocket from './websocket';
|
||||
|
||||
export default combineReducers({
|
||||
connection,
|
||||
dimension,
|
||||
isTablet,
|
||||
orientation,
|
||||
statusBarHeight
|
||||
statusBarHeight,
|
||||
websocket
|
||||
});
|
||||
|
|
|
|||
34
app/reducers/device/websocket.js
Normal file
34
app/reducers/device/websocket.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {GeneralTypes, UserTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
function getInitialState() {
|
||||
return {
|
||||
connected: false,
|
||||
lastConnectAt: 0,
|
||||
lastDisconnectAt: 0
|
||||
};
|
||||
}
|
||||
|
||||
export default function(state = getInitialState(), action) {
|
||||
if (!state.connected && action.type === GeneralTypes.WEBSOCKET_SUCCESS) {
|
||||
return {
|
||||
...state,
|
||||
connected: true,
|
||||
lastConnectAt: new Date().getTime()
|
||||
};
|
||||
} else if (state.connected && (action.type === GeneralTypes.WEBSOCKET_FAILURE || action.type === GeneralTypes.WEBSOCKET_CLOSED)) {
|
||||
return {
|
||||
...state,
|
||||
connected: false,
|
||||
lastDisconnectAt: new Date().getTime()
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === UserTypes.LOGOUT_SUCCESS) {
|
||||
return getInitialState();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
@ -246,6 +246,19 @@ function loadingPosts(state = {}, action) {
|
|||
}
|
||||
}
|
||||
|
||||
function lastGetPosts(state = {}, action) {
|
||||
switch (action.type) {
|
||||
case ViewTypes.RECEIVED_POSTS_FOR_CHANNEL_AT_TIME:
|
||||
return {
|
||||
...state,
|
||||
[action.channelId]: action.time
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default combineReducers({
|
||||
displayName,
|
||||
drafts,
|
||||
|
|
@ -253,5 +266,6 @@ export default combineReducers({
|
|||
refreshing,
|
||||
tooltipVisible,
|
||||
postVisibility,
|
||||
loadingPosts
|
||||
loadingPosts,
|
||||
lastGetPosts
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export default function configureAppStore(initialState) {
|
|||
const channel = {};
|
||||
|
||||
for (const channelKey of Object.keys(inboundState.channel)) {
|
||||
if (channelViewBlackList[channelKey]) {
|
||||
if (!channelViewBlackList[channelKey]) {
|
||||
channel[channelKey] = inboundState.channel[channelKey];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue