ConnectedUsersManager.coffee 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. _ = require("underscore")
  2. async = require("async")
  3. Settings = require('settings-sharelatex')
  4. logger = require("logger-sharelatex")
  5. redis = require('redis')
  6. rclient = redis.createClient(Settings.redis.web.port, Settings.redis.web.host)
  7. rclient.auth(Settings.redis.web.password)
  8. ONE_HOUR_IN_S = 60 * 60
  9. ONE_DAY_IN_S = ONE_HOUR_IN_S * 24
  10. FOUR_DAYS_IN_S = ONE_DAY_IN_S * 4
  11. USER_TIMEOUT_IN_S = ONE_HOUR_IN_S / 4
  12. buildProjectSetKey = (project_id)-> return "clients_in_project:#{project_id}"
  13. buildUserKey = (project_id, client_id)-> return "connected_user:#{project_id}:#{client_id}"
  14. module.exports =
  15. # Use the same method for when a user connects, and when a user sends a cursor
  16. # update. This way we don't care if the connected_user key has expired when
  17. # we receive a cursor update.
  18. updateUserPosition: (project_id, client_id, user, cursorData, callback = (err)->)->
  19. logger.log project_id:project_id, client_id:client_id, "marking user as connected"
  20. multi = rclient.multi()
  21. multi.sadd buildProjectSetKey(project_id), client_id
  22. multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
  23. multi.hset buildUserKey(project_id, client_id), "last_updated_at", Date.now()
  24. multi.hset buildUserKey(project_id, client_id), "user_id", user._id
  25. multi.hset buildUserKey(project_id, client_id), "first_name", user.first_name
  26. multi.hset buildUserKey(project_id, client_id), "last_name", user.last_name
  27. multi.hset buildUserKey(project_id, client_id), "email", user.email
  28. if cursorData?
  29. multi.hset buildUserKey(project_id, client_id), "cursorData", JSON.stringify(cursorData)
  30. multi.expire buildUserKey(project_id, client_id), USER_TIMEOUT_IN_S
  31. multi.exec (err)->
  32. if err?
  33. logger.err err:err, project_id:project_id, client_id:client_id, "problem marking user as connected"
  34. callback(err)
  35. markUserAsDisconnected: (project_id, client_id, callback)->
  36. logger.log project_id:project_id, client_id:client_id, "marking user as disconnected"
  37. multi = rclient.multi()
  38. multi.srem buildProjectSetKey(project_id), client_id
  39. multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
  40. multi.del buildUserKey(project_id, client_id)
  41. multi.exec callback
  42. _getConnectedUser: (project_id, client_id, callback)->
  43. rclient.hgetall buildUserKey(project_id, client_id), (err, result)->
  44. if !result?
  45. result =
  46. connected : false
  47. client_id:client_id
  48. else
  49. result.connected = true
  50. result.client_id = client_id
  51. if result.cursorData?
  52. result.cursorData = JSON.parse(result.cursorData)
  53. callback err, result
  54. getConnectedUsers: (project_id, callback)->
  55. self = @
  56. rclient.smembers buildProjectSetKey(project_id), (err, results)->
  57. jobs = results.map (client_id)->
  58. (cb)->
  59. self._getConnectedUser(project_id, client_id, cb)
  60. async.series jobs, (err, users)->
  61. users = _.filter users, (user)->
  62. user.connected
  63. callback err, users