```
result = Promise.all([<Promise that rejects eventually>]) # rejection 1
result.then () -> RoomEvents.emit(eventName) # rejection 2
result.catch (err) -> RoomEvents.emit(eventName, err) # handle r1
```
As shown above, the second rejection remains unhandled. The fix is to
chain the `.catch()` onto the `.then()` Promise.
When the user provides a function as last argument for socket.emit,
socket.io will flag this as an RPC and add a cb as the last argument
to the client.on('event', ...) handler on the server side.
Without a function as last argument for socket.emit, the callback
argument on the server side is undefined, leading to invalid function
calls (`undefined()`) and an unhandled exception.
The user can also provide lots of other arguments, so the 2nd/3rd ...
argument is of arbitrary type, again leading to invalid function calls
-- e.g. `1()`.
This can now happen all the time, as we skip the join for clients that
disconnect before joinProject/joinDoc completed.
(cherry-picked from commit f357931de74e088800f3cced3898cce4f251dad0)
Sinon does not check the contents of the passed error when checked via
sinon.stub().calledWith.
```
callback = sinon.stub()
callback(new Error("some message"))
.calledWith(new Error("completely different message"))
=== true
```
Cherry-pick plus an additional patch for the joinProject bail-out.
(cherry picked from commit d9570fee70701a5f431c39fdbec5f8bc5a7843fe)
Also drop dead code:
- user_id bailout
There is a check on a completed joinProject call now. It will always
set a user_id, see Router.coffee which has a fallback `{_id:"..."}`.
- late project_id bailout
WebsocketLoadBalancer.emitToRoom will not work without a project_id.
We have to bail out before the call.
frontend -> real-time and doc-updater -> real-time should be in sync.
Otherwise we can send a payload to doc-updater, but can not receive the
confirmation of it -- and the client will send it again in a loop.
Also log the size of the payload.
bail out early on -- especially do not push the update into redis for
doc-updater to discard it.
Confirm the update silently, otherwise the frontend will send it again.
Broadcast a 'otUpdateError' message and disconnect the client, like
doc-updater would do.
Then, don't send new chat messages and new comments to those restricted clients.
We do this because we don't want to leak private information (email addresses
and names) to "restricted" users, those who have read-only access via a
shared token.