overleaf/services/web/public/coffee/ide/connection/ConnectionManager.coffee

209 lines
6.5 KiB
CoffeeScript
Raw Normal View History

define [], () ->
ONEHOUR = 1000 * 60 * 60
class ConnectionManager
disconnectAfterMs: ONEHOUR * 24
lastUserAction : new Date()
constructor: (@ide, @$scope) ->
if !io?
console.error "Socket.io javascript not loaded. Please check that the real-time service is running and accessible."
@ide.socket =
on: () ->
$scope.$apply () =>
@$scope.state.error = "Could not connect to websocket server :("
return
2014-06-24 11:33:36 -04:00
setInterval(() =>
@disconnectIfInactive()
, ONEHOUR)
@userIsLeavingPage = false
window.addEventListener 'beforeunload', =>
@userIsLeavingPage = true
return # Don't return true or it will show a pop up
@connected = false
@userIsInactive = false
@gracefullyReconnecting = false
2014-06-24 11:33:36 -04:00
@$scope.connection =
reconnecting: false
# If we need to force everyone to reload the editor
forced_disconnect: false
inactive_disconnect: false
2014-06-24 11:33:36 -04:00
@$scope.tryReconnectNow = () =>
@tryReconnect()
@$scope.$on 'cursor:editor:update', () =>
@lastUserAction = new Date()
if !@connected
@tryReconnect()
document.querySelector('body').addEventListener 'click', (e) =>
if !@connected and e.target.id != 'try-reconnect-now-button'
@tryReconnect()
2014-07-09 15:32:03 -04:00
2015-03-20 15:08:35 -04:00
@ide.socket = io.connect null,
reconnect: false
'connect timeout': 30 * 1000
"force new connection": true
@ide.socket.on "connect", () =>
sl_console.log "[socket.io connect] Connected"
2014-06-24 11:33:36 -04:00
@connected = true
@gracefullyReconnecting = false
2014-06-24 11:33:36 -04:00
@ide.pushEvent("connected")
@$scope.$apply () =>
2014-06-24 11:33:36 -04:00
@$scope.connection.reconnecting = false
@$scope.connection.inactive_disconnect = false
2014-06-24 11:33:36 -04:00
if @$scope.state.loading
2014-07-10 08:41:54 -04:00
@$scope.state.load_progress = 70
2014-06-24 11:33:36 -04:00
setTimeout(() =>
@joinProject()
, 100)
@ide.socket.on "connect_failed", () =>
@connected = false
$scope.$apply () =>
@$scope.state.error = "Unable to connect, please view the <u><a href='http://sharelatex.tenderapp.com/help/kb/latex-editor/editor-connection-problems'>connection problems guide</a></u> to fix the issue."
2014-06-24 11:33:36 -04:00
@ide.socket.on 'disconnect', () =>
sl_console.log "[socket.io disconnect] Disconnected"
2014-06-24 11:33:36 -04:00
@connected = false
@ide.pushEvent("disconnected")
@$scope.$apply () =>
@$scope.connection.reconnecting = false
if !$scope.connection.forced_disconnect and !@userIsInactive and !@gracefullyReconnecting
2014-06-24 11:33:36 -04:00
@startAutoReconnectCountdown()
2014-06-24 11:33:36 -04:00
@ide.socket.on 'forceDisconnect', (message) =>
@$scope.$apply () =>
@$scope.permissions.write = false
2014-06-24 11:33:36 -04:00
@$scope.connection.forced_disconnect = true
2014-07-24 11:39:32 -04:00
@ide.socket.disconnect()
@ide.showGenericMessageModal("Please Refresh", """
We're performing maintenance on ShareLaTeX and you need to refresh the editor.
Sorry for any inconvenience.
The editor will refresh in automatically in 10 seconds.
""")
setTimeout () ->
location.reload()
, 10 * 1000
@ide.socket.on "reconnectGracefully", () =>
sl_console.log "Reconnect gracefully"
@reconnectGracefully()
2014-06-24 11:33:36 -04:00
joinProject: () ->
sl_console.log "[joinProject] joining..."
2014-06-24 11:33:36 -04:00
@ide.socket.emit 'joinProject', {
project_id: @ide.project_id
}, (err, project, permissionsLevel, protocolVersion) =>
if err?
if err.message == "not authorized"
window.location = "/login?redir=#{encodeURI(window.location.pathname)}"
else
@ide.socket.disconnect()
@ide.showGenericMessageModal("Something went wrong connecting", """
Something went wrong connecting to your project. Please refresh is this continues to happen.
""")
return
2014-06-24 11:33:36 -04:00
if @$scope.protocolVersion? and @$scope.protocolVersion != protocolVersion
location.reload(true)
2014-06-24 11:33:36 -04:00
@$scope.$apply () =>
@$scope.protocolVersion = protocolVersion
@$scope.project = project
@$scope.permissionsLevel = permissionsLevel
2014-06-24 11:33:36 -04:00
@$scope.state.load_progress = 100
@$scope.state.loading = false
@$scope.$broadcast "project:joined"
2014-06-24 10:31:44 -04:00
reconnectImmediately: () ->
@disconnect()
2014-06-24 11:33:36 -04:00
@tryReconnect()
2014-06-24 10:31:44 -04:00
disconnect: () ->
2014-06-24 11:33:36 -04:00
@ide.socket.disconnect()
startAutoReconnectCountdown: () ->
twoMinutes = 2 * 60 * 1000
2014-07-09 15:32:03 -04:00
if @lastUpdated? and new Date() - @lastUpdated > twoMinutes
# between 1 minute and 3 minutes
countdown = 60 + Math.floor(Math.random() * 120)
else
countdown = 3 + Math.floor(Math.random() * 7)
if @userIsLeavingPage #user will have pressed refresh or back etc
return
2014-06-24 11:33:36 -04:00
@$scope.$apply () =>
2014-07-02 11:41:29 -04:00
@$scope.connection.reconnecting = false
@$scope.connection.reconnection_countdown = countdown
2014-06-24 11:33:36 -04:00
setTimeout(=>
if !@connected
@timeoutId = setTimeout (=> @decreaseCountdown()), 1000
, 200)
cancelReconnect: () ->
clearTimeout @timeoutId if @timeoutId?
decreaseCountdown: () ->
return if !@$scope.connection.reconnection_countdown?
2014-06-24 11:33:36 -04:00
@$scope.$apply () =>
@$scope.connection.reconnection_countdown--
if @$scope.connection.reconnection_countdown <= 0
@$scope.$apply () =>
@tryReconnect()
else
@timeoutId = setTimeout (=> @decreaseCountdown()), 1000
tryReconnect: () ->
@cancelReconnect()
delete @$scope.connection.reconnection_countdown
2014-07-17 08:44:50 -04:00
return if @connected
2014-06-24 11:33:36 -04:00
@$scope.connection.reconnecting = true
@ide.socket.socket.reconnect()
setTimeout (=> @startAutoReconnectCountdown() if !@connected), 2000
2014-06-24 11:33:36 -04:00
disconnectIfInactive: ()->
@userIsInactive = (new Date() - @lastUserAction) > @disconnectAfterMs
if @userIsInactive and @connected
@disconnect()
@$scope.$apply () =>
@$scope.connection.inactive_disconnect = true
RECONNECT_GRACEFULLY_RETRY_INTERVAL: 5000 # ms
MAX_RECONNECT_GRACEFULLY_INTERVAL: 60 * 5 * 1000 # 5 minutes
reconnectGracefully: () ->
@reconnectGracefullyStarted ?= new Date()
userIsInactive = (new Date() - @lastUserAction) > @RECONNECT_GRACEFULLY_RETRY_INTERVAL
maxIntervalReached = (new Date() - @reconnectGracefullyStarted) > @MAX_RECONNECT_GRACEFULLY_INTERVAL
if userIsInactive or maxIntervalReached
sl_console.log "[reconnectGracefully] User didn't do anything for last 5 seconds, reconnecting"
@_reconnectGracefullyNow()
else
sl_console.log "[reconnectGracefully] User is working, will try again in 5 seconds"
setTimeout () =>
@reconnectGracefully()
, @RECONNECT_GRACEFULLY_RETRY_INTERVAL
_reconnectGracefullyNow: () ->
@gracefullyReconnecting = true
@reconnectGracefullyStarted = null
# Clear cookie so we don't go to the same backend server
$.cookie("SERVERID", "", { expires: -1, path: "/" })
@reconnectImmediately()