Răsfoiți Sursa

Add in clientTracking.updatePosition end point

James Allen 12 ani în urmă
părinte
comite
e769819521

+ 22 - 17
services/real-time/app/coffee/Router.coffee

@@ -5,6 +5,16 @@ HttpController = require "./HttpController"
 Utils = require "./Utils"
 
 module.exports = Router =
+	_handleError: (callback, error, client, method, extraAttrs = {}) ->
+		Utils.getClientAttributes client, ["project_id", "doc_id", "user_id"], (_, attrs) ->
+			for key, value of extraAttrs
+				attrs[key] = value
+			attrs.client_id = client.id
+			attrs.err = error
+			logger.error attrs, "server side error in #{method}"
+		# Don't return raw error to prevent leaking server side info
+		return callback {message: "Something went wrong"}
+
 	configure: (app, io, session) ->
 		app.set("io", io)
 		app.get "/clients", HttpController.getConnectedClients
@@ -29,9 +39,7 @@ module.exports = Router =
 			client.on "joinProject", (data = {}, callback) ->
 				WebsocketController.joinProject client, user, data.project_id, (err, args...) ->
 					if err?
-						logger.error {err, user_id: user?.id, project_id: data.project_id}, "server side error in joinProject"
-						# Don't return raw error to prevent leaking server side info
-						return callback {message: "Something went wrong"}
+						Router._handleError callback, err, client, "joinProject", {project_id: data.project_id, user_id: user?.id}
 					else
 						callback(null, args...)
 						
@@ -44,30 +52,27 @@ module.exports = Router =
 				
 				WebsocketController.joinDoc client, doc_id, fromVersion, (err, args...) ->
 					if err?
-						Utils.getClientAttributes client, ["project_id", "user_id"], (_, {project_id, user_id}) ->
-							logger.error {err, client_id: client.id, user_id, project_id, doc_id, fromVersion}, "server side error in joinDoc"
-						# Don't return raw error to prevent leaking server side info
-						return callback {message: "Something went wrong"}
+						Router._handleError callback, err, client, "joinDoc", {doc_id, fromVersion}
 					else
 						callback(null, args...)
 						
 			client.on "leaveDoc", (doc_id, callback) ->
 				WebsocketController.leaveDoc client, doc_id, (err, args...) ->
 					if err?
-						Utils.getClientAttributes client, ["project_id", "user_id"], (_, {project_id, user_id}) ->
-							logger.error {err, client_id: client.id, user_id, project_id, doc_id}, "server side error in leaveDoc"
-						# Don't return raw error to prevent leaking server side info
-						return callback {message: "Something went wrong"}
+						Router._handleError callback, err, client, "leaveDoc"
 					else
 						callback(null, args...)
 						
-			client.on "getConnectedUsers", (callback = (error, users) ->) ->
+			client.on "clientTracking.getConnectedUsers", (callback = (error, users) ->) ->
 				WebsocketController.getConnectedUsers client, (err, users) ->
 					if err?
-						Utils.getClientAttributes client, ["project_id", "user_id", "doc_id"], (_, {project_id, user_id, doc_id}) ->
-							logger.error {err, client_id: client.id, user_id, project_id, doc_id}, "server side error in getConnectedUsers"
-						# Don't return raw error to prevent leaking server side info
-						return callback {message: "Something went wrong"}
+						Router._handleError callback, err, client, "clientTracking.getConnectedUsers"
 					else
 						callback(null, users)
-		
+						
+			client.on "clientTracking.updatePosition", (cursorData, callback = (error) ->) ->
+				WebsocketController.updateClientPosition client, cursorData, (err) ->
+					if err?
+						Router._handleError callback, err, client, "clientTracking.updatePosition"
+					else
+						callback()

+ 30 - 0
services/real-time/app/coffee/WebsocketController.coffee

@@ -70,7 +70,37 @@ module.exports = WebsocketController =
 		client.leave doc_id
 		callback()
 		
+	updateClientPosition: (client, cursorData, callback = (error) ->) ->
+		Utils.getClientAttributes client, [
+			"project_id", "first_name", "last_name", "email", "user_id"
+		], (error, {project_id, first_name, last_name, email, user_id}) ->
+			return callback(error) if error?
+			logger.log {user_id, project_id, client_id: client.id, cursorData: cursorData}, "updating client position"
+			cursorData.id      = client.id
+			cursorData.user_id = user_id if user_id?
+			cursorData.email   = email   if email?
+			if first_name? and last_name?
+				cursorData.name = first_name + " " + last_name
+				ConnectedUsersManager.updateUserPosition(project_id, client.id, {
+					first_name: first_name,
+					last_name:  last_name,
+					email:      email,
+					user_id:    user_id
+				}, {
+					row:    cursorData.row,
+					column: cursorData.column,
+					doc_id: cursorData.doc_id
+				}, callback)
+			else
+				cursorData.name = "Anonymous"
+				callback()
+			#EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientUpdated", cursorData)
+			#callback()
+		
 	getConnectedUsers: (client, callback = (error, users) ->) ->
+		Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
+			logger.log {user_id, project_id, client_id: client.id}, "getting connected users"
+			
 		AuthorizationManager.assertClientCanViewProject client, (error) ->
 			return callback(error) if error?
 			client.get "project_id", (error, project_id) ->

+ 61 - 0
services/real-time/test/acceptance/coffee/ClientTrackingTests.coffee

@@ -0,0 +1,61 @@
+chai = require("chai")
+expect = chai.expect
+chai.should()
+
+RealTimeClient = require "./helpers/RealTimeClient"
+MockWebServer = require "./helpers/MockWebServer"
+FixturesManager = require "./helpers/FixturesManager"
+
+describe "clientTracking", ->
+	before (done) ->
+		FixturesManager.setUpProject {
+			privilegeLevel: "owner"
+			project: {
+				name: "Test Project"
+			}
+		}, (error, data) =>
+			throw error if error?
+			{@user_id, @project_id} = data
+			@clientA = RealTimeClient.connect()
+			@clientB = RealTimeClient.connect()
+			@clientA.emit "joinProject", {
+				project_id: @project_id
+			}, (error) =>
+				throw error if error?
+				@clientB.emit "joinProject", {
+					project_id: @project_id
+				}, (error) =>
+					throw error if error?
+					done()
+					
+	describe "when a client updates its cursor location", ->
+		before (done) ->
+			@updates = []
+			@clientB.on "clientTracking.clientUpdated", (data) ->
+				@updates.push data
+				
+			@clientA.emit "clientTracking.updatePosition", {
+				row: @row = 42
+				column: @column = 36
+				doc_id: @doc_id = "mock-doc-id"
+			}, (error) ->
+				throw error if error?
+				done()
+			
+		it "should tell other clients about the update"
+		
+		it "should record the update in getConnectedUsers", (done) ->
+			@clientB.emit "clientTracking.getConnectedUsers", (error, users) =>
+				for user in users
+					if user.client_id == @clientA.socket.sessionid
+						expect(user.cursorData).to.deep.equal({
+							row: @row
+							column: @column
+							doc_id: @doc_id 
+						})
+						return done()
+				throw new Error("user was never found")
+				
+				
+	describe "anonymous users", ->
+		it "should test something..."

+ 1 - 1
services/real-time/test/acceptance/coffee/JoinProjectTests.coffee

@@ -47,7 +47,7 @@ describe "joinProject", ->
 				done()
 				
 		it "should have marked the user as connected", (done) ->
-			@client.emit "getConnectedUsers", (error, users) =>
+			@client.emit "clientTracking.getConnectedUsers", (error, users) =>
 				connected = false
 				for user in users
 					if user.client_id == @client.socket.sessionid and user.user_id == @user_id

+ 5 - 1
services/real-time/test/acceptance/coffee/helpers/FixturesManager.coffee

@@ -16,7 +16,11 @@ module.exports = FixturesManager =
 		MockWebServer.run (error) =>
 			throw error if error?
 			RealTimeClient.setSession {
-				user: { _id: user_id }
+				user: {
+					_id: user_id
+					first_name: "Joe"
+					last_name: "Bloggs"
+				}
 			}, (error) =>
 				throw error if error?
 				callback null, {project_id, user_id, privilegeLevel, project}

+ 69 - 1
services/real-time/test/unit/coffee/WebsocketControllerTests.coffee

@@ -217,4 +217,72 @@ describe 'WebsocketController', ->
 			it "should return an error", ->
 				@callback.calledWith(@err).should.equal true
 				
-		
+	describe "updateClientPosition", ->
+		beforeEach ->
+			#@EditorRealTimeController.emitToRoom = sinon.stub()
+			@ConnectedUsersManager.updateUserPosition = sinon.stub().callsArgWith(4)
+			@update = {
+				doc_id: @doc_id = "doc-id-123"
+				row: @row = 42
+				column: @column = 37
+			}
+
+		describe "with a logged in user", ->
+			beforeEach ->
+				@clientParams = {
+					project_id: @project_id
+					first_name: @first_name = "Douglas"
+					last_name: @last_name = "Adams"
+					email: @email = "joe@example.com"
+					user_id: @user_id = "user-id-123"
+				}
+				@client.get = (param, callback) => callback null, @clientParams[param]
+				@WebsocketController.updateClientPosition @client, @update
+
+				@populatedCursorData = 
+					doc_id: @doc_id,
+					id: @client.id
+					name: "#{@first_name} #{@last_name}"
+					row: @row
+					column: @column
+					email: @email
+					user_id: @user_id
+
+			# it "should send the update to the project room with the user's name", ->
+			# 	@EditorRealTimeController.emitToRoom.calledWith(@project_id, "clientTracking.clientUpdated", @populatedCursorData).should.equal true
+
+			it "should send the  cursor data to the connected user manager", (done)->
+				@ConnectedUsersManager.updateUserPosition.calledWith(@project_id, @client.id, {
+					user_id: @user_id,
+					email: @email,
+					first_name: @first_name,
+					last_name: @last_name
+				}, {
+					row: @row
+					column: @column
+					doc_id: @doc_id
+				}).should.equal true
+				done()
+
+		describe "with an anonymous user", ->
+			beforeEach ->
+				@clientParams = {
+					project_id: @project_id
+				}
+				@client.get = (param, callback) => callback null, @clientParams[param]
+				@WebsocketController.updateClientPosition @client, @update
+
+			# it "should send the update to the project room with an anonymous name", ->
+			# 	@EditorRealTimeController.emitToRoom
+			# 		.calledWith(@project_id, "clientTracking.clientUpdated", {
+			# 			doc_id: @doc_id,
+			# 			id: @client.id
+			# 			name: "Anonymous"
+			# 			row: @row
+			# 			column: @column
+			# 		})
+			# 		.should.equal true
+				
+			it "should not send cursor data to the connected user manager", (done)->
+				@ConnectedUsersManager.updateUserPosition.called.should.equal false
+				done()