fix: Improve websocket reliability (#1470)
* check connection on page visibility change * fix: SocketPresence account for socket changing
This commit is contained in:
@ -3,7 +3,7 @@ import { find } from "lodash";
|
|||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { inject, observer } from "mobx-react";
|
import { inject, observer } from "mobx-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import io from "socket.io-client";
|
import io, { Socket } from "socket.io-client";
|
||||||
import AuthStore from "stores/AuthStore";
|
import AuthStore from "stores/AuthStore";
|
||||||
import CollectionsStore from "stores/CollectionsStore";
|
import CollectionsStore from "stores/CollectionsStore";
|
||||||
import DocumentPresenceStore from "stores/DocumentPresenceStore";
|
import DocumentPresenceStore from "stores/DocumentPresenceStore";
|
||||||
@ -13,6 +13,7 @@ import MembershipsStore from "stores/MembershipsStore";
|
|||||||
import PoliciesStore from "stores/PoliciesStore";
|
import PoliciesStore from "stores/PoliciesStore";
|
||||||
import UiStore from "stores/UiStore";
|
import UiStore from "stores/UiStore";
|
||||||
import ViewsStore from "stores/ViewsStore";
|
import ViewsStore from "stores/ViewsStore";
|
||||||
|
import { getVisibilityListener, getPageVisible } from "utils/pageVisibility";
|
||||||
|
|
||||||
export const SocketContext: any = React.createContext();
|
export const SocketContext: any = React.createContext();
|
||||||
|
|
||||||
@ -31,9 +32,35 @@ type Props = {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
class SocketProvider extends React.Component<Props> {
|
class SocketProvider extends React.Component<Props> {
|
||||||
@observable socket;
|
@observable socket: Socket;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.createConnection();
|
||||||
|
|
||||||
|
document.addEventListener(getVisibilityListener(), this.checkConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.authenticated = false;
|
||||||
|
this.socket.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.removeEventListener(getVisibilityListener(), this.checkConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConnection = () => {
|
||||||
|
if (this.socket && this.socket.disconnected && getPageVisible()) {
|
||||||
|
// null-ifying this reference is important, do not remove. Without it
|
||||||
|
// references to old sockets are potentially held in context
|
||||||
|
this.socket.close();
|
||||||
|
this.socket = null;
|
||||||
|
|
||||||
|
this.createConnection();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
createConnection = () => {
|
||||||
this.socket = io(window.location.origin, {
|
this.socket = io(window.location.origin, {
|
||||||
path: "/realtime",
|
path: "/realtime",
|
||||||
transports: ["websocket"],
|
transports: ["websocket"],
|
||||||
@ -264,14 +291,7 @@ class SocketProvider extends React.Component<Props> {
|
|||||||
this.socket.on("user.presence", (event) => {
|
this.socket.on("user.presence", (event) => {
|
||||||
presence.touch(event.documentId, event.userId, event.isEditing);
|
presence.touch(event.documentId, event.userId, event.isEditing);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.socket) {
|
|
||||||
this.socket.disconnect();
|
|
||||||
this.socket.authenticated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -41,7 +41,7 @@ export default class SocketPresence extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupOnce = () => {
|
setupOnce = () => {
|
||||||
if (this.context && !this.previousContext) {
|
if (this.context && this.context !== this.previousContext) {
|
||||||
this.previousContext = this.context;
|
this.previousContext = this.context;
|
||||||
|
|
||||||
if (this.context.authenticated) {
|
if (this.context.authenticated) {
|
||||||
|
25
app/utils/pageVisibility.js
Normal file
25
app/utils/pageVisibility.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// @flow
|
||||||
|
let hidden = "hidden";
|
||||||
|
let visibilityChange = "visibilitychange";
|
||||||
|
|
||||||
|
if ("hidden" in document) {
|
||||||
|
hidden = "hidden";
|
||||||
|
visibilityChange = "visibilitychange";
|
||||||
|
} else if ("mozHidden" in document) {
|
||||||
|
// Firefox up to v17
|
||||||
|
hidden = "mozHidden";
|
||||||
|
visibilityChange = "mozvisibilitychange";
|
||||||
|
} else if ("webkitHidden" in document) {
|
||||||
|
// Chrome up to v32, Android up to v4.4, Blackberry up to v10
|
||||||
|
hidden = "webkitHidden";
|
||||||
|
visibilityChange = "webkitvisibilitychange";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVisibilityListener(): string {
|
||||||
|
return visibilityChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPageVisible(): boolean {
|
||||||
|
// $FlowFixMe
|
||||||
|
return !document[hidden];
|
||||||
|
}
|
Reference in New Issue
Block a user