feat: http user join/leave

This commit is contained in:
cha0s 2020-07-16 22:46:11 -05:00
parent 7780efa239
commit a2a485fbee
2 changed files with 50 additions and 40 deletions

View File

@ -1,47 +1,40 @@
import {joinChannel} from '~/common/channel'; import {joinChannel} from '~/common/channel';
import createRedisClient from './redis'; import createRedisClient, {keys} from './redis';
const redisClient = createRedisClient(); const redisClient = createRedisClient();
const enterChannel = async (req, channel) => { const channelState = async (req, channel) => {
const messages = await new Promise((resolve, reject) => { const messageKeys = await keys(redisClient, `${channel}:messages:*`);
redisClient.scan( const messages = 0 === messageKeys.length
0, ? []
'COUNT', 50, : await new Promise((resolve, reject) => {
'MATCH', `${channel}:*`, redisClient.mget(messageKeys, (error, replies) => (
(error, [, keys]) => (
error error
? reject(error) ? reject(error)
: resolve( : resolve(replies
0 === keys.length .map((reply, i) => ({
? [] ...JSON.parse(reply),
: new Promise((resolve, reject) => { uuid: messageKeys[i].split(':')[2],
redisClient.mget(keys, (error, replies) => ( }))
error .sort((l, r) => l.timestamp - r.timestamp))
? reject(error) ));
: resolve(replies });
.map((reply, i) => ({ const socketKeys = await keys(redisClient, `${channel}:users:*`);
...JSON.parse(reply), const users = 0 === socketKeys.length
uuid: keys[i].split(':')[1], ? []
})) : await new Promise((resolve, reject) => {
.sort((l, r) => l.timestamp - r.timestamp)) redisClient.mget(socketKeys, (error, replies) => (
)); error ? reject(error) : resolve(
}), Object
) .keys(replies.reduce((r, k) => ({[k]: true, ...r}), {}))
), .map((idStrings) => parseInt(idStrings, 10)),
); )
}); ));
// const users = await new Promise((resolve, reject) => { });
// req.adapter.remoteJoin(req.socketId, channel, (error) => {
// if (error) {
// reject(error);
// return;
// }
// });
// });
return { return {
messages, messages,
users,
}; };
}; };
@ -72,14 +65,14 @@ export const chatState = async (req) => {
recent: [], recent: [],
}; };
const entries = await Promise.all( const entries = await Promise.all(
toHydrate.map((favorite) => enterChannel(req, joinChannel(favorite))), toHydrate.map((favorite) => channelState(req, joinChannel(favorite))),
); );
for (let i = 0; i < toHydrate.length; i++) { for (let i = 0; i < toHydrate.length; i++) {
const channel = joinChannel(toHydrate[i]); const channel = joinChannel(toHydrate[i]);
const {messages} = entries[i]; const {messages, users} = entries[i];
chat.channels[channel] = { chat.channels[channel] = {
messages: messages.map((message) => message.uuid), messages: messages.map((message) => message.uuid),
users: [], users,
}; };
messages.forEach((message) => { messages.forEach((message) => {
chat.messages[message.uuid] = message; chat.messages[message.uuid] = message;

View File

@ -11,7 +11,7 @@ import Message from '~/common/packets/message.packet';
import {channelsToHydrate} from '~/server/entry'; import {channelsToHydrate} from '~/server/entry';
import passport from './passport'; import passport from './passport';
import createRedisClient from './redis'; import createRedisClient, {keys} from './redis';
import session from './session'; import session from './session';
const pubClient = createRedisClient(); const pubClient = createRedisClient();
@ -46,6 +46,17 @@ export function createSocketServer(httpServer) {
); );
next(); next();
}); });
socketServer.io.use(async (socket, next) => {
await Promise.all(
channelsToHydrate(socket.handshake)
.map((channel) => new Promise((resolve, reject) => {
const key = `${joinChannel(channel)}:users:${socket.id}`;
const {user} = socket.handshake;
pubClient.set(key, user ? user.id : 0, (error) => (error ? reject(error) : resolve()));
})),
);
next();
});
socketServer.on('connect', (socket) => { socketServer.on('connect', (socket) => {
const {req} = socket; const {req} = socket;
socket.on('packet', (packet, fn) => { socket.on('packet', (packet, fn) => {
@ -54,7 +65,7 @@ export function createSocketServer(httpServer) {
const owner = req.user ? req.user.id : 0; const owner = req.user ? req.user.id : 0;
const timestamp = Date.now(); const timestamp = Date.now();
const uuid = uuidv4(); const uuid = uuidv4();
const key = `${channel}:${uuid}`; const key = `${channel}:messages:${uuid}`;
pubClient pubClient
.multi() .multi()
.set(key, JSON.stringify({ .set(key, JSON.stringify({
@ -66,6 +77,12 @@ export function createSocketServer(httpServer) {
.exec(() => fn([timestamp, uuid])); .exec(() => fn([timestamp, uuid]));
} }
}); });
socket.on('disconnect', async () => {
const socketKeys = await keys(pubClient, `*:users:${socket.id}`);
if (socketKeys.length > 0) {
pubClient.del(socketKeys);
}
});
}); });
return socketServer; return socketServer;
} }