diff --git a/services/web/public/coffee/ide/connection/ConnectionManager.coffee b/services/web/public/coffee/ide/connection/ConnectionManager.coffee index 0454395d69..61d3d1c37d 100644 --- a/services/web/public/coffee/ide/connection/ConnectionManager.coffee +++ b/services/web/public/coffee/ide/connection/ConnectionManager.coffee @@ -28,24 +28,27 @@ define [], () -> @connected = false @userIsInactive = false @gracefullyReconnecting = false - - @$scope.connection = + + @$scope.connection = reconnecting: false # If we need to force everyone to reload the editor forced_disconnect: false inactive_disconnect: false @$scope.tryReconnectNow = () => - @tryReconnect() + # user manually requested reconnection via "Try now" button + @tryReconnectWithRateLimit({force:true}) @$scope.$on 'cursor:editor:update', () => - @lastUserAction = new Date() + @lastUserAction = new Date() # time of last edit if !@connected - @tryReconnect() + # user is editing, try to reconnect + @tryReconnectWithRateLimit() document.querySelector('body').addEventListener 'click', (e) => if !@connected and e.target.id != 'try-reconnect-now-button' - @tryReconnect() + # user is editing, try to reconnect + @tryReconnectWithRateLimit() @ide.socket = io.connect null, reconnect: false @@ -166,11 +169,13 @@ define [], () -> @tryReconnect() disconnect: () -> + sl_console.log "[socket.io] disconnecting client" @ide.socket.disconnect() startAutoReconnectCountdown: () -> + sl_console.log "[ConnectionManager] starting autoreconnect countdown" twoMinutes = 2 * 60 * 1000 - if @lastUpdated? and new Date() - @lastUpdated > twoMinutes + if @lastUserAction? and new Date() - @lastUserAction > twoMinutes # between 1 minute and 3 minutes countdown = 60 + Math.floor(Math.random() * 120) else @@ -189,10 +194,16 @@ define [], () -> , 200) cancelReconnect: () -> - clearTimeout @timeoutId if @timeoutId? - + # clear timeout and set to null so we know there is no countdown running + if @timeoutId? + sl_console.log "[ConnectionManager] cancelling existing reconnect timer" + clearTimeout @timeoutId + @timeoutId = null + decreaseCountdown: () -> + @timeoutId = null return if !@$scope.connection.reconnection_countdown? + sl_console.log "[ConnectionManager] decreasing countdown", @$scope.connection.reconnection_countdown @$scope.$apply () => @$scope.connection.reconnection_countdown-- @@ -203,13 +214,33 @@ define [], () -> @timeoutId = setTimeout (=> @decreaseCountdown()), 1000 tryReconnect: () -> + sl_console.log "[ConnectionManager] tryReconnect" @cancelReconnect() delete @$scope.connection.reconnection_countdown return if @connected @$scope.connection.reconnecting = true - @ide.socket.socket.reconnect() + # use socket.io connect() here to make a single attempt, the + # reconnect() method makes multiple attempts + @ide.socket.socket.connect() + # record the time of the last attempt to connect + @lastConnectionAttempt = new Date() setTimeout (=> @startAutoReconnectCountdown() if !@connected), 2000 + MIN_RETRY_INTERVAL: 1000 # ms + BACKGROUND_RETRY_INTERVAL : 30 * 1000 # ms + + tryReconnectWithRateLimit: (options) -> + # bail out if the reconnect is already in progress + return if @$scope.connection?.reconnecting + # bail out if we are going to reconnect soon anyway + reconnectingSoon = @$scope.connection?.reconnection_countdown? and @$scope.connection.reconnection_countdown <= 5 + clickedTryNow = options?.force # user requested reconnection + return if reconnectingSoon and not clickedTryNow + # bail out if we tried reconnecting recently + allowedInterval = if clickedTryNow then @MIN_RETRY_INTERVAL else @BACKGROUND_RETRY_INTERVAL + return if @lastConnectionAttempt? and new Date() - @lastConnectionAttempt < allowedInterval + @tryReconnect() + disconnectIfInactive: ()-> @userIsInactive = (new Date() - @lastUserAction) > @disconnectAfterMs if @userIsInactive and @connected @@ -231,7 +262,7 @@ define [], () -> setTimeout () => @reconnectGracefully() , @RECONNECT_GRACEFULLY_RETRY_INTERVAL - + _reconnectGracefullyNow: () -> @gracefullyReconnecting = true @reconnectGracefullyStarted = null