overleaf/services/web/app/coffee/Features/Chat/ChatController.coffee
James Allen 014e3afb36 Don't call sync functions inside async
Calling sync functions inside async can trigger the node max stack size.
Instead, build up our unique list of ids in advance, so we only call a
method in async for each user we actually need to look up, asynchronously.
Then use all the cached values synchronously afterwards.
2017-05-04 17:04:20 +01:00

65 lines
No EOL
2.5 KiB
CoffeeScript

ChatApiHandler = require("./ChatApiHandler")
EditorRealTimeController = require("../Editor/EditorRealTimeController")
logger = require("logger-sharelatex")
AuthenticationController = require('../Authentication/AuthenticationController')
UserInfoManager = require('../User/UserInfoManager')
UserInfoController = require('../User/UserInfoController')
async = require "async"
module.exports = ChatController =
sendMessage: (req, res, next)->
project_id = req.params.project_id
content = req.body.content
user_id = AuthenticationController.getLoggedInUserId(req)
if !user_id?
err = new Error('no logged-in user')
return next(err)
ChatApiHandler.sendGlobalMessage project_id, user_id, content, (err, message) ->
return next(err) if err?
UserInfoManager.getPersonalInfo message.user_id, (err, user) ->
return next(err) if err?
message.user = UserInfoController.formatPersonalInfo(user)
EditorRealTimeController.emitToRoom project_id, "new-chat-message", message, (err)->
res.send(204)
getMessages: (req, res, next)->
project_id = req.params.project_id
query = req.query
logger.log project_id:project_id, query:query, "getting messages"
ChatApiHandler.getGlobalMessages project_id, query.limit, query.before, (err, messages) ->
return next(err) if err?
ChatController._injectUserInfoIntoThreads {global: { messages: messages }}, (err) ->
return next(err) if err?
logger.log length: messages?.length, "sending messages to client"
res.json messages
_injectUserInfoIntoThreads: (threads, callback = (error, threads) ->) ->
# There will be a lot of repitition of user_ids, so first build a list
# of unique ones to perform db look ups on, then use these to populate the
# user fields
user_ids = {}
for thread_id, thread of threads
if thread.resolved
user_ids[thread.resolved_by_user_id] = true
for message in thread.messages
user_ids[message.user_id] = true
jobs = []
users = {}
for user_id, _ of user_ids
do (user_id) ->
jobs.push (cb) ->
UserInfoManager.getPersonalInfo user_id, (err, user) ->
return cb(error) if error?
user = UserInfoController.formatPersonalInfo user
users[user_id] = user
cb()
async.series jobs, (error) ->
return callback(error) if error?
for thread_id, thread of threads
if thread.resolved
thread.resolved_by_user = users[thread.resolved_by_user_id]
for message in thread.messages
message.user = users[message.user_id]
return callback null, threads