Просмотр исходного кода

Generate deterministic range ids based on seed

James Allen 9 лет назад
Родитель
Сommit
7cac2f7d76

+ 2 - 0
services/document-updater/app/coffee/RangesManager.coffee

@@ -8,6 +8,8 @@ module.exports = RangesManager =
 		rangesTracker = new RangesTracker(changes, comments)
 		for update in updates
 			rangesTracker.track_changes = !!update.meta.tc
+			if !!update.meta.tc
+				rangesTracker.setIdSeed(update.meta.tc)
 			for op in update.op
 				rangesTracker.applyOp(op, { user_id: update.meta?.user_id })
 		

+ 16 - 47
services/document-updater/app/coffee/RangesTracker.coffee

@@ -35,18 +35,19 @@ load = (EventEmitter) ->
 		#   * Inserts by another user will not combine with inserts by the first user. If they are in the
 		#     middle of a previous insert by the first user, the original insert will be split into two.
 		constructor: (@changes = [], @comments = []) ->
-			# Change objects have the following structure:
-			# {
-			#   id: ... # Uniquely generated by us
-			#   op: { # ShareJs style op tracking the offset (p) and content inserted (i) or deleted (d)
-			#     i: "..."
-			#     p: 42
-			#   }
-			# }
-			#
-			# Ids are used to uniquely identify a change, e.g. for updating it in the database, or keeping in
-			# sync with Ace ranges.
-			@id = 0
+
+		getIdSeed: () ->
+			return @id_seed
+
+		setIdSeed: (seed) ->
+			@id_seed = seed
+			@id_increment = 0
+
+		newId: () ->
+			@id_increment++
+			increment = @id_increment.toString(16)
+			id = @id_seed + '000000'.substr(0, 6 - increment.length) + increment;
+			return id
 		
 		getComment: (comment_id) ->
 			comment = null
@@ -56,19 +57,6 @@ load = (EventEmitter) ->
 					break
 			return comment
 		
-		resolveCommentId: (comment_id, resolved_data) ->
-			comment = @getComment(comment_id)
-			return if !comment?
-			comment.metadata.resolved = true
-			comment.metadata.resolved_data = resolved_data
-			@emit "comment:resolved", comment
-		
-		unresolveCommentId: (comment_id) ->
-			comment = @getComment(comment_id)
-			return if !comment?
-			comment.metadata.resolved = false
-			@emit "comment:unresolved", comment
-		
 		removeCommentId: (comment_id) ->
 			comment = @getComment(comment_id)
 			return if !comment?
@@ -88,7 +76,7 @@ load = (EventEmitter) ->
 			return if !change?
 			@_removeChange(change)
 
-		applyOp: (op, metadata) ->
+		applyOp: (op, metadata = {}) ->
 			metadata.ts ?= new Date()
 			# Apply an op that has been applied to the document to our changes to keep them up to date
 			if op.i?
@@ -105,7 +93,7 @@ load = (EventEmitter) ->
 		addComment: (op, metadata) ->
 			# TODO: Don't allow overlapping comments?
 			@comments.push comment = {
-				id: @_newId()
+				id: @newId()
 				op: # Copy because we'll modify in place
 					c: op.c
 					p: op.p
@@ -394,28 +382,9 @@ load = (EventEmitter) ->
 			if moved_changes.length > 0
 				@emit "changes:moved", moved_changes
 
-		_newId: () ->
-			# Generate a Mongo ObjectId
-			# Reference: https://github.com/dreampulse/ObjectId.js/blob/master/src/main/javascript/Objectid.js
-			@_pid ?= Math.floor(Math.random() * (32767))
-			@_machine ?= Math.floor(Math.random() * (16777216))
-			timestamp = Math.floor(new Date().valueOf() / 1000)
-			@_increment ?= 0
-			@_increment++
-			
-			timestamp = timestamp.toString(16)
-			machine = @_machine.toString(16)
-			pid = @_pid.toString(16)
-			increment = @_increment.toString(16)
-			
-			return '00000000'.substr(0, 8 - timestamp.length) + timestamp +
-				'000000'.substr(0, 6 - machine.length) + machine +
-				'0000'.substr(0, 4 - pid.length) + pid +
-				'000000'.substr(0, 6 - increment.length) + increment;
-
 		_addOp: (op, metadata) ->
 			change = {
-				id: @_newId()
+				id: @newId()
 				op: op
 				metadata: metadata
 			}

+ 5 - 2
services/document-updater/test/acceptance/coffee/RangesTests.coffee

@@ -12,6 +12,7 @@ describe "Ranges", ->
 		before (done) ->
 			@project_id = DocUpdaterClient.randomId()
 			@user_id = DocUpdaterClient.randomId()
+			@id_seed = "587357bd35e64f6157"
 			@doc = {
 				id: DocUpdaterClient.randomId()
 				lines: ["aaa"]
@@ -25,7 +26,7 @@ describe "Ranges", ->
 				doc: @doc.id
 				op: [{ i: "456", p: 5 }]
 				v: 1
-				meta: { user_id: @user_id, tc: 1 }
+				meta: { user_id: @user_id, tc: @id_seed }
 			}, {
 				doc: @doc.id
 				op: [{ d: "12", p: 1 }]
@@ -52,6 +53,7 @@ describe "Ranges", ->
 				ranges = data.ranges
 				change = ranges.changes[0]
 				change.op.should.deep.equal { i: "456", p: 3 }
+				change.id.should.equal @id_seed + "000001"
 				change.metadata.user_id.should.equal @user_id
 				done()
 	
@@ -135,6 +137,7 @@ describe "Ranges", ->
 		before (done) ->
 			@project_id = DocUpdaterClient.randomId()
 			@user_id = DocUpdaterClient.randomId()
+			@id_seed = "587357bd35e64f6157"
 			@doc = {
 				id: DocUpdaterClient.randomId()
 				lines: ["a123aa"]
@@ -143,7 +146,7 @@ describe "Ranges", ->
 				doc: @doc.id
 				op: [{ i: "456", p: 5 }]
 				v: 0
-				meta: { user_id: @user_id, tc: 1 }
+				meta: { user_id: @user_id, tc: @id_seed }
 			}
 			MockWebApi.insertDoc @project_id, @doc.id, {
 				lines: @doc.lines