summaryrefslogtreecommitdiffstats
path: root/webapp/action_creators
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2016-03-23 10:20:52 -0400
committerChristopher Speller <crspeller@gmail.com>2016-03-23 10:38:35 -0400
commit9239a7353af2c67a6778ff4cabd164db62087bde (patch)
tree78335a5254885058ed3b224a4b050db03c732bb3 /webapp/action_creators
parent6568e15023c009c96a46f022236f5fd4415445c0 (diff)
downloadchat-9239a7353af2c67a6778ff4cabd164db62087bde.tar.gz
chat-9239a7353af2c67a6778ff4cabd164db62087bde.tar.bz2
chat-9239a7353af2c67a6778ff4cabd164db62087bde.zip
Fixing websocket connection issue. Refactoring websockets into an action creator.
Diffstat (limited to 'webapp/action_creators')
-rw-r--r--webapp/action_creators/global_actions.jsx34
-rw-r--r--webapp/action_creators/websocket_actions.jsx227
2 files changed, 259 insertions, 2 deletions
diff --git a/webapp/action_creators/global_actions.jsx b/webapp/action_creators/global_actions.jsx
index 0280d5974..ab38532a6 100644
--- a/webapp/action_creators/global_actions.jsx
+++ b/webapp/action_creators/global_actions.jsx
@@ -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
+ });
+}
diff --git a/webapp/action_creators/websocket_actions.jsx b/webapp/action_creators/websocket_actions.jsx
new file mode 100644
index 000000000..55a76dbea
--- /dev/null
+++ b/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);
+}