mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-26 21:27:40 -05:00
Increase performance when receiving posts in 3.6 (#5385)
This commit is contained in:
committed by
George Goldberg
parent
c5458f1609
commit
22bb594a2b
+9
-9
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -92,3 +92,8 @@ export function updateTeamMemberRoles(teamId, userId, newRoles, success, error)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function switchTeams(url) {
|
||||
AsyncClient.viewChannel();
|
||||
browserHistory.push(url);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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}`).
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user