diff --git a/services/web/public/coffee/ide/editor/Document.coffee b/services/web/public/coffee/ide/editor/Document.coffee index d525c7f7bf..1927b791da 100644 --- a/services/web/public/coffee/ide/editor/Document.coffee +++ b/services/web/public/coffee/ide/editor/Document.coffee @@ -150,14 +150,16 @@ define [ wantToBeJoined: @wantToBeJoined update: update - if Math.random() < (@ide.disconnectRate or 0) - console.log "Simulating disconnect" - @ide.connectionManager.disconnect() + if window.disconnectOnAck? and Math.random() < window.disconnectOnAck + console.log "Disconnecting on ack", update + window._ide.socket.socket.disconnect() + # Pretend we never received the ack return - if Math.random() < (@ide.ignoreRate or 0) - console.log "Simulating lost update" - return + if window.dropAcks? and Math.random() < window.dropAcks + if !update.op? # Only drop our own acks, not collaborator updates + console.log "Simulating a lost ack", update + return if update?.doc == @doc_id and @doc? @doc.processUpdateFromServer update @@ -240,8 +242,7 @@ define [ doc_id: @doc_id op: op @trigger "op:timeout" - ga?('send', 'event', 'error', "op timeout", "Op was now acknowledged - #{@ide.socket.socket.transport.name}" ) - @ide.connectionManager.reconnectImmediately() + @_onError new Error("op timed out"), {op: op} @doc.on "flush", (inflightOp, pendingOp, version) => @ide.pushEvent "flush", doc_id: @doc_id, diff --git a/services/web/public/coffee/ide/editor/ShareJsDoc.coffee b/services/web/public/coffee/ide/editor/ShareJsDoc.coffee index 15ba95f56f..61b9ffb6cf 100644 --- a/services/web/public/coffee/ide/editor/ShareJsDoc.coffee +++ b/services/web/public/coffee/ide/editor/ShareJsDoc.coffee @@ -28,6 +28,12 @@ define [ @connection = { send: (update) => @_startInflightOpTimeout(update) + if window.disconnectOnUpdate? and Math.random() < window.disconnectOnUpdate + console.log "Disconnecting on update", update + window._ide.socket.socket.disconnect() + if window.dropUpdates? and Math.random() < window.dropUpdates + console.log "Simulating a lost update", update + return @socket.emit "applyOtUpdate", @doc_id, update state: "ok" id: @socket.socket.sessionid @@ -103,17 +109,42 @@ define [ attachToAce: (ace) -> @_doc.attach_ace(ace, false, window.maxDocLength) detachFromAce: () -> @_doc.detach_ace?() - INFLIGHT_OP_TIMEOUT: 10000 + INFLIGHT_OP_TIMEOUT: 5000 # Retry sending ops after 5 seconds without an ack _startInflightOpTimeout: (update) -> - meta = - v: update.v - op_sent_at: new Date() + @_startFatalTimeoutTimer(update) timer = setTimeout () => - @trigger "op:timeout", update + # Only send the update again if inflightOp is still populated + # This can be cleared when hard reloading the document in which + # case we don't want to keep trying to send it. + if @_doc.inflightOp? + # When there is a socket.io disconnect, @_doc.inflightSubmittedIds + # is updated with the socket.io client id of the current op in flight + # (meta.source of the op). + # @connection.id is the client id of the current socket.io session. + # So we need both depending on whether the op was submitted before + # one or more disconnects, or if it was submitted during the current session. + update.dupIfSource = [@connection.id, @_doc.inflightSubmittedIds...] + @connection.send(update) , @INFLIGHT_OP_TIMEOUT @_doc.inflightCallbacks.push () => + @_clearFatalTimeoutTimer() clearTimeout timer + FATAL_OP_TIMEOUT: 30000 # 30 seconds + _startFatalTimeoutTimer: (update) -> + # If an op doesn't get acked within FATAL_OP_TIMEOUT, something has + # gone unrecoverably wrong (the op will have been retried multiple times) + return if @_timeoutTimer? + @_timeoutTimer = setTimeout () => + @_clearFatalTimeoutTimer() + @trigger "op:timeout", update + , @FATAL_OP_TIMEOUT + + _clearFatalTimeoutTimer: () -> + return if !@_timeoutTimer? + clearTimeout @_timeoutTimer + @_timeoutTimer = null + _handleError: (error, meta = {}) -> @trigger "error", error, meta diff --git a/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee b/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee index 0bffb60204..f9c68ca05f 100644 --- a/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee +++ b/services/web/public/coffee/ide/editor/controllers/SavingNotificationController.coffee @@ -24,8 +24,6 @@ define [ if oldStatus[doc_id]? newStatus[doc_id] = oldStatus[doc_id] newStatus[doc_id].unsavedSeconds += 1 - if newStatus[doc_id].unsavedSeconds == 60 - reportUnsavedChanges(doc) else newStatus[doc_id] = { unsavedSeconds: 0 @@ -41,12 +39,6 @@ define [ $scope.docSavingStatusCount = newUnsavedCount $scope.$apply() - reportUnsavedChanges = (doc) -> - ide.reportError new Error("unsaved changes"), { - inflightOp: doc?.getInflightOp(), - pendingOp: doc?.getPendingOp() - } - warnAboutUnsavedChanges = () -> if Document.hasUnsavedChanges() return "You have unsaved changes. If you leave now they will not be saved."