Fixing websocket connection issue. Refactoring websockets into an action creator.

Этот коммит содержится в:
Christopher Speller
2016-03-23 10:20:52 -04:00
родитель 6568e15023
Коммит 9239a7353a
11 изменённых файлов: 495 добавлений и 430 удалений

Просмотреть файл

@@ -10,6 +10,7 @@ const ActionTypes = Constants.ActionTypes;
import * as AsyncClient from 'utils/async_client.jsx';
import * as Client from 'utils/client.jsx';
import * as Utils from 'utils/utils.jsx';
import * as Websockets from './websocket_actions.jsx';
import * as I18n from 'i18n/i18n.jsx';
import en from 'i18n/en.json';
@@ -97,10 +98,21 @@ export function emitLoadMorePostsFocusedBottomEvent() {
AsyncClient.getPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE);
}
export function emitPostRecievedEvent(post) {
export function emitPostRecievedEvent(post, websocketMessageProps) {
if (ChannelStore.getCurrentId() === post.channel_id) {
if (window.isActive) {
AsyncClient.updateLastViewedAt();
} else {
AsyncClient.getChannel(post.channel_id);
}
} else {
AsyncClient.getChannel(post.channel_id);
}
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_POST,
post
post,
websocketMessageProps
});
}
@@ -261,3 +273,21 @@ export function viewLoggedIn() {
// Clear pending posts (shouldn't have pending posts if we are loading)
PostStore.clearPendingPosts();
}
var lastTimeTypingSent = 0;
export function emitLocalUserTypingEvent(channelId, parentId) {
const t = Date.now();
if ((t - lastTimeTypingSent) > Constants.UPDATE_TYPING_MS) {
Websockets.sendMessage({channel_id: channelId, action: 'typing', props: {parent_id: parentId}, state: {}});
lastTimeTypingSent = t;
}
}
export function emitRemoteUserTypingEvent(channelId, userId, postParentId) {
AppDispatcher.handleViewAction({
type: Constants.ActionTypes.USER_TYPING,
channelId,
userId,
postParentId
});
}

227
webapp/action_creators/websocket_actions.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,227 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import $ from 'jquery';
import UserStore from 'stores/user_store.jsx';
import PostStore from 'stores/post_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import ErrorStore from 'stores/error_store.jsx';
import * as Utils from 'utils/utils.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import Constants from 'utils/constants.jsx';
const SocketEvents = Constants.SocketEvents;
const MAX_WEBSOCKET_FAILS = 7;
const WEBSOCKET_RETRY_TIME = 3000;
var conn = null;
var connectFailCount = 0;
var pastFirstInit = false;
export function initialize() {
if (window.WebSocket && !conn) {
let protocol = 'ws://';
if (window.location.protocol === 'https:') {
protocol = 'wss://';
}
const connUrl = protocol + location.host + ((/:\d+/).test(location.host) ? '' : Utils.getWebsocketPort(protocol)) + '/api/v1/websocket';
if (connectFailCount === 0) {
console.log('websocket connecting to ' + connUrl); //eslint-disable-line no-console
}
conn = new WebSocket(connUrl);
conn.onopen = () => {
if (connectFailCount > 0) {
console.log('websocket re-established connection'); //eslint-disable-line no-console
AsyncClient.getChannels();
AsyncClient.getPosts(ChannelStore.getCurrentId());
}
if (pastFirstInit) {
ErrorStore.clearLastError();
ErrorStore.emitChange();
}
pastFirstInit = true;
connectFailCount = 0;
};
conn.onclose = () => {
conn = null;
if (connectFailCount === 0) {
console.log('websocket closed'); //eslint-disable-line no-console
}
connectFailCount = connectFailCount + 1;
if (connectFailCount > MAX_WEBSOCKET_FAILS) {
ErrorStore.storeLastError(Utils.localizeMessage('channel_loader.socketError', 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.'));
}
ErrorStore.setConnectionErrorCount(connectFailCount);
ErrorStore.emitChange();
setTimeout(
() => {
initialize();
},
WEBSOCKET_RETRY_TIME
);
};
conn.onerror = (evt) => {
if (connectFailCount <= 1) {
console.log('websocket error'); //eslint-disable-line no-console
console.log(evt); //eslint-disable-line no-console
}
};
conn.onmessage = (evt) => {
const msg = JSON.parse(evt.data);
handleMessage(msg);
};
}
}
function handleMessage(msg) {
// Let the store know we are online. This probably shouldn't be here.
UserStore.setStatus(msg.user_id, 'online');
switch (msg.action) {
case SocketEvents.POSTED:
case SocketEvents.EPHEMERAL_MESSAGE:
handleNewPostEvent(msg);
break;
case SocketEvents.POST_EDITED:
handlePostEditEvent(msg);
break;
case SocketEvents.POST_DELETED:
handlePostDeleteEvent(msg);
break;
case SocketEvents.NEW_USER:
handleNewUserEvent();
break;
case SocketEvents.USER_ADDED:
handleUserAddedEvent(msg);
break;
case SocketEvents.USER_REMOVED:
handleUserRemovedEvent(msg);
break;
case SocketEvents.CHANNEL_VIEWED:
handleChannelViewedEvent(msg);
break;
case SocketEvents.PREFERENCE_CHANGED:
handlePreferenceChangedEvent(msg);
break;
case SocketEvents.TYPING:
handleUserTypingEvent(msg);
break;
default:
}
}
export function sendMessage(msg) {
if (conn && conn.readyState === WebSocket.OPEN) {
conn.send(JSON.stringify(msg));
} else if (!conn || conn.readyState === WebSocket.Closed) {
conn = null;
this.initialize();
}
}
export function close() {
if (conn && conn.readyState === WebSocket.OPEN) {
conn.close();
}
}
function handleNewPostEvent(msg) {
const post = JSON.parse(msg.props.post);
GlobalActions.emitPostRecievedEvent(post, msg.props);
}
function handlePostEditEvent(msg) {
// Store post
const post = JSON.parse(msg.props.post);
PostStore.storePost(post);
PostStore.emitChange();
// Update channel state
if (ChannelStore.getCurrentId() === msg.channel_id) {
if (window.isActive) {
AsyncClient.updateLastViewedAt();
}
}
}
function handlePostDeleteEvent(msg) {
const post = JSON.parse(msg.props.post);
GlobalActions.emitPostDeletedEvent(post);
}
function handleNewUserEvent() {
AsyncClient.getProfiles();
AsyncClient.getChannelExtraInfo();
}
function handleUserAddedEvent(msg) {
if (ChannelStore.getCurrentId() === msg.channel_id) {
AsyncClient.getChannelExtraInfo();
}
if (UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannel(msg.channel_id);
}
}
function handleUserRemovedEvent(msg) {
if (UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannels();
if (msg.props.remover_id !== msg.user_id &&
msg.channel_id === ChannelStore.getCurrentId() &&
$('#removed_from_channel').length > 0) {
var sentState = {};
sentState.channelName = ChannelStore.getCurrent().display_name;
sentState.remover = UserStore.getProfile(msg.props.remover_id).username;
BrowserStore.setItem('channel-removed-state', sentState);
$('#removed_from_channel').modal('show');
}
} else if (ChannelStore.getCurrentId() === msg.channel_id) {
AsyncClient.getChannelExtraInfo();
}
}
function handleChannelViewedEvent(msg) {
// Useful for when multiple devices have the app open to different channels
if (ChannelStore.getCurrentId() !== msg.channel_id && UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannel(msg.channel_id);
}
}
function handlePreferenceChangedEvent(msg) {
const preference = JSON.parse(msg.props.preference);
GlobalActions.emitPreferenceChangedEvent(preference);
}
function handleUserTypingEvent(msg) {
GlobalActions.emitRemoteUserTypingEvent(msg.channel_id, msg.user_id, msg.props.parent_id);
}