mirror of
https://github.com/overleaf/overleaf.git
synced 2025-02-23 00:13:30 +00:00
cursor data is stored in redis
This commit is contained in:
parent
61b7bea203
commit
d13676dab2
4 changed files with 73 additions and 28 deletions
|
@ -11,6 +11,8 @@ ONE_HOUR_IN_S = 60 * 60
|
|||
ONE_DAY_IN_S = ONE_HOUR_IN_S * 24
|
||||
FOUR_DAYS_IN_S = ONE_DAY_IN_S * 4
|
||||
|
||||
USER_TIMEOUT_IN_S = ONE_HOUR_IN_S
|
||||
|
||||
buildProjectSetKey = (project_id)-> return "users_in_project:#{project_id}"
|
||||
buildUserKey = (project_id, user_id)-> return "connected_user:#{project_id}:#{user_id}"
|
||||
|
||||
|
@ -25,7 +27,9 @@ module.exports =
|
|||
(cb)->
|
||||
rclient.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S, cb
|
||||
(cb)->
|
||||
rclient.setex buildUserKey(project_id, user_id), ONE_HOUR_IN_S, new Date(), cb
|
||||
rclient.hset buildUserKey(project_id, user_id), "connected_at", new Date(), cb
|
||||
(cb)->
|
||||
rclient.expire buildUserKey(project_id, user_id), USER_TIMEOUT_IN_S, cb
|
||||
], (err)->
|
||||
if err?
|
||||
logger.err err:err, project_id:project_id, user_id:user_id, "problem marking user as connected"
|
||||
|
@ -43,13 +47,25 @@ module.exports =
|
|||
], callback
|
||||
|
||||
_getConnectedUser: (project_id, user_id, callback)->
|
||||
rclient.get buildUserKey(project_id, user_id), (err, result)->
|
||||
rclient.hgetall buildUserKey(project_id, user_id), (err, result)->
|
||||
if !result?
|
||||
connected = false
|
||||
result =
|
||||
connected : false
|
||||
user_id:user_id
|
||||
else
|
||||
connected = true
|
||||
result.connected = true
|
||||
result.user_id = user_id
|
||||
|
||||
callback err, result
|
||||
|
||||
setUserCursorPosition: (project_id, user_id, cursorData, callback)->
|
||||
async.series [
|
||||
(cb)->
|
||||
rclient.hset buildUserKey(project_id, user_id), "cursorData", JSON.stringify(cursorData), cb
|
||||
(cb)->
|
||||
rclient.expire buildUserKey(project_id, user_id), USER_TIMEOUT_IN_S, cb
|
||||
], callback
|
||||
|
||||
callback err, {connected:connected, user_id:user_id}
|
||||
|
||||
getConnectedUsers: (project_id, callback)->
|
||||
self = @
|
||||
|
@ -60,8 +76,5 @@ module.exports =
|
|||
async.series jobs, (err, users)->
|
||||
users = _.filter users, (user)->
|
||||
user.connected
|
||||
user_ids = _.map users, (user)->
|
||||
user.user_id
|
||||
callback err, user_ids
|
||||
|
||||
callback err, users
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ module.exports = EditorController =
|
|||
cursorData.email = email if email?
|
||||
if first_name? and last_name?
|
||||
cursorData.name = first_name + " " + last_name
|
||||
ConnectedUsersManager.setUserCursorPosition(project_id, user_id, cursorData, ->)
|
||||
else
|
||||
cursorData.name = "Anonymous"
|
||||
EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientUpdated", cursorData)
|
||||
|
|
|
@ -25,6 +25,8 @@ describe "ConnectedUsersManager", ->
|
|||
del:sinon.stub()
|
||||
smembers:sinon.stub()
|
||||
expire:sinon.stub()
|
||||
hset:sinon.stub()
|
||||
hgetall:sinon.stub()
|
||||
tk.freeze(new Date())
|
||||
|
||||
@ConnectedUsersManager = SandboxedModule.require modulePath, requires:
|
||||
|
@ -40,14 +42,14 @@ describe "ConnectedUsersManager", ->
|
|||
|
||||
describe "markUserAsConnected", ->
|
||||
beforeEach ->
|
||||
@rClient.setex.callsArgWith(3)
|
||||
@rClient.hset.callsArgWith(3)
|
||||
@rClient.sadd.callsArgWith(2)
|
||||
@rClient.expire.callsArgWith(2)
|
||||
|
||||
|
||||
it "should set a key with the date and give it a ttl", (done)->
|
||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
||||
@rClient.setex.calledWith("connected_user:#{@project_id}:#{@user_id}", 60 * 60, new Date()).should.equal true
|
||||
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@user_id}", "connected_at", new Date()).should.equal true
|
||||
done()
|
||||
|
||||
it "should push the user_id on to the project list", (done)->
|
||||
|
@ -60,6 +62,11 @@ describe "ConnectedUsersManager", ->
|
|||
@rClient.expire.calledWith("users_in_project:#{@project_id}", 24 * 4 * 60 * 60).should.equal true
|
||||
done()
|
||||
|
||||
it "should add a ttl to the connected user so it stays clean", (done)->
|
||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
||||
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@user_id}", 60 * 60).should.equal true
|
||||
done()
|
||||
|
||||
describe "markUserAsDisconnected", ->
|
||||
beforeEach ->
|
||||
@rClient.srem.callsArgWith(2)
|
||||
|
@ -85,14 +92,14 @@ describe "ConnectedUsersManager", ->
|
|||
describe "_getConnectedUser", ->
|
||||
|
||||
it "should get the user returning connected if there is a value", (done)->
|
||||
@rClient.get.callsArgWith(1, null, new Date())
|
||||
@rClient.hgetall.callsArgWith(1, null, {connected_at:new Date(), cursorData:{row:1}})
|
||||
@ConnectedUsersManager._getConnectedUser @project_id, @user_id, (err, result)=>
|
||||
result.connected.should.equal true
|
||||
result.user_id.should.equal @user_id
|
||||
done()
|
||||
|
||||
it "should get the user returning connected if there is a value", (done)->
|
||||
@rClient.get.callsArgWith(1)
|
||||
@rClient.hgetall.callsArgWith(1)
|
||||
@ConnectedUsersManager._getConnectedUser @project_id, @user_id, (err, result)=>
|
||||
result.connected.should.equal false
|
||||
result.user_id.should.equal @user_id
|
||||
|
@ -114,11 +121,25 @@ describe "ConnectedUsersManager", ->
|
|||
it "should only return the users in the list which are still in redis", (done)->
|
||||
@ConnectedUsersManager.getConnectedUsers @project_id, (err, users)=>
|
||||
users.length.should.equal 2
|
||||
users[0].should.equal @users[0]
|
||||
users[1].should.equal @users[2]
|
||||
users[0].should.deep.equal {user_id:@users[0], connected:true}
|
||||
users[1].should.deep.equal {user_id:@users[2], connected:true}
|
||||
done()
|
||||
|
||||
describe "setUserCursorPosition", ->
|
||||
|
||||
beforeEach ->
|
||||
@cursorData = { row: 12, column: 9, doc_id: '53c3b8c85fee64000023dc6e' }
|
||||
@rClient.hset.callsArgWith(3)
|
||||
@rClient.expire.callsArgWith(2)
|
||||
|
||||
it "should add the cursor data to the users hash", (done)->
|
||||
@ConnectedUsersManager.setUserCursorPosition @project_id, @user_id, @cursorData, (err)=>
|
||||
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@user_id}", "cursorData", JSON.stringify(@cursorData)).should.equal true
|
||||
done()
|
||||
|
||||
|
||||
|
||||
|
||||
it "should add the ttl on", (done)->
|
||||
@ConnectedUsersManager.setUserCursorPosition @project_id, @user_id, @cursorData, (err)=>
|
||||
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@user_id}", 60 * 60).should.equal true
|
||||
done()
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ describe "EditorController", ->
|
|||
@ConnectedUsersManager =
|
||||
markUserAsDisconnected:sinon.stub()
|
||||
markUserAsConnected:sinon.stub()
|
||||
setUserCursorPosition:sinon.stub()
|
||||
|
||||
@EditorController = SandboxedModule.require modulePath, requires:
|
||||
"../../infrastructure/Server" : io : @io
|
||||
|
@ -262,11 +263,14 @@ describe "EditorController", ->
|
|||
describe "updateClientPosition", ->
|
||||
beforeEach ->
|
||||
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||
@ConnectedUsersManager.setUserCursorPosition.callsArgWith(3)
|
||||
@update = {
|
||||
doc_id: @doc_id = "doc-id-123"
|
||||
row: @row = 42
|
||||
column: @column = 37
|
||||
}
|
||||
|
||||
|
||||
describe "with a logged in user", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
|
@ -279,18 +283,21 @@ describe "EditorController", ->
|
|||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@EditorController.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", {
|
||||
doc_id: @doc_id,
|
||||
id: @client.id
|
||||
name: "#{@first_name} #{@last_name}"
|
||||
row: @row
|
||||
column: @column
|
||||
email: @email
|
||||
user_id: @user_id
|
||||
})
|
||||
.should.equal true
|
||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, "clientTracking.clientUpdated", @populatedCursorData).should.equal true
|
||||
|
||||
it "should send the cursor data to the connected user manager", (done)->
|
||||
@ConnectedUsersManager.setUserCursorPosition.calledWith(@project_id, @user_id, @populatedCursorData).should.equal true
|
||||
done()
|
||||
|
||||
describe "with an anonymous user", ->
|
||||
beforeEach ->
|
||||
|
@ -311,6 +318,9 @@ describe "EditorController", ->
|
|||
})
|
||||
.should.equal true
|
||||
|
||||
it "should not send cursor data to the connected user manager", (done)->
|
||||
@ConnectedUsersManager.setUserCursorPosition.called.should.equal false
|
||||
done()
|
||||
|
||||
describe "addUserToProject", ->
|
||||
beforeEach ->
|
||||
|
|
Loading…
Reference in a new issue