Browse Source

Buffer updates when only a single user is editing a document

Add in 5 second delay between flushing updates when only a single user
is editing a document. As soon as an update is received from another user
we switch to sending updates immediately again so there is no latency
between collaborators. The logic applies to individual docs, so two users
can be editing different docs and will still buffer updates since they
will not affect each other.
James Allen 11 years ago
parent
commit
af85c83877

+ 1 - 1
services/web/app/views/project/editor.jade

@@ -29,7 +29,7 @@ block content
 				strong #{translate("reconnecting")}...
 				strong #{translate("reconnecting")}...
 
 
 			.div(ng-controller="SavingNotificationController")
 			.div(ng-controller="SavingNotificationController")
-				.alert.alert-warning.small( ng-repeat="(doc_id, state) in docSavingStatus" ng-if="state.unsavedSeconds > 3") #{translate("saving_notification_with_seconds", {docname:"{{ state.doc.name }}", seconds:"{{ state.unsavedSeconds }}"})}
+				.alert.alert-warning.small( ng-repeat="(doc_id, state) in docSavingStatus" ng-if="state.unsavedSeconds > 8") #{translate("saving_notification_with_seconds", {docname:"{{ state.doc.name }}", seconds:"{{ state.unsavedSeconds }}"})}
 
 
 		include ./editor/left-menu
 		include ./editor/left-menu
 
 

+ 7 - 0
services/web/public/coffee/ide/editor/Document.coffee

@@ -14,6 +14,10 @@ define [
 				return true if doc.hasBufferedOps()
 				return true if doc.hasBufferedOps()
 			return false
 			return false
 
 
+		@flushAll: () ->
+			for doc_id, doc of @openDocs
+				doc.flush()
+
 		constructor: (@ide, @doc_id) ->
 		constructor: (@ide, @doc_id) ->
 			@connected = @ide.socket.socket.connected
 			@connected = @ide.socket.socket.connected
 			@joined = false
 			@joined = false
@@ -109,6 +113,9 @@ define [
 			else
 			else
 				@_leaveDoc(callback)
 				@_leaveDoc(callback)
 
 
+		flush: () ->
+			@doc?.flushPendingOps()
+
 		pollSavedStatus: () ->
 		pollSavedStatus: () ->
 			# returns false if doc has ops waiting to be acknowledged or
 			# returns false if doc has ops waiting to be acknowledged or
 			# sent that haven't changed since the last time we checked.
 			# sent that haven't changed since the last time we checked.

+ 3 - 0
services/web/public/coffee/ide/editor/EditorManager.coffee

@@ -28,6 +28,9 @@ define [
 					initialized = true
 					initialized = true
 					@autoOpenDoc()
 					@autoOpenDoc()
 
 
+			@$scope.$on "flush-changes", () =>
+				Document.flushAll()
+
 		autoOpenDoc: () ->
 		autoOpenDoc: () ->
 			open_doc_id = 
 			open_doc_id = 
 				@ide.localStorage("doc.open_id.#{@$scope.project_id}") or
 				@ide.localStorage("doc.open_id.#{@$scope.project_id}") or

+ 6 - 0
services/web/public/coffee/ide/editor/ShareJsDoc.coffee

@@ -2,6 +2,8 @@ define [
 	"utils/EventEmitter"
 	"utils/EventEmitter"
 	"libs/sharejs"
 	"libs/sharejs"
 ], (EventEmitter, ShareJs) ->
 ], (EventEmitter, ShareJs) ->
+	SINGLE_USER_FLUSH_DELAY = 5000 #ms
+
 	class ShareJsDoc extends EventEmitter
 	class ShareJsDoc extends EventEmitter
 		constructor: (@doc_id, docLines, version, @socket) ->
 		constructor: (@doc_id, docLines, version, @socket) ->
 			# Dencode any binary bits of data
 			# Dencode any binary bits of data
@@ -33,11 +35,15 @@ define [
 
 
 			@_doc = new ShareJs.Doc @connection, @doc_id,
 			@_doc = new ShareJs.Doc @connection, @doc_id,
 				type: @type
 				type: @type
+			@_doc.setFlushDelay(SINGLE_USER_FLUSH_DELAY)
 			@_doc.on "change", () =>
 			@_doc.on "change", () =>
 				@trigger "change"
 				@trigger "change"
 			@_doc.on "acknowledge", () =>
 			@_doc.on "acknowledge", () =>
 				@trigger "acknowledge"
 				@trigger "acknowledge"
 			@_doc.on "remoteop", () =>
 			@_doc.on "remoteop", () =>
+				# As soon as we're working with a collaborator, start sending
+				# ops as quickly as possible for low latency.
+				@_doc.setFlushDelay(0)
 				@trigger "remoteop"
 				@trigger "remoteop"
 
 
 			@_bindToDocChanges(@_doc)
 			@_bindToDocChanges(@_doc)

+ 9 - 1
services/web/public/coffee/ide/editor/sharejs/vendor/client/doc.coffee

@@ -247,6 +247,9 @@ class Doc
   # Only one op can be in-flight at a time, so if an op is already on its way then
   # Only one op can be in-flight at a time, so if an op is already on its way then
   # this method does nothing.
   # this method does nothing.
   flush: =>
   flush: =>
+    delete @flushTimeout
+    #console.log "CALLED FLUSH"
+
     return unless @connection.state == 'ok' and @inflightOp == null and @pendingOp != null
     return unless @connection.state == 'ok' and @inflightOp == null and @pendingOp != null
 
 
     # Rotate null -> pending -> inflight
     # Rotate null -> pending -> inflight
@@ -256,6 +259,7 @@ class Doc
     @pendingOp = null
     @pendingOp = null
     @pendingCallbacks = []
     @pendingCallbacks = []
 
 
+    #console.log "SENDING OP TO SERVER", @inflightOp, @version
     @connection.send {doc:@name, op:@inflightOp, v:@version}
     @connection.send {doc:@name, op:@inflightOp, v:@version}
 
 
   # Submit an op to the server. The op maybe held for a little while before being sent, as only one
   # Submit an op to the server. The op maybe held for a little while before being sent, as only one
@@ -277,7 +281,11 @@ class Doc
 
 
     # A timeout is used so if the user sends multiple ops at the same time, they'll be composed
     # A timeout is used so if the user sends multiple ops at the same time, they'll be composed
     # & sent together.
     # & sent together.
-    setTimeout @flush, 0
+    if !@flushTimeout?
+        @flushTimeout = setTimeout @flush, @_flushDelay || 0
+  
+  setFlushDelay: (delay) =>
+      @_flushDelay = delay
   
   
   shout: (msg) =>
   shout: (msg) =>
     # Meta ops don't have to queue, they can go direct. Good/bad idea?
     # Meta ops don't have to queue, they can go direct. Good/bad idea?

+ 2 - 0
services/web/public/coffee/ide/pdf/controllers/PdfController.coffee

@@ -123,6 +123,8 @@ define [
 			return if $scope.pdf.compiling
 			return if $scope.pdf.compiling
 			$scope.pdf.compiling = true
 			$scope.pdf.compiling = true
 			
 			
+			ide.$scope.$broadcast("flush-changes")
+
 			if !options.isAutoCompile
 			if !options.isAutoCompile
 				compileCount++
 				compileCount++
 				if compileCount == 1
 				if compileCount == 1