Real-time Chat (#7664)

* feat(realtime-chat): add Pusher library to the server

* feat(realtime-chat): only for private groups

* feat(realtime-chat): add authentication endpoint for Pusher

* feat(realtime-chat): client proof of concept

* fix typo in apidoc

* feat(realtime-chat): redo authentication and write integration tests

* remove firebase code

* fix client side tests

* fix line ending in bower.json

* feat(realtime chat): use presence channels for parties, send events & disconnect clients if user leaves or is removed from party, automatically update UI

* pusher: enable all events in the background

* fix pusher integration tests
This commit is contained in:
Matteo Pagliazzi
2016-07-02 15:17:24 +02:00
committed by GitHub
parent 889c41fa18
commit 0880850408
26 changed files with 393 additions and 285 deletions

View File

@@ -8,6 +8,7 @@ import {
import _ from 'lodash';
import { removeFromArray } from '../../libs/api-v3/collectionManipulators';
import { getUserInfo, getGroupUrl, sendTxn } from '../../libs/api-v3/email';
import pusher from '../../libs/api-v3/pusher';
import nconf from 'nconf';
import Bluebird from 'bluebird';
@@ -53,8 +54,8 @@ api.getChat = {
* @apiGroup Chat
*
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {message} Body parameter - message The message to post
* @apiParam {previousMsg} previousMsg Query parameter - The previous chat message which will force a return of the full group chat
* @apiParam {string} message Body parameter - message The message to post
* @apiParam {UUID} previousMsg Query parameter - The previous chat message which will force a return of the full group chat
*
* @apiSuccess data An array of chat messages if a new message was posted after previousMsg, otherwise the posted message
*/
@@ -83,7 +84,7 @@ api.postChat = {
let lastClientMsg = req.query.previousMsg;
chatUpdated = lastClientMsg && group.chat && group.chat[0] && group.chat[0].id !== lastClientMsg ? true : false;
group.sendChat(req.body.message, user);
let newChatMessage = group.sendChat(req.body.message, user);
let toSave = [group.save()];
@@ -93,6 +94,14 @@ api.postChat = {
}
let [savedGroup] = await Bluebird.all(toSave);
// real-time chat is only enabled for private groups (for now only for parties)
if (savedGroup.privacy === 'private' && savedGroup.type === 'party') {
// req.body.pusherSocketId is sent from official clients to identify the sender user's real time socket
// see https://pusher.com/docs/server_api_guide/server_excluding_recipients
pusher.trigger(`presence-group-${savedGroup._id}`, 'new-chat', newChatMessage, req.body.pusherSocketId);
}
if (chatUpdated) {
res.respond(200, {chat: Group.toJSONCleanChat(savedGroup, user).chat});
} else {
@@ -107,8 +116,8 @@ api.postChat = {
* @apiName LikeChat
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message _id
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} chatId The chat message _id
*
* @apiSuccess {Object} data The liked chat message
*/
@@ -154,8 +163,8 @@ api.likeChat = {
* @apiName FlagChat
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message id
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} chatId The chat message id
*
* @apiSuccess {object} data The flagged chat message
*/
@@ -243,8 +252,8 @@ api.flagChat = {
* @apiName ClearFlags
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {chatId} chatId The chat message id
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} chatId The chat message id
*
* @apiSuccess {Object} data An empty object
*/
@@ -318,7 +327,7 @@ api.clearChatFlags = {
* @apiName SeenChat
* @apiGroup Chat
*
* @apiParam {groupId} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
*
* @apiSuccess {Object} data An empty object
*/
@@ -354,8 +363,8 @@ api.seenChat = {
* @apiGroup Chat
*
* @apiParam {string} previousMsg Query parameter - The last message fetched by the client so that the whole chat will be returned only if new messages have been posted in the meantime
* @apiParam {string} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {string} chatId The chat message id
* @apiParam {UUID} groupId The group _id ('party' for the user party and 'habitrpg' for tavern are accepted)
* @apiParam {UUID} chatId The chat message id
*
* @apiSuccess data The updated chat array or an empty object if no message was posted after previousMsg
* @apiSuccess {Object} data An empty object when the previous message was deleted