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:
Harrison Healey 2017-10-02 11:21:39 -04:00 committed by enahum
parent c93f04a708
commit 8e526b61ed
6 changed files with 101 additions and 15 deletions

View file

@ -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);
};
}

View file

@ -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 {

View file

@ -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
});

View 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;
}

View file

@ -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
});

View file

@ -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];
}
}