diff --git a/src/modules/room/RoomChatForm.tsx b/src/modules/room/RoomChatForm.tsx index c279494..7b31a94 100644 --- a/src/modules/room/RoomChatForm.tsx +++ b/src/modules/room/RoomChatForm.tsx @@ -2,7 +2,7 @@ import { FC } from "react"; import { Form, Field } from "react-final-form"; import { useDispatch } from "react-redux"; -import { roomMessage } from "modules/room/slice"; +import { roomSendMessage } from "modules/room/slice"; interface Props { roomName: string; @@ -18,7 +18,7 @@ const RoomChatForm: FC = ({ roomName, loginUserName }) => { const onSubmit = ({ message }: Fields, form: any) => { dispatch( - roomMessage({ + roomSendMessage({ roomName, userName: loginUserName, message, diff --git a/src/modules/room/message.ts b/src/modules/room/message.ts index eb97709..01d85c6 100644 --- a/src/modules/room/message.ts +++ b/src/modules/room/message.ts @@ -1,53 +1,107 @@ import { AppDispatch } from "app/store"; -import { roomMessage, roomGetAll, roomSetAll } from "modules/room/slice"; +import { + RoomMembership, + RoomMessagePayload, + RoomState, + roomReceiveMessage, + roomSendMessage, + roomGetAll, + roomSetAll, +} from "modules/room/slice"; import { SocketMessage, SocketMessageMiddleware } from "modules/socket/message"; function roomListRequest(): SocketMessage { return "RoomListRequest"; } -// TODO: Adapt to new response format. -function handleRoomListResponse(dispatch: AppDispatch, outerFields: any[]) { - if (outerFields.length !== 1) { - console.log("RoomListResponse has wrong number of fields:", outerFields); - return; +function roomMessageRequest({ roomName, message }: RoomMessagePayload) { + return { + RoomMessageRequest: { + room_name: roomName, + message, + }, + }; +} + +function convertMembership(membership: string): RoomMembership { + switch (membership) { + case "NonMember": + return RoomMembership.Left; + case "Joining": + return RoomMembership.Joining; + case "Member": + return RoomMembership.Joined; + case "Leaving": + return RoomMembership.Leaving; } +} - const { rooms } = outerFields[0]; - if (rooms === undefined) { - console.log("RoomListResponse field has wrong shape:", outerFields[0]); - return; +function convertMessages(messages: any[]): RoomMessage[] { + const result = []; + for (const message of messages) { + result.push({ + userName: message.user_name, + message: message.message, + }); } + return result; +} - dispatch(roomSetAll(rooms)); +function convertRoomListEntry(name: string, room: any): RoomState { + return { + name, + membership: convertMembership(room.membership), + visibility: room.visibility, + operated: room.operated, + userCount: room.user_count, + owner: room.owner, + operators: room.operators, + members: room.members, + messages: convertMessages(room.messages), + tickers: room.tickers, + }; } -// TODO: Adapt to new response format. -function handleRoomMessageResponse(dispatch: AppDispatch, outerFields: any[]) { - if (outerFields.length !== 1) { - console.log("RoomMessageResponse has wrong number of fields:", outerFields); +function handleRoomListResponse(dispatch: AppDispatch, response) { + const { rooms } = response; + if (rooms === undefined) { + console.log("RoomListResponse has wrong shape:", response); return; } - dispatch(roomMessage(outerFields[0])); + const map = {}; + for (const [name, room] of rooms) { + map[name] = convertRoomListEntry(name, room); + } + + dispatch(roomSetAll(map)); +} + +function handleRoomMessageResponse(dispatch: AppDispatch, response) { + dispatch( + roomReceiveMessage({ + roomName: response.room_name, + userName: response.user_name, + message: response.message, + }) + ); } export const roomSocketMessageMiddleware: SocketMessageMiddleware = { // TODO: Adapt to new response format. - handleMessage: (dispatch, { variant, fields }) => { - switch (variant) { - case "RoomListResponse": - handleRoomListResponse(dispatch, fields); - break; - case "RoomMessageResponse": - handleRoomMessageResponse(dispatch, fields); - break; + handleMessage: (dispatch, message) => { + if ("RoomListResponse" in message) { + handleRoomListResponse(dispatch, message["RoomListResponse"]); + } else if ("RoomMessageResponse" in message) { + handleRoomMessageResponse(dispatch, message["RoomMessageResponse"]); } }, handleAction: (send, action) => { if (roomGetAll.match(action)) { send(roomListRequest()); + } else if (roomSendMessage.match(action)) { + send(roomMessageRequest(action.payload)); } }, }; diff --git a/src/modules/room/slice.ts b/src/modules/room/slice.ts index 267595e..63cd3d9 100644 --- a/src/modules/room/slice.ts +++ b/src/modules/room/slice.ts @@ -24,7 +24,7 @@ export interface RoomState { operators: string[]; members: string[]; messages: RoomMessage[]; - tickers: string[]; + tickers: [string, string][]; // showUsers: boolean; } @@ -99,7 +99,7 @@ export const roomSlice = createSlice({ room.membership = membership; }, - roomMessage: ( + roomReceiveMessage: ( state: RoomSliceState, action: PayloadAction ) => { @@ -115,6 +115,21 @@ export const roomSlice = createSlice({ room.messages.push({ userName, message }); }, + roomSendMessage: ( + state: RoomSliceState, + action: PayloadAction + ) => { + const { roomName, userName, message } = action.payload; + const room = state.rooms[roomName]; + if (room === undefined) { + console.log( + `Cannot send message to unknown room ${roomName}: ${message}` + ); + return; + } + + room.messages.push({ userName, message }); + }, roomSetAll: (state: RoomSliceState, action: PayloadAction) => { state.rooms = {}; for (const room of action.payload) { @@ -125,8 +140,13 @@ export const roomSlice = createSlice({ }, }); -export const { roomSetMembership, roomMessage, roomGetAll, roomSetAll } = - roomSlice.actions; +export const { + roomSetMembership, + roomReceiveMessage, + roomSendMessage, + roomGetAll, + roomSetAll, +} = roomSlice.actions; export function selectAllRooms(state: RootState): RoomMap { return state.rooms.rooms; diff --git a/src/modules/socket/message.ts b/src/modules/socket/message.ts index 79da047..71694a3 100644 --- a/src/modules/socket/message.ts +++ b/src/modules/socket/message.ts @@ -5,10 +5,7 @@ import { PayloadAction } from "@reduxjs/toolkit"; import { AppDispatch } from "app/store"; // The type of a message exchanged over a websocket. -export interface SocketMessage { - variant: string; - fields: any[]; -} +export type SocketMessage = any; // Serializes the given message for sending over the wire. export function serializeMessage(message: SocketMessage): string { @@ -18,12 +15,7 @@ export function serializeMessage(message: SocketMessage): string { // Attempts to parse a message out of the given data. // Throws an error if unsuccessful. export function parseMessage(serialized: string): SocketMessage { - const { variant, fields } = JSON.parse(serialized); - if (typeof variant === "undefined") { - throw new Error('Missing "variant" field in socket message'); - } - - return { variant, fields }; + return JSON.parse(serialized); } // An interface passed to socket message middleware, used to send messages.