refactor: no username roundtrips

This commit is contained in:
cha0s 2020-07-25 11:18:25 -05:00
parent ba5e3c71a6
commit 291847cf95
5 changed files with 29 additions and 57 deletions

View File

@ -14,7 +14,6 @@ import {
addMessage, addMessage,
confirmMessage, confirmMessage,
join, join,
joined,
leave, leave,
rejectMessage, rejectMessage,
submitJoin, submitJoin,
@ -38,7 +37,7 @@ import {
unblock, unblock,
} from '../../common/state/user'; } from '../../common/state/user';
import { import {
fetchUsernames, setUsernames,
usernamesSelector, usernamesSelector,
} from '~/common/state/usernames'; } from '~/common/state/usernames';
@ -48,9 +47,6 @@ const characterLimiter = new RateLimiterMemory({points: 2048, duration: 2});
const messageLimiter = new RateLimiterMemory({points: 10, duration: 15}); const messageLimiter = new RateLimiterMemory({points: 10, duration: 15});
const effects = { const effects = {
[addFriendship]: ({dispatch}, {payload: {addeeId, adderId}}) => {
dispatch(fetchUsernames([addeeId, adderId]));
},
[confirmFriendship]: ({dispatch, getState}, {payload: {addeeId, adderId}}) => { [confirmFriendship]: ({dispatch, getState}, {payload: {addeeId, adderId}}) => {
const state = getState(); const state = getState();
const id = idSelector(state); const id = idSelector(state);
@ -58,15 +54,6 @@ const effects = {
const name = usernamesSelector(state)[otherId]; const name = usernamesSelector(state)[otherId];
dispatch(submitJoin({channel: `/u/${name}`, id})); dispatch(submitJoin({channel: `/u/${name}`, id}));
}, },
[join]: ({dispatch}, {payload: {messages, users}}) => {
const ids = new Set();
Object.values(messages).map((message) => message.owner).forEach((id) => ids.add(id));
users.forEach((id) => ids.add(id));
dispatch(fetchUsernames(Array.from(ids.keys())));
},
[joined]: ({dispatch}, {payload: {id}}) => {
dispatch(fetchUsernames([id]));
},
[submitAddFavorite]: ({dispatch}, {payload}) => { [submitAddFavorite]: ({dispatch}, {payload}) => {
dispatch(addToFavorites(payload)); dispatch(addToFavorites(payload));
socket.send(new AddFavorite(payload)); socket.send(new AddFavorite(payload));
@ -75,7 +62,7 @@ const effects = {
const state = getState(); const state = getState();
const userId = idSelector(state); const userId = idSelector(state);
const hasFriendship = !!payload.addeeId; const hasFriendship = !!payload.addeeId;
socket.send(new AddFriend({nameOrStatus: payload.nameOrStatus}), (error, id) => { socket.send(new AddFriend({nameOrStatus: payload.nameOrStatus}), (error, {id, name}) => {
if (error) { if (error) {
return; return;
} }
@ -85,6 +72,7 @@ const effects = {
...(hasFriendship ? payload : {}), ...(hasFriendship ? payload : {}),
status: hasFriendship ? 'active' : 'pending', status: hasFriendship ? 'active' : 'pending',
})); }));
dispatch(setUsernames({[id]: name}));
}); });
}, },
[submitBlock]: ({dispatch}, {payload: id}) => { [submitBlock]: ({dispatch}, {payload: id}) => {

View File

@ -8,6 +8,7 @@ export default class Join extends Packet {
data: { data: {
id: 'uint32', id: 'uint32',
channel: 'string', channel: 'string',
name: 'string',
}, },
}; };
} }

View File

@ -1,12 +1,12 @@
import { import {
createAsyncThunk,
createSelector, createSelector,
createSlice, createSlice,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import Usernames from '~/common/packets/usernames.packet'; import {
join,
import {socket} from '~/client/hooks/useSocket'; joined,
} from '~/common/state/chat';
import hydration from './hydration'; import hydration from './hydration';
@ -17,49 +17,22 @@ export const usernameSelector = createSelector(
(usernames, id) => usernames[id], (usernames, id) => usernames[id],
); );
export const fetchUsernames = createAsyncThunk(
'usernames/fetchUsernames',
async (ids, {getState}) => {
const usernames = usernamesSelector(getState());
const hasAnonymous = -1 !== ids.indexOf(0);
const missingIds = ids.filter((id) => 0 !== id && !usernames[id]);
if (0 === missingIds.length) {
return hasAnonymous ? [[0, 'anonymous']] : [];
}
return new Promise((resolve, reject) => (
socket.send(new Usernames(missingIds), (error, usernames) => {
if (error) {
reject(error);
return;
}
resolve(
missingIds
.map((id, i) => [id, usernames[i]])
.concat(hasAnonymous ? [[0, 'anonymous']] : []),
);
})
));
},
);
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
const slice = createSlice({ const slice = createSlice({
name: 'usernames', name: 'usernames',
initialState: hydration('usernames') || {}, initialState: hydration('usernames') || {},
extraReducers: { extraReducers: {
[fetchUsernames.fulfilled]: (state, {payload}) => { [join]: (state, {payload: {usernames}}) => ({...state, ...usernames}),
payload.forEach(([id, name]) => { [joined]: (state, {payload: {id, name}}) => ({...state, [id]: name}),
state[id] = name;
});
}, },
reducers: {
setUsernames: (state, {payload}) => ({...state, ...payload}),
}, },
}); });
/* eslint-enable no-param-reassign */ /* eslint-enable no-param-reassign */
export const { export const {
addFriend, setUsernames,
blockUser,
removeFriend,
} = slice.actions; } = slice.actions;
export default slice.reducer; export default slice.reducer;

View File

@ -41,6 +41,9 @@ export default {
nameOrStatus: friendship.status, nameOrStatus: friendship.status,
})); }));
}); });
return addeeId; return {
id: addeeId,
name: user.redditUsername,
};
}, },
}; };

View File

@ -10,14 +10,16 @@ import {
channelState, channelState,
channelUsers, channelUsers,
} from '~/server/entry'; } from '~/server/entry';
import {allModels} from '~/server/models/registrar';
import ValidationError from './validation-error'; import ValidationError from './validation-error';
export const userJoin = async (channel, socket) => { export const userJoin = async (channel, socket) => {
const userId = '/r/anonymous' === channel ? 0 : socket.handshake.userId; const id = '/r/anonymous' === channel ? 0 : socket.handshake.userId;
const name = '/r/anonymous' === channel ? 'anonymous' : socket.handshake.user.redditUsername;
const users = await channelUsers(socket.handshake, channel); const users = await channelUsers(socket.handshake, channel);
if (-1 === users.indexOf(userId)) { if (-1 === users.indexOf(id)) {
ServerSocket.send(socket.to(channel), new Join({channel, id: userId})); ServerSocket.send(socket.to(channel), new Join({channel, id, name}));
} }
await promisify(socket.join.bind(socket))(channel); await promisify(socket.join.bind(socket))(channel);
}; };
@ -31,7 +33,12 @@ export default {
}, },
responder: async ({data: {channel}}, socket) => { responder: async ({data: {channel}}, socket) => {
const {req} = socket; const {req} = socket;
const {User} = allModels();
await userJoin(channel, socket.socket); await userJoin(channel, socket.socket);
return channelState(req, channel); const state = channelState(req, channel);
const entries = await Promise.all(
state.users.map(async (id) => [id, (await User.findByPk(id)).redditUsername]),
);
return {...state, usernames: entries.reduce((r, [id, name]) => ({...r, [id]: name}))};
}, },
}; };