fix: hydrate

This commit is contained in:
cha0s 2020-12-14 13:52:22 -06:00
parent b7331148b6
commit adba33448b

View File

@ -1,49 +1,41 @@
import {promisify} from 'util'; import {promisify} from 'util';
import D from 'debug'; // import D from 'debug';
import {ModelMap} from '@latus/db'; import {ModelMap} from '@latus/db';
import {createClient, keys} from '@latus/redis'; import {createClient, keys} from '@latus/redis';
import {channelIsAnonymous, parseChannel, renderChannel} from '@reddichat/core'; import {channelIsAnonymous, parseChannel, renderChannel} from '@reddichat/core';
const debug = D('@reddichat/chat/state'); // const debug = D('@reddichat/chat/state');
export const channelUserCounts = async (req, channel) => { export const channelUserCounts = async (req, channel) => {
const rooms = [renderChannel(channel)]; const rooms = [renderChannel(channel)];
debug('channelUserCounts: rooms(%O)', rooms);
const ids = await req.clients(rooms); const ids = await req.clients(rooms);
debug('channelUserCounts: ids(%O)', ids);
if (0 === ids.length) { if (0 === ids.length) {
return {}; return {};
} }
const replies = channelIsAnonymous(channel) const replies = channelIsAnonymous(channel)
? [ids.reduce((r, socketKey) => ({...r, [socketKey]: 0}), {})] ? [ids.reduce((r, socketKey) => ({...r, [socketKey]: 0}), {})]
: await req.intercom('@reddichat/user/users', ids); : await req.intercom('@reddichat/user/users', ids);
debug('channelUserCounts: replies(%O)', replies);
const uids = replies.reduce((r, m) => ({...r, ...m}), {}); const uids = replies.reduce((r, m) => ({...r, ...m}), {});
debug('channelUserCounts: uids(%O)', uids);
const reduced = Object.values(uids).reduce((r, uid) => ({...r, [uid]: 1 + (r[uid] || 0)}), {}); const reduced = Object.values(uids).reduce((r, uid) => ({...r, [uid]: 1 + (r[uid] || 0)}), {});
debug('channelUserCounts: reduced(%O)', reduced);
return reduced; return reduced;
}; };
export const channelUsers = async (req, channel) => { export const channelUsers = async (req, channel) => {
const userCounts = await channelUserCounts(req, channel); const userCounts = await channelUserCounts(req, channel);
debug('channelUsers: userCounts(%O)', userCounts);
const parsed = Object.keys(userCounts).map((id) => parseInt(id, 10)); const parsed = Object.keys(userCounts).map((id) => parseInt(id, 10));
debug('channelUsers: parsed(%O)', parsed);
return parsed; return parsed;
}; };
export const channelState = async (req, latus, channel) => { export const channelState = async (req, latus, channel) => {
debug('channelState');
const {name, type} = channel; const {name, type} = channel;
const redisClient = createClient(latus); const redisClient = createClient(latus);
const mget = promisify(redisClient.mget.bind(redisClient)); const mget = promisify(redisClient.mget.bind(redisClient));
const realName = 'r' === type const realName = 'r' === type
? name ? name
: `${[name, req.user.redditUsername].sort().join('$')}`; : `${[name, req.user.redditUsername].sort().join('$')}`;
const messagesKey = `${renderChannel({type, name: realName})}:messages:*`; const pattern = `${renderChannel({type, name: realName})}:messages:*`;
const messageKeys = await keys(redisClient, messagesKey); const messageKeys = await keys(redisClient, pattern);
const messages = 0 === messageKeys.length const messages = 0 === messageKeys.length
? [] ? []
: (await mget(messageKeys)) : (await mget(messageKeys))
@ -53,19 +45,19 @@ export const channelState = async (req, latus, channel) => {
})) }))
.filter(({message}) => !!message) .filter(({message}) => !!message)
.sort((l, r) => l.timestamp - r.timestamp); .sort((l, r) => l.timestamp - r.timestamp);
const users = new Set(await channelUsers(req, channel)); const users = channelIsAnonymous(channel)
users.add(channelIsAnonymous(channel) ? 0 : req.userId); ? [0]
: Array.from((new Set(await channelUsers(req, channel))).values());
return { return {
messages, messages,
users: Array.from(users.values()), users,
}; };
}; };
export const channelsToHydrate = async (req, latus) => { export const channelsToHydrate = async (req, latus) => {
debug('channelsToHydrate');
const {channel, user} = req; const {channel, user} = req;
if (!user) { if (!user && channel) {
return channel ? [channel] : []; return channelIsAnonymous(channel) ? [channel] : [];
} }
const {User} = ModelMap(latus); const {User} = ModelMap(latus);
const channels = await Promise.all( const channels = await Promise.all(
@ -79,13 +71,15 @@ export const channelsToHydrate = async (req, latus) => {
}), }),
))), ))),
); );
return Promise.all(Array.from((new Set(channels.map(renderChannel))).values()) // eslint-disable-next-line max-len
return (await Promise.all(Array.from((new Set(channels.map(renderChannel))).values())
.map(parseChannel) .map(parseChannel)
.filter((channel) => !user.isBannedFrom(channel))); .map(async (channel) => [await user.isBannedFrom(channel), channel])))
.filter(([isBanned]) => !isBanned)
.map(([, channel]) => channel);
}; };
export const chatUserIds = async (req, latus) => { export const chatUserIds = async (req, latus) => {
debug('chatUserIds');
const toHydrate = await channelsToHydrate(req, latus); const toHydrate = await channelsToHydrate(req, latus);
if (0 === toHydrate.length) { if (0 === toHydrate.length) {
return []; return [];
@ -103,9 +97,7 @@ export const chatUserIds = async (req, latus) => {
}; };
export default async (req, latus) => { export default async (req, latus) => {
debug('default state: url(%s), headers(%O)', req.url, req.headers);
const toHydrate = await channelsToHydrate(req, latus); const toHydrate = await channelsToHydrate(req, latus);
debug('default state: toHydrate(%O)', toHydrate);
const chat = { const chat = {
channels: {}, channels: {},
input: {}, input: {},
@ -117,7 +109,6 @@ export default async (req, latus) => {
const entries = await Promise.all( const entries = await Promise.all(
toHydrate.map((favorite) => channelState(req, latus, favorite)), toHydrate.map((favorite) => channelState(req, latus, favorite)),
); );
debug('default state: entries(%O)', entries);
for (let i = 0; i < toHydrate.length; i++) { for (let i = 0; i < toHydrate.length; i++) {
const channel = renderChannel(toHydrate[i]); const channel = renderChannel(toHydrate[i]);
const {messages, users} = entries[i]; const {messages, users} = entries[i];
@ -129,6 +120,5 @@ export default async (req, latus) => {
chat.messages[message.uuid] = message; chat.messages[message.uuid] = message;
}); });
} }
debug('default state(%O)', chat);
return chat; return chat;
}; };