ConnectedUsersManager.coffee 2.8 KB

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