Increase performance when receiving posts in 3.6 (#5385)

This commit is contained in:
Joram Wilander
2017-02-16 19:09:08 +00:00
committed by George Goldberg
parent c5458f1609
commit 22bb594a2b
17 changed files with 206 additions and 60 deletions
+9 -9
View File
@@ -1257,12 +1257,11 @@ func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if len(view.ChannelId) == 0 {
ReturnStatusOK(w)
return
}
channelIds := []string{}
channelIds := []string{view.ChannelId}
if len(view.ChannelId) > 0 {
channelIds = append(channelIds, view.ChannelId)
}
var pchan store.StoreChannel
if len(view.PrevChannelId) > 0 {
@@ -1273,6 +1272,11 @@ func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
if len(channelIds) == 0 {
ReturnStatusOK(w)
return
}
uchan := Srv.Store.Channel().UpdateLastViewedAt(channelIds, c.Session.UserId)
if pchan != nil {
@@ -1291,10 +1295,6 @@ func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_VIEWED, c.TeamId, "", c.Session.UserId, nil)
message.Add("channel_id", view.ChannelId)
go Publish(message)
ReturnStatusOK(w)
}
-10
View File
@@ -99,11 +99,6 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
Srv.Store.Preference().Save(&model.Preferences{teamPref, chanPref})
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_VIEWED, c.TeamId, "", c.Session.UserId, nil)
message.Add("channel_id", id)
go Publish(message)
result := make(map[string]string)
result["id"] = id
w.Write([]byte(model.MapToJson(result)))
@@ -134,11 +129,6 @@ func setLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
Srv.Store.Preference().Save(&model.Preferences{teamPref, chanPref})
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CHANNEL_VIEWED, c.TeamId, "", c.Session.UserId, nil)
message.Add("channel_id", id)
go Publish(message)
result := make(map[string]string)
result["id"] = id
w.Write([]byte(model.MapToJson(result)))
-1
View File
@@ -14,7 +14,6 @@ const (
WEBSOCKET_EVENT_POST_EDITED = "post_edited"
WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
WEBSOCKET_EVENT_NEW_USER = "new_user"
WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
+4 -3
View File
@@ -47,16 +47,17 @@ export function emitChannelClickEvent(channel) {
function switchToChannel(chan) {
const channelMember = ChannelStore.getMyMember(chan.id);
const getMyChannelMembersPromise = AsyncClient.getChannelMember(chan.id, UserStore.getCurrentId());
const oldChannelId = ChannelStore.getCurrentId();
getMyChannelMembersPromise.then(() => {
AsyncClient.getChannelStats(chan.id, true);
AsyncClient.viewChannel(chan.id, ChannelStore.getCurrentId());
AsyncClient.viewChannel(chan.id, oldChannelId);
loadPosts(chan.id);
trackPage();
});
// Mark previous and next channel as read
ChannelStore.resetCounts(ChannelStore.getCurrentId());
ChannelStore.resetCounts(oldChannelId);
ChannelStore.resetCounts(chan.id);
BrowserStore.setGlobalItem(chan.team_id, chan.id);
@@ -68,7 +69,7 @@ export function emitChannelClickEvent(channel) {
team_id: chan.team_id,
total_msg_count: chan.total_msg_count,
channelMember,
prev: ChannelStore.getCurrentId()
prev: oldChannelId
});
}
-20
View File
@@ -5,7 +5,6 @@ import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import PostStore from 'stores/post_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import {loadStatusesForChannel} from 'actions/status_actions.jsx';
@@ -19,30 +18,11 @@ const ActionTypes = Constants.ActionTypes;
const Preferences = Constants.Preferences;
export function handleNewPost(post, msg) {
const teamId = TeamStore.getCurrentId();
if (ChannelStore.getCurrentId() === post.channel_id) {
if (window.isActive) {
AsyncClient.viewChannel();
} else {
AsyncClient.getChannel(post.channel_id);
}
} else if (msg && (teamId === msg.data.team_id || msg.data.channel_type === Constants.DM_CHANNEL)) {
if (Client.teamId) {
AsyncClient.getChannel(post.channel_id);
}
}
let websocketMessageProps = null;
if (msg) {
websocketMessageProps = msg.data;
}
const myTeams = TeamStore.getMyTeamMembers();
if (msg.data.team_id !== teamId && myTeams.filter((m) => m.team_id === msg.data.team_id).length) {
AsyncClient.getMyTeamsUnread(teamId);
}
if (msg && msg.data && msg.data.channel_type === Constants.DM_CHANNEL) {
loadNewDMIfNeeded(post.user_id);
}
+5
View File
@@ -92,3 +92,8 @@ export function updateTeamMemberRoles(teamId, userId, newRoles, success, error)
}
);
}
export function switchTeams(url) {
AsyncClient.viewChannel();
browserHistory.push(url);
}
-13
View File
@@ -136,10 +136,6 @@ function handleEvent(msg) {
handleUserUpdatedEvent(msg);
break;
case SocketEvents.CHANNEL_VIEWED:
handleChannelViewedEvent(msg);
break;
case SocketEvents.CHANNEL_DELETED:
handleChannelDeletedEvent(msg);
break;
@@ -281,15 +277,6 @@ function handleUserUpdatedEvent(msg) {
}
}
function handleChannelViewedEvent(msg) {
// Useful for when multiple devices have the app open to different channels
if (TeamStore.getCurrentId() === msg.broadcast.team_id &&
ChannelStore.getCurrentId() !== msg.data.channel_id &&
UserStore.getCurrentId() === msg.broadcast.user_id) {
AsyncClient.getChannel(msg.data.channel_id);
}
}
function handleChannelDeletedEvent(msg) {
if (ChannelStore.getCurrentId() === msg.data.channel_id) {
const teamUrl = TeamStore.getCurrentTeamRelativeUrl();
+9
View File
@@ -1469,6 +1469,15 @@ export default class Client {
end(this.handleResponse.bind(this, 'getMyChannelMembers', success, error));
}
getMyChannelMembersForTeam(teamId, success, error) {
request.
get(`${this.getTeamsRoute()}/${teamId}/channels/members`).
set(this.defaultHeaders).
type('application/json').
accept('application/json').
end(this.handleResponse.bind(this, 'getMyChannelMembersForTeam', success, error));
}
getChannelByName(channelName, success, error) {
request.
get(`${this.getChannelsRoute()}/name/${channelName}`).
+9
View File
@@ -42,6 +42,8 @@ import SelectTeamModal from 'components/admin_console/select_team_modal.jsx';
import iNoBounce from 'inobounce';
import * as UserAgent from 'utils/user_agent.jsx';
const UNREAD_CHECK_TIME_MILLISECONDS = 10000;
export default class NeedsTeam extends React.Component {
constructor(params) {
super(params);
@@ -49,6 +51,8 @@ export default class NeedsTeam extends React.Component {
this.onTeamChanged = this.onTeamChanged.bind(this);
this.onPreferencesChanged = this.onPreferencesChanged.bind(this);
this.blurTime = new Date().getTime();
const team = TeamStore.getCurrent();
this.state = {
@@ -97,11 +101,16 @@ export default class NeedsTeam extends React.Component {
AsyncClient.viewChannel();
ChannelStore.resetCounts(ChannelStore.getCurrentId());
ChannelStore.emitChange();
window.isActive = true;
if (new Date().getTime() - this.blurTime > UNREAD_CHECK_TIME_MILLISECONDS) {
AsyncClient.getMyChannelMembers();
}
});
$(window).on('blur', () => {
window.isActive = false;
this.blurTime = new Date().getTime();
if (UserStore.getCurrentUser()) {
AsyncClient.viewChannel('');
}
@@ -32,7 +32,7 @@ export default class PostViewCache extends React.Component {
componentWillUnmount() {
if (UserStore.getCurrentUser()) {
AsyncClient.viewChannel('');
AsyncClient.viewChannel('', this.state.currentChannelId || '');
}
ChannelStore.removeChangeListener(this.onChannelChange);
}
@@ -3,6 +3,8 @@
import Constants from 'utils/constants.jsx';
import {switchTeams} from 'actions/team_actions.jsx';
import React from 'react';
import {Link} from 'react-router/es6';
import {Tooltip, OverlayTrigger} from 'react-bootstrap';
@@ -11,9 +13,15 @@ export default class TeamButton extends React.Component {
constructor(props) {
super(props);
this.handleSwitch = this.handleSwitch.bind(this);
this.handleDisabled = this.handleDisabled.bind(this);
}
handleSwitch(e) {
e.preventDefault();
switchTeams(this.props.url);
}
handleDisabled(e) {
e.preventDefault();
}
@@ -22,7 +30,7 @@ export default class TeamButton extends React.Component {
let teamClass = this.props.active ? 'active' : '';
const btnClass = this.props.btnClass;
const disabled = this.props.disabled ? 'team-disabled' : '';
const handleClick = (this.props.active || this.props.disabled) ? this.handleDisabled : null;
const handleClick = (this.props.active || this.props.disabled) ? this.handleDisabled : this.handleSwitch;
let badge;
if (!teamClass) {
+6
View File
@@ -11,7 +11,10 @@ import PDFJS from 'pdfjs-dist';
import * as GlobalActions from 'actions/global_actions.jsx';
import * as Websockets from 'actions/websocket_actions.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as I18n from 'i18n/i18n.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
// Import our styles
import 'bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css';
@@ -58,6 +61,9 @@ function preRenderSetup(callwhendone) {
$(window).on('beforeunload',
() => {
BrowserStore.setLastServerVersion('');
if (UserStore.getCurrentUser()) {
AsyncClient.viewChannel('', ChannelStore.getCurrentId() || '');
}
Websockets.close();
}
);
+7 -2
View File
@@ -34,7 +34,7 @@ function doChannelChange(state, replace, callback) {
} else {
channel = ChannelStore.getByName(state.params.channel);
if (channel.type === Constants.DM_CHANNEL) {
if (channel && channel.type === Constants.DM_CHANNEL) {
loadNewDMIfNeeded(Utils.getUserIdFromChannelName(channel));
}
@@ -106,7 +106,12 @@ function preNeedsTeam(nextState, replace, callback) {
if (nextState.location.pathname.indexOf('/channels/') > -1 ||
nextState.location.pathname.indexOf('/pl/') > -1) {
AsyncClient.getMyTeamsUnread();
AsyncClient.getMyChannelMembers();
const teams = TeamStore.getAll();
for (const id in teams) {
if (teams.hasOwnProperty(id)) {
AsyncClient.getMyChannelMembersForTeam(id);
}
}
}
const d1 = $.Deferred(); //eslint-disable-line new-cap
+67
View File
@@ -5,9 +5,11 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
var Utils;
import {ActionTypes, Constants} from 'utils/constants.jsx';
import {isSystemMessage} from 'utils/post_utils.jsx';
const NotificationPrefs = Constants.NotificationPrefs;
const CHANGE_EVENT = 'change';
@@ -343,6 +345,41 @@ class ChannelStoreClass extends EventEmitter {
return channelNamesMap;
}
incrementMessages(id, markRead = false) {
if (!this.unreadCounts[id]) {
return;
}
const member = this.getMyMember(id);
if (member && member.notify_props && member.notify_props.mark_unread === NotificationPrefs.MENTION) {
return;
}
this.get(id).total_msg_count++;
if (markRead) {
this.resetCounts(id);
} else {
this.unreadCounts[id].msgs++;
}
}
incrementMentionsIfNeeded(id, msgProps) {
let mentions = [];
if (msgProps && msgProps.mentions) {
mentions = JSON.parse(msgProps.mentions);
}
if (!this.unreadCounts[id]) {
return;
}
if (mentions.indexOf(UserStore.getCurrentId()) !== -1) {
this.unreadCounts[id].mentions++;
this.getMyMember(id).mention_count++;
}
}
}
var ChannelStore = new ChannelStoreClass();
@@ -417,6 +454,36 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
ChannelStore.emitStatsChange();
break;
case ActionTypes.RECEIVED_POST:
if (action.post.type === Constants.POST_TYPE_JOIN_LEAVE) {
return;
}
if (action.post.user_id === UserStore.getCurrentId() && !isSystemMessage(action.post)) {
return;
}
var id = action.post.channel_id;
var teamId = action.websocketMessageProps ? action.websocketMessageProps.team_id : null;
var markRead = id === ChannelStore.getCurrentId() && window.isActive;
if (TeamStore.getCurrentId() === teamId || teamId === '') {
ChannelStore.incrementMentionsIfNeeded(id, action.websocketMessageProps);
ChannelStore.incrementMessages(id, markRead);
ChannelStore.emitChange();
}
break;
case ActionTypes.CREATE_POST:
ChannelStore.incrementMessages(action.post.channel_id, true);
ChannelStore.emitChange();
break;
case ActionTypes.CREATE_COMMENT:
ChannelStore.incrementMessages(action.post.channel_id, true);
ChannelStore.emitChange();
break;
default:
break;
}
+36
View File
@@ -4,8 +4,10 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import Constants from 'utils/constants.jsx';
const NotificationPrefs = Constants.NotificationPrefs;
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
@@ -321,6 +323,28 @@ class TeamStoreClass extends EventEmitter {
member.mention_count -= channelMember.mention_count;
}
}
incrementMessages(id, channelId) {
const channelMember = ChannelStore.getMyMember(channelId);
if (channelMember && channelMember.notify_props && channelMember.notify_props.mark_unread === NotificationPrefs.MENTION) {
return;
}
const member = this.my_team_members.filter((m) => m.team_id === id)[0];
member.msg_count++;
}
incrementMentionsIfNeeded(id, msgProps) {
let mentions = [];
if (msgProps && msgProps.mentions) {
mentions = JSON.parse(msgProps.mentions);
}
if (mentions.indexOf(UserStore.getCurrentId()) !== -1) {
const member = this.my_team_members.filter((m) => m.team_id === id)[0];
member.mention_count++;
}
}
}
var TeamStore = new TeamStoreClass();
@@ -375,6 +399,18 @@ TeamStore.dispatchToken = AppDispatcher.register((payload) => {
TeamStore.emitUnreadChange();
}
break;
case ActionTypes.RECEIVED_POST:
if (action.post.type === Constants.POST_TYPE_JOIN_LEAVE) {
return;
}
var id = action.websocketMessageProps ? action.websocketMessageProps.team_id : null;
if (id && TeamStore.getCurrentId() !== id) {
TeamStore.incrementMessages(id, action.post.channel_id);
TeamStore.incrementMentionsIfNeeded(id, action.websocketMessageProps);
TeamStore.emitChange();
}
break;
default:
}
});
+15
View File
@@ -352,6 +352,21 @@ describe('Client.Channels', function() {
});
});
it('getMyChannelMembersForTeam', function(done) {
TestHelper.initBasic(() => {
TestHelper.basicClient().getMyChannelMembersForTeam(
TestHelper.basicTeam().id,
function(data) {
assert.equal(data.length > 0, true);
done();
},
function(err) {
done(new Error(err.message));
}
);
});
});
it('getChannelStats', function(done) {
TestHelper.initBasic(() => {
TestHelper.basicClient().getChannelStats(
+29
View File
@@ -138,6 +138,35 @@ export function getMyChannelMembers() {
});
}
export function getMyChannelMembersForTeam(teamId) {
return new Promise((resolve, reject) => {
if (isCallInProgress(`getMyChannelMembers${teamId}`)) {
resolve();
return;
}
callTracker[`getMyChannelMembers${teamId}`] = utils.getTimestamp();
Client.getMyChannelMembersForTeam(
teamId,
(data) => {
callTracker[`getMyChannelMembers${teamId}`] = 0;
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_MY_CHANNEL_MEMBERS,
members: data
});
resolve();
},
(err) => {
callTracker[`getMyChannelMembers${teamId}`] = 0;
dispatchError(err, 'getMyChannelMembersForTeam');
reject();
}
);
});
}
export function viewChannel(channelId = ChannelStore.getCurrentId(), prevChannelId = '', time = 0) {
if (channelId == null || !Client.teamId) {
return;