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,
confirmMessage,
join,
joined,
leave,
rejectMessage,
submitJoin,
@ -38,7 +37,7 @@ import {
unblock,
} from '../../common/state/user';
import {
fetchUsernames,
setUsernames,
usernamesSelector,
} 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 effects = {
[addFriendship]: ({dispatch}, {payload: {addeeId, adderId}}) => {
dispatch(fetchUsernames([addeeId, adderId]));
},
[confirmFriendship]: ({dispatch, getState}, {payload: {addeeId, adderId}}) => {
const state = getState();
const id = idSelector(state);
@ -58,15 +54,6 @@ const effects = {
const name = usernamesSelector(state)[otherId];
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}) => {
dispatch(addToFavorites(payload));
socket.send(new AddFavorite(payload));
@ -75,7 +62,7 @@ const effects = {
const state = getState();
const userId = idSelector(state);
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) {
return;
}
@ -85,6 +72,7 @@ const effects = {
...(hasFriendship ? payload : {}),
status: hasFriendship ? 'active' : 'pending',
}));
dispatch(setUsernames({[id]: name}));
});
},
[submitBlock]: ({dispatch}, {payload: id}) => {

View File

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

View File

@ -1,12 +1,12 @@
import {
createAsyncThunk,
createSelector,
createSlice,
} from '@reduxjs/toolkit';
import Usernames from '~/common/packets/usernames.packet';
import {socket} from '~/client/hooks/useSocket';
import {
join,
joined,
} from '~/common/state/chat';
import hydration from './hydration';
@ -17,49 +17,22 @@ export const usernameSelector = createSelector(
(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 */
const slice = createSlice({
name: 'usernames',
initialState: hydration('usernames') || {},
extraReducers: {
[fetchUsernames.fulfilled]: (state, {payload}) => {
payload.forEach(([id, name]) => {
state[id] = name;
});
},
[join]: (state, {payload: {usernames}}) => ({...state, ...usernames}),
[joined]: (state, {payload: {id, name}}) => ({...state, [id]: name}),
},
reducers: {
setUsernames: (state, {payload}) => ({...state, ...payload}),
},
});
/* eslint-enable no-param-reassign */
export const {
addFriend,
blockUser,
removeFriend,
setUsernames,
} = slice.actions;
export default slice.reducer;

View File

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

View File

@ -10,14 +10,16 @@ import {
channelState,
channelUsers,
} from '~/server/entry';
import {allModels} from '~/server/models/registrar';
import ValidationError from './validation-error';
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);
if (-1 === users.indexOf(userId)) {
ServerSocket.send(socket.to(channel), new Join({channel, id: userId}));
if (-1 === users.indexOf(id)) {
ServerSocket.send(socket.to(channel), new Join({channel, id, name}));
}
await promisify(socket.join.bind(socket))(channel);
};
@ -31,7 +33,12 @@ export default {
},
responder: async ({data: {channel}}, socket) => {
const {req} = socket;
const {User} = allModels();
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}))};
},
};