cleaning a bunch and adding in the right handlers for sockets much cleaner
This commit is contained in:
+62
-61
@@ -1,24 +1,21 @@
|
||||
import { JwtClaims, authCheck } from "../middleware/auth";
|
||||
import {
|
||||
Line,
|
||||
LineMember,
|
||||
LineMemberState,
|
||||
} from "@nirvana/core/models/line.model";
|
||||
import express, { Application, Request, Response } from "express";
|
||||
import { JwtClaims, authCheck } from '../middleware/auth';
|
||||
import { Line, LineMember, LineMemberState } from '@nirvana/core/models/line.model';
|
||||
import express, { Application, Request, Response } from 'express';
|
||||
|
||||
import Content from "@nirvana/core/models/content.model";
|
||||
import CreateLineRequest from "@nirvana/core/requests/createLine.request";
|
||||
import GetConversationDetailsResponse from "@nirvana/core/responses/getConversationDetails.response";
|
||||
import GetDmConversationByOtherUserIdResponse from "@nirvana/core/responses/getDmConversationByOtherUserId.response";
|
||||
import GetUserLinesResponse from "@nirvana/core/responses/getUserLines.response";
|
||||
import { LineService } from "../services/line.service";
|
||||
import MasterLineData from "@nirvana/core/models/masterLineData.model";
|
||||
import NirvanaResponse from "../../core/responses/nirvanaResponse";
|
||||
import { ObjectId } from "mongodb";
|
||||
import Relationship from "@nirvana/core/models/relationship.model";
|
||||
import { User } from "@nirvana/core/models/user.model";
|
||||
import { UserService } from "../services/user.service";
|
||||
import { collections } from "../services/database.service";
|
||||
import Content from '@nirvana/core/models/content.model';
|
||||
import CreateLineRequest from '@nirvana/core/requests/createLine.request';
|
||||
import GetConversationDetailsResponse from '@nirvana/core/responses/getConversationDetails.response';
|
||||
import GetDmConversationByOtherUserIdResponse from '@nirvana/core/responses/getDmConversationByOtherUserId.response';
|
||||
import GetUserLinesResponse from '@nirvana/core/responses/getUserLines.response';
|
||||
import { LineService } from '../services/line.service';
|
||||
import MasterLineData from '@nirvana/core/models/masterLineData.model';
|
||||
import NirvanaResponse from '@nirvana/core/responses/nirvanaResponse';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import Relationship from '@nirvana/core/models/relationship.model';
|
||||
import { User } from '@nirvana/core/models/user.model';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { collections } from '../services/database.service';
|
||||
import UpdateLineMemberState from '@nirvana/core/requests/updateLineMemberState.request';
|
||||
|
||||
export default function getLineRoutes() {
|
||||
const router = express.Router();
|
||||
@@ -29,13 +26,16 @@ export default function getLineRoutes() {
|
||||
// router.get("/:otherUserGoogleUserId", authCheck, getConversationDetails);
|
||||
|
||||
// create a line
|
||||
router.post("/", authCheck, createLine);
|
||||
router.post('/', authCheck, createLine);
|
||||
|
||||
// get all of user's lines
|
||||
router.get("/", authCheck, getUserLines);
|
||||
router.get('/', authCheck, getUserLines);
|
||||
|
||||
// toggle tune into a line
|
||||
router.post('/:lineId/state', authCheck, updateLineMemberState);
|
||||
|
||||
// get conversation between user and other user
|
||||
router.get("/dm/:otherUserId", authCheck, getDmByOtherUserId);
|
||||
router.get('/dm/:otherUserId', authCheck, getDmByOtherUserId);
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ async function getDmByOtherUserId(req: Request, res: Response) {
|
||||
res.status(200).json();
|
||||
return;
|
||||
|
||||
res.status(205).json("no such conversation between you two");
|
||||
res.status(205).json('no such conversation between you two');
|
||||
} catch (error) {
|
||||
res.status(500).json(error);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ async function createLine(req: Request, res: Response) {
|
||||
console.log(req.body);
|
||||
|
||||
if (!reqObj?.otherMemberIds.length) {
|
||||
res.status(400).json("must provide member Ids");
|
||||
res.status(400).json('must provide member Ids');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ async function createLine(req: Request, res: Response) {
|
||||
reqObj.lineName ?? undefined,
|
||||
new Date(),
|
||||
new Date(),
|
||||
new ObjectId()
|
||||
new ObjectId(),
|
||||
);
|
||||
|
||||
// TODO: validate that users exists before creating line members
|
||||
@@ -86,67 +86,74 @@ async function createLine(req: Request, res: Response) {
|
||||
const newLineMember = new LineMember(
|
||||
newLine._id!,
|
||||
new ObjectId(memId),
|
||||
LineMemberState.INBOX
|
||||
LineMemberState.INBOX,
|
||||
);
|
||||
|
||||
return newLineMember;
|
||||
}) ?? [];
|
||||
|
||||
lineMembers.push(
|
||||
new LineMember(
|
||||
newLine._id!,
|
||||
new ObjectId(userInfo.userId),
|
||||
LineMemberState.INBOX
|
||||
)
|
||||
new LineMember(newLine._id!, new ObjectId(userInfo.userId), LineMemberState.INBOX),
|
||||
);
|
||||
|
||||
const transactionResult = await LineService.createLine(
|
||||
newLine,
|
||||
lineMembers
|
||||
);
|
||||
const transactionResult = await LineService.createLine(newLine, lineMembers);
|
||||
|
||||
transactionResult
|
||||
? res.status(200).json(new NirvanaResponse(newLine))
|
||||
: res
|
||||
.status(400)
|
||||
.json(
|
||||
new NirvanaResponse(undefined, new Error("unable to create line"))
|
||||
);
|
||||
: res.status(400).json(new NirvanaResponse(undefined, new Error('unable to create line')));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(500).json(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLineMemberState(req: Request, res: Response) {
|
||||
try {
|
||||
const userInfo = res.locals.userInfo as JwtClaims;
|
||||
const { lineId } = req.params;
|
||||
const request = req.body as UpdateLineMemberState;
|
||||
|
||||
// TODO: validation to check if user is actually a member of the line
|
||||
|
||||
const result = await LineService.updateLineMemberState(
|
||||
lineId,
|
||||
userInfo.userId,
|
||||
request.newState,
|
||||
);
|
||||
|
||||
return result?.ok
|
||||
? res.status(200).json(new NirvanaResponse("successfully updated line member's state"))
|
||||
: res
|
||||
.status(400)
|
||||
.json(new NirvanaResponse(undefined, new Error('not updated...something went wrong')));
|
||||
} catch (error) {
|
||||
res.status(500).json(new NirvanaResponse(undefined, error as Error));
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserLines(req: Request, res: Response) {
|
||||
try {
|
||||
const userInfo = res.locals.userInfo as JwtClaims;
|
||||
|
||||
// get all of user's lineMember entries
|
||||
const userLineMembers = await LineService.getLineMembersByUserId(
|
||||
userInfo.userId
|
||||
);
|
||||
const userLineMembers = await LineService.getLineMembersByUserId(userInfo.userId);
|
||||
|
||||
if (!userLineMembers?.length) {
|
||||
const resObj = new GetUserLinesResponse([]);
|
||||
|
||||
res.json(
|
||||
new NirvanaResponse(resObj, undefined, "this user is not in any lines")
|
||||
);
|
||||
res.json(new NirvanaResponse(resObj, undefined, 'this user is not in any lines'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const lineIds =
|
||||
userLineMembers?.map((lineMember) => lineMember.lineId) ?? [];
|
||||
const lineIds = userLineMembers?.map((lineMember) => lineMember.lineId) ?? [];
|
||||
|
||||
// this will include the current user lineMember association to the line
|
||||
const allLineMembers = await LineService.getLineMembersInLines(lineIds);
|
||||
|
||||
const allLinesUsersIds: ObjectId[] = [];
|
||||
allLineMembers?.map((currentLineMember) => {
|
||||
if (currentLineMember?.userId)
|
||||
allLinesUsersIds.push(currentLineMember.userId);
|
||||
if (currentLineMember?.userId) allLinesUsersIds.push(currentLineMember.userId);
|
||||
}) ?? [];
|
||||
|
||||
// get all users relevant here
|
||||
@@ -174,34 +181,28 @@ async function getUserLines(req: Request, res: Response) {
|
||||
// get the user lineMember assoc out of the list of the lineMembers for this line
|
||||
const userLineMember = associatedLineMembersForLine?.find(
|
||||
(currentLineMemberForLine) =>
|
||||
currentLineMemberForLine.userId.toString() === userInfo.userId
|
||||
currentLineMemberForLine.userId.toString() === userInfo.userId,
|
||||
);
|
||||
|
||||
if (userLineMember) {
|
||||
// take out the current user from the "other" line members list now
|
||||
|
||||
associatedLineMembersForLine = associatedLineMembersForLine.filter(
|
||||
(currentLineMember) =>
|
||||
currentLineMember.userId.toString() !== userInfo.userId
|
||||
(currentLineMember) => currentLineMember.userId.toString() !== userInfo.userId,
|
||||
);
|
||||
|
||||
// get the user objects for all of the other members
|
||||
const otherUsers: User[] = [];
|
||||
associatedLineMembersForLine.forEach((currentLineMember) => {
|
||||
const foundUserObject = allRelevantUsers?.find((currentUser) =>
|
||||
currentUser._id?.equals(currentLineMember.userId)
|
||||
currentUser._id?.equals(currentLineMember.userId),
|
||||
);
|
||||
|
||||
if (foundUserObject) otherUsers.push(foundUserObject);
|
||||
});
|
||||
|
||||
masterLines.push(
|
||||
new MasterLineData(
|
||||
currentLine,
|
||||
userLineMember,
|
||||
associatedLineMembersForLine,
|
||||
otherUsers
|
||||
)
|
||||
new MasterLineData(currentLine, userLineMember, associatedLineMembersForLine, otherUsers),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
+16
-114
@@ -7,6 +7,7 @@ import {
|
||||
ServerRequestChannels,
|
||||
ServerResponseChannels,
|
||||
SomeoneConnectedResponse,
|
||||
SomeoneDisconnectedResponse,
|
||||
SomeoneTunedResponse,
|
||||
SomeoneUntunedFromLineResponse,
|
||||
StartBroadcastingRequest,
|
||||
@@ -84,23 +85,12 @@ export default function InitializeWs(io: any) {
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
socket.join(roomName);
|
||||
|
||||
console.log(`${socket.id} now in rooms ${socket.rooms}`);
|
||||
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map(
|
||||
(otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId],
|
||||
);
|
||||
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE,
|
||||
new SomeoneConnectedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
new SomeoneConnectedResponse(req.lineId, userInfo.userId),
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* TODO: handle when user wants to completely leave a line (delete or removed from one)
|
||||
*/
|
||||
socket.on(ServerRequestChannels.DISCONNECT_FROM_LINE, () => console.log('not implemented'));
|
||||
|
||||
/** TUNE | User tunes into the line either temporarily or toggled in */
|
||||
socket.on(ServerRequestChannels.TUNE_INTO_LINE, async (req: TuneToLineRequest) => {
|
||||
console.log(`${socket.id} user TUNED into room for line ${req.lineId}`);
|
||||
@@ -108,38 +98,12 @@ export default function InitializeWs(io: any) {
|
||||
const roomName = `tunedLine:${req.lineId}`;
|
||||
socket.join(roomName);
|
||||
|
||||
console.log(`${socket.id} now in rooms ${Object.keys(socket.rooms)}`);
|
||||
|
||||
// persist tuning in if user is toggle tuning in
|
||||
if (req.keepTunedIn) {
|
||||
await LineService.updateLineMemberState(
|
||||
req.lineId,
|
||||
userInfo.userId,
|
||||
LineMemberState.TUNED,
|
||||
);
|
||||
} else {
|
||||
await LineService.updateLineMemberState(
|
||||
req.lineId,
|
||||
userInfo.userId,
|
||||
LineMemberState.INBOX,
|
||||
);
|
||||
}
|
||||
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map(
|
||||
(otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId],
|
||||
);
|
||||
|
||||
// we want to notify everyone connected to the line even if they are not tuned in
|
||||
const connectedLineRoomName = `connectedLine:${req.lineId}`;
|
||||
|
||||
io.in(connectedLineRoomName).emit(
|
||||
ServerResponseChannels.SOMEONE_TUNED_INTO_LINE,
|
||||
new SomeoneTunedResponse(
|
||||
req.lineId,
|
||||
userInfo.userId,
|
||||
clientUserIdsInRoom,
|
||||
req.keepTunedIn,
|
||||
),
|
||||
new SomeoneTunedResponse(req.lineId, userInfo.userId),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -151,18 +115,14 @@ export default function InitializeWs(io: any) {
|
||||
const roomName = `tunedLine:${req.lineId}`;
|
||||
socket.leave(roomName);
|
||||
|
||||
console.log('someone left room');
|
||||
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map(
|
||||
(otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId],
|
||||
);
|
||||
console.log(`${userInfo.userId} left room: ${roomName}`);
|
||||
|
||||
// we want to notify everyone connected to the line even if they are not tuned in
|
||||
const connectedLineRoomName = `connectedLine:${req.lineId}`;
|
||||
|
||||
io.in(connectedLineRoomName).emit(
|
||||
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
|
||||
new SomeoneUntunedFromLineResponse(req.lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
new SomeoneUntunedFromLineResponse(req.lineId, userInfo.userId),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -186,21 +146,6 @@ export default function InitializeWs(io: any) {
|
||||
);
|
||||
});
|
||||
|
||||
// socket.on(SocketChannels.SEND_SIGNAL, async (payload: SendSignal) => {
|
||||
// console.log(payload);
|
||||
|
||||
// const sendingBackData: ReceiveSignal = {
|
||||
// simplePeerSignal: payload.simplePeerSignal,
|
||||
// senderUserSocketId: socket.id,
|
||||
// isGoingBackToInitiator: payload.isAnswerer ? true : false,
|
||||
// };
|
||||
|
||||
// io.to(payload.userSocketIdToSignal).emit(
|
||||
// SocketChannels.RECEIVE_SIGNAL,
|
||||
// sendingBackData
|
||||
// );
|
||||
// });
|
||||
|
||||
// tell the proper other user to create a local peer object for the one on one mesh connection
|
||||
socket.on(ServerRequestChannels.RTC_CALL_REQUEST, (req: RtcCallRequest) => {
|
||||
const userSocketId = userIdsToSocketIds[req.userIdToCall];
|
||||
@@ -220,58 +165,25 @@ export default function InitializeWs(io: any) {
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: not complete
|
||||
socket.on(ServerRequestChannels.GOING_INTO_FLOW_STATE, () => {
|
||||
// change user object to persist this state
|
||||
|
||||
// get all of the connectedLine rooms of this person, and tell them that user is going into flow state
|
||||
|
||||
for (const roomName of socket.rooms) {
|
||||
if (roomName !== socket.id) {
|
||||
const lineId = roomName.split(':')[1];
|
||||
if (roomName.includes('connectedLine')) {
|
||||
// get fresh list of tuned in folks without me
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])]
|
||||
.filter((mappedSocketId) => mappedSocketId !== socket.id)
|
||||
.map((otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]);
|
||||
|
||||
// io.in(roomName).emit(
|
||||
// ServerResponseChannels.SOMEONE_GOING_INTO_FLOW_STATE,
|
||||
// new SomeoneGoingIntoFlowState(
|
||||
|
||||
// userInfo.userId
|
||||
|
||||
// )
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// tell all connected people that I am disconnecting
|
||||
// tell tuned in folks that I am leaving the room
|
||||
// tell all people in all my lines that I am disconnecting or untuning
|
||||
// tell the tuned in folks the new list of
|
||||
socket.on('disconnecting', (reason: any) => {
|
||||
console.log(reason);
|
||||
console.log(`someone disconnecting: ${reason}`);
|
||||
|
||||
console.log(socket.rooms);
|
||||
|
||||
for (const roomName of socket.rooms) {
|
||||
if (roomName !== socket.id) {
|
||||
const lineId = roomName.split(':')[1];
|
||||
if (roomName.includes('tunedLine')) {
|
||||
// get fresh list of tuned in folks without me
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])]
|
||||
.filter((mappedSocketId) => mappedSocketId !== socket.id)
|
||||
.map((otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]);
|
||||
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
|
||||
new SomeoneUntunedFromLineResponse(lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
);
|
||||
} else if (roomName.includes('connectedLine')) {
|
||||
//TODO: p3: client doesn't really to know right now in our flow as this list is not really used
|
||||
// io.in(roomName).emit(ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE, new SomeoneDisconnected(lineId, userInfo.userId, clientUserIdsInRoom));
|
||||
}
|
||||
const roomToTell = roomName.includes('tunedLine')
|
||||
? `connectedLine:${lineId}`
|
||||
: roomName;
|
||||
|
||||
io.in(roomToTell).emit(
|
||||
ServerResponseChannels.SOMEONE_DISCONNECTED_FROM_LINE,
|
||||
new SomeoneDisconnectedResponse(lineId, userInfo.userId),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -280,16 +192,6 @@ export default function InitializeWs(io: any) {
|
||||
socket.on('disconnect', () => {
|
||||
delete socketIdsToUserIds[socket.id];
|
||||
delete userIdsToSocketIds[userInfo.userId];
|
||||
|
||||
// get all of the rooms of this socket
|
||||
// notify everyone of this disconnection
|
||||
|
||||
console.log('user disconnected');
|
||||
console.log(`list of sockets mappings in memory: ${socketIdsToUserIds}`);
|
||||
|
||||
console.log(socket.rooms);
|
||||
|
||||
// ! NOTIFY ALL CONNECTED LINES SO THAT THEY CAN REMOVE FROM THEIR SESSION CONNECTED USERS ARRAY AND TUNED IN ARRAY
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { LineMemberState } from '../models/line.model';
|
||||
export default class UpdateLineMemberState {
|
||||
constructor(public newState: LineMemberState) {}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { ObjectId } from "mongodb";
|
||||
import { RelationshipState } from "../models/relationship.model";
|
||||
|
||||
export default class UpdateRelationshipStateRequest {
|
||||
constructor(
|
||||
public relationshipId: ObjectId,
|
||||
public newState: RelationshipState
|
||||
) {}
|
||||
}
|
||||
@@ -1,68 +1,68 @@
|
||||
// ! NOTE: these are legacy and too much thinking in the developers head to understand the flow
|
||||
enum SocketChannels {
|
||||
SEND_AUDIO_CLIP = "SEND_AUDIO_CLIP",
|
||||
SEND_USER_STATUS_UPDATE = "SEND_USER_STATUS_UPDATE",
|
||||
SEND_AUDIO_CLIP = 'SEND_AUDIO_CLIP',
|
||||
SEND_USER_STATUS_UPDATE = 'SEND_USER_STATUS_UPDATE',
|
||||
|
||||
SEND_STARTED_SPEAKING = "SEND_STARTED_SPEAKING",
|
||||
SEND_STOPPED_SPEAKING = "SEND_STOPPED_SPEAKING",
|
||||
SEND_STARTED_SPEAKING = 'SEND_STARTED_SPEAKING',
|
||||
SEND_STOPPED_SPEAKING = 'SEND_STOPPED_SPEAKING',
|
||||
|
||||
JOIN_LIVE_ROOM = "JOIN_LIVE_ROOM",
|
||||
GET_ALL_ACTIVE_SOCKET_IDS = "GET_ALL_ACTIVE_SOCKET_IDS",
|
||||
JOIN_LIVE_ROOM = 'JOIN_LIVE_ROOM',
|
||||
GET_ALL_ACTIVE_SOCKET_IDS = 'GET_ALL_ACTIVE_SOCKET_IDS',
|
||||
|
||||
SEND_SIGNAL = "SEND_SIGNAL",
|
||||
SEND_SIGNAL = 'SEND_SIGNAL',
|
||||
|
||||
RECEIVE_SIGNAL = "RECEIVE_SIGNAL",
|
||||
RECEIVE_SIGNAL = 'RECEIVE_SIGNAL',
|
||||
|
||||
// v3
|
||||
|
||||
/**
|
||||
* when someone connects to a line, whether tuned in or not
|
||||
*/
|
||||
CONNECT_TO_LINE = "CONNECT_TO_LINE",
|
||||
SOMEONE_CONNECTED_TO_LINE = "SOMEONE_CONNECTED_TO_LINE",
|
||||
CONNECT_TO_LINE = 'CONNECT_TO_LINE',
|
||||
SOMEONE_CONNECTED_TO_LINE = 'SOMEONE_CONNECTED_TO_LINE',
|
||||
|
||||
TUNE_TO_LINE = "TUNE_TO_LINE",
|
||||
SOMEONE_TUNED_TO_LINE = "SOMEONE_TUNED_TO_LINE",
|
||||
TUNE_TO_LINE = 'TUNE_TO_LINE',
|
||||
SOMEONE_TUNED_TO_LINE = 'SOMEONE_TUNED_TO_LINE',
|
||||
|
||||
SOMEONE_UNTUNED_FROM_LINE = "SOMEONE_UNTUNED_FROM_LINE",
|
||||
SOMEONE_UNTUNED_FROM_LINE = 'SOMEONE_UNTUNED_FROM_LINE',
|
||||
|
||||
USER_BROADCAST_PUSH_PULL = "USER_BROADCAST_PUSH_PULL",
|
||||
USER_BROADCAST_PUSH_PULL = 'USER_BROADCAST_PUSH_PULL',
|
||||
}
|
||||
|
||||
// ! MAKE SURE THAT THE ENUMS BETWEEN REQUEST AND RESPONSE DON'T OVERLAP???
|
||||
// ?maybe won't matter since it's different for server and client?
|
||||
export enum ServerRequestChannels {
|
||||
CONNECT_TO_LINE = "CONNECT_TO_LINE",
|
||||
CONNECT_TO_LINE = 'CONNECT_TO_LINE',
|
||||
|
||||
DISCONNECT_FROM_LINE = "DISCONNECT_FROM_LINE", // TODO: not implementing now
|
||||
DISCONNECT_FROM_LINE = 'DISCONNECT_FROM_LINE', // TODO: not implementing now
|
||||
|
||||
TUNE_INTO_LINE = "TUNE_INTO_LINE", // pass in if user wants to toggle/persist? or is this just temporary?
|
||||
UNTUNE_FROM_LINE = "UNTUNE_FROM_LINE",
|
||||
TUNE_INTO_LINE = 'TUNE_INTO_LINE', // pass in if user wants to toggle/persist? or is this just temporary?
|
||||
UNTUNE_FROM_LINE = 'UNTUNE_FROM_LINE',
|
||||
|
||||
BROADCAST_TO_LINE = "BROADCAST_TO_LINE",
|
||||
STOP_BROADCAST_TO_LINE = "STOP_BROADCAST_TO_LINE",
|
||||
BROADCAST_TO_LINE = 'BROADCAST_TO_LINE',
|
||||
STOP_BROADCAST_TO_LINE = 'STOP_BROADCAST_TO_LINE',
|
||||
|
||||
RTC_CALL_REQUEST = "RTC_CALL_PREFIX",
|
||||
RTC_ANSWER_REQUEST = "RTC_ANSWER_REQUEST_PREFIX",
|
||||
RTC_CALL_REQUEST = 'RTC_CALL_PREFIX',
|
||||
RTC_ANSWER_REQUEST = 'RTC_ANSWER_REQUEST_PREFIX',
|
||||
|
||||
GOING_INTO_FLOW_STATE = "GOING_INTO_FLOW_STATE",
|
||||
GOING_INTO_FLOW_STATE = 'GOING_INTO_FLOW_STATE',
|
||||
}
|
||||
|
||||
export enum ServerResponseChannels {
|
||||
SOMEONE_CONNECTED_TO_LINE = "SOMEONE_CONNECTED_TO_LINE",
|
||||
SOMEONE_DISCONNECTED_FROM_LINE = "SOMEONE_DISCONNECTED_FROM_LINE",
|
||||
SOMEONE_CONNECTED_TO_LINE = 'SOMEONE_CONNECTED_TO_LINE',
|
||||
SOMEONE_DISCONNECTED_FROM_LINE = 'SOMEONE_DISCONNECTED_FROM_LINE',
|
||||
|
||||
SOMEONE_TUNED_INTO_LINE = "SOMEONE_TUNED_INTO_LINE", // allows all current tuned in folks to create peer objects
|
||||
SOMEONE_UNTUNED_FROM_LINE = "SOMEONE_UNTUNED_FROM_LINE", // discard peer
|
||||
SOMEONE_TUNED_INTO_LINE = 'SOMEONE_TUNED_INTO_LINE', // allows all current tuned in folks to create peer objects
|
||||
SOMEONE_UNTUNED_FROM_LINE = 'SOMEONE_UNTUNED_FROM_LINE', // discard peer
|
||||
|
||||
SOMEONE_STARTED_BROADCASTING = "SOMEONE_STARTED_BROADCASTING", //show their stream tracks
|
||||
SOMEONE_STOPPED_BROADCASTING = "SOMEONE_STOPPED_BROADCASTING", // stop showing their stream tracks
|
||||
SOMEONE_STARTED_BROADCASTING = 'SOMEONE_STARTED_BROADCASTING', //show their stream tracks
|
||||
SOMEONE_STOPPED_BROADCASTING = 'SOMEONE_STOPPED_BROADCASTING', // stop showing their stream tracks
|
||||
|
||||
// sending to the correct room of tunedin folks AND also making sure it's the right event handler in the right handler for this component
|
||||
RTC_NEW_USER_JOINED_RESPONSE_PREFIX = "RTC_NEW_USER_JOINED_RESPONSE_PREFIX",
|
||||
RTC_RECEIVING_ANSWER_RESPONSE_PREFIX = "RTC_RECEIVING_ANSWER_RESPONSE_PREFIX",
|
||||
RTC_NEW_USER_JOINED_RESPONSE_PREFIX = 'RTC_NEW_USER_JOINED_RESPONSE_PREFIX',
|
||||
RTC_RECEIVING_ANSWER_RESPONSE_PREFIX = 'RTC_RECEIVING_ANSWER_RESPONSE_PREFIX',
|
||||
|
||||
SOMEONE_GOING_INTO_FLOW_STATE = "SOMEONE_GOING_INTO_FLOW_STATE",
|
||||
SOMEONE_GOING_INTO_FLOW_STATE = 'SOMEONE_GOING_INTO_FLOW_STATE',
|
||||
}
|
||||
|
||||
export default SocketChannels;
|
||||
@@ -71,33 +71,23 @@ export class ConnectToLineRequest {
|
||||
constructor(public lineId: string) {}
|
||||
}
|
||||
export class SomeoneConnectedResponse {
|
||||
constructor(
|
||||
public lineId: string,
|
||||
public userId: string,
|
||||
public allConnectedIntoUserIds: string[]
|
||||
) {}
|
||||
constructor(public lineId: string, public userId: string) {}
|
||||
}
|
||||
|
||||
export class SomeoneDisconnectedResponse {
|
||||
constructor(public lineId: string, public userId: string) {}
|
||||
}
|
||||
export class TuneToLineRequest {
|
||||
constructor(public lineId: string, public keepTunedIn: boolean = false) {}
|
||||
}
|
||||
export class SomeoneTunedResponse {
|
||||
constructor(
|
||||
public lineId: string,
|
||||
public userId: string,
|
||||
public allTunedIntoUserIds: string[],
|
||||
public toggledIn: boolean = false // tell client if this new user toggled in or just temporary so that they can update the right LineMember assoc
|
||||
) {}
|
||||
constructor(public lineId: string, public userId: string) {}
|
||||
}
|
||||
export class UntuneFromLineRequest {
|
||||
constructor(public lineId: string) {}
|
||||
}
|
||||
export class SomeoneUntunedFromLineResponse {
|
||||
constructor(
|
||||
public lineId: string,
|
||||
public userId: string,
|
||||
public allTunedIntoUserIds: string[]
|
||||
) {}
|
||||
constructor(public lineId: string, public userId: string) {}
|
||||
}
|
||||
|
||||
export class StartBroadcastingRequest {
|
||||
@@ -120,11 +110,7 @@ export class SocketEmitter<T> {
|
||||
}
|
||||
|
||||
export class RtcCallRequest {
|
||||
constructor(
|
||||
public lineId: string,
|
||||
public userIdToCall: string,
|
||||
public simplePeerSignal: any
|
||||
) {}
|
||||
constructor(public lineId: string, public userIdToCall: string, public simplePeerSignal: any) {}
|
||||
}
|
||||
|
||||
export class RtcNewUserResponse {
|
||||
@@ -132,11 +118,7 @@ export class RtcNewUserResponse {
|
||||
}
|
||||
|
||||
export class RtcAnswerRequest {
|
||||
constructor(
|
||||
public lineId: string,
|
||||
public userIdToCall: string,
|
||||
public simplePeerSignal: any
|
||||
) {}
|
||||
constructor(public lineId: string, public userIdToCall: string, public simplePeerSignal: any) {}
|
||||
}
|
||||
|
||||
export class RtcReceiveAnswerResponse {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"axios": "^0.26.1",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"electron-store": "^8.0.1",
|
||||
"immer": "^9.0.14",
|
||||
"moment": "^2.29.1",
|
||||
"mongodb": "^4.4.1",
|
||||
"react": "^17.0.2",
|
||||
@@ -119,6 +120,7 @@
|
||||
"recoil": "^0.6.1",
|
||||
"sass": "^1.51.0",
|
||||
"simple-peer": "^9.11.1",
|
||||
"socket.io-client": "^4.4.1"
|
||||
"socket.io-client": "^4.4.1",
|
||||
"use-immer": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@ import { LineMemberState } from '@nirvana/core/models/line.model';
|
||||
import {
|
||||
ServerResponseChannels,
|
||||
SomeoneConnectedResponse,
|
||||
SomeoneDisconnectedResponse,
|
||||
SomeoneTunedResponse,
|
||||
SomeoneUntunedFromLineResponse,
|
||||
UserStartedBroadcastingResponse,
|
||||
UserStoppedBroadcastingResponse,
|
||||
} from '@nirvana/core/sockets/channels';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useMap } from 'react-use';
|
||||
import { useImmer } from 'use-immer';
|
||||
|
||||
type LineIdToMasterLine = {
|
||||
[lineId: string]: MasterLineData;
|
||||
@@ -33,84 +36,125 @@ const RealTimeRoomContext = React.createContext<IRealTimeRoomProvider>({
|
||||
},
|
||||
});
|
||||
|
||||
// handles reads of new data
|
||||
// keeps listening to incoming socket events to make sure that the realtime rooms map is highly available
|
||||
/**
|
||||
*
|
||||
* handles reads of new data
|
||||
* keeps listening to incoming socket events to make sure that the realtime rooms map is highly available
|
||||
*
|
||||
* on load, we want to grab all of the rooms we are in
|
||||
* put them in a map
|
||||
*
|
||||
* fetch more audio clips, fire off async function to fetch more and add to the room map
|
||||
*
|
||||
* Socket Rooms:
|
||||
* - all people online for a line
|
||||
* - all tuned in folks on a line...have it selected or toggle tuned
|
||||
*
|
||||
* Socket Events:
|
||||
* - someone connected
|
||||
* - someone tuned in
|
||||
* - someone started broadcasting
|
||||
* - someone stopped broadcasting
|
||||
*
|
||||
* - someone disconnected...take them out of the necessary lists
|
||||
* - someone left x room
|
||||
* - someone joined x room
|
||||
*
|
||||
* - someone added me to line
|
||||
*
|
||||
* - someone went into flow state their status
|
||||
*
|
||||
* Socket Emissions:
|
||||
* - join a line
|
||||
* - tune into a line
|
||||
* - send audio clip
|
||||
* - create a line -> send to specific people
|
||||
*
|
||||
* REST endpoints:
|
||||
* - toggle tune or untoggle tune
|
||||
* - fetch content blocks for line history - react query
|
||||
*/
|
||||
|
||||
export function RealTimeRoomProvider({ children }: { children: React.ReactChild }) {
|
||||
const { rooms } = useRooms();
|
||||
const { $ws } = useSockets();
|
||||
const [realTimeRoomMap, setRealTimeRoomMap] = useState<LineIdToMasterLine>({});
|
||||
const [roomMap, updateRoomMap] = useImmer<LineIdToMasterLine>({});
|
||||
|
||||
const [selectedLineId, setSelectedLineId] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
// when me or anyone just initially connects to line
|
||||
$ws.on(ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE, (res: SomeoneConnectedResponse) => {
|
||||
console.log(
|
||||
`connected to line...here are all of the updated in the conected line ${res.lineId}...this isn't reliable considering it's not updated later`,
|
||||
res.allConnectedIntoUserIds,
|
||||
);
|
||||
console.log(`${res.userId} connected to room ${res.lineId}`);
|
||||
|
||||
setRealTimeRoomMap((prevLinesMap) => {
|
||||
const newMap = { ...prevLinesMap };
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newMap[res.lineId])
|
||||
newMap[res.lineId].connectedMemberIds = [
|
||||
...(newMap[res.lineId]?.connectedMemberIds ?? []),
|
||||
res.userId,
|
||||
];
|
||||
|
||||
return newMap;
|
||||
if (draft[res.lineId].connectedMemberIds) {
|
||||
draft[res.lineId].connectedMemberIds.push(res.userId);
|
||||
} else {
|
||||
draft[res.lineId].connectedMemberIds = [res.userId];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// someone tuning in, including perhaps me | either toggled in or just temporary
|
||||
$ws.on(ServerResponseChannels.SOMEONE_TUNED_INTO_LINE, (res: SomeoneTunedResponse) => {
|
||||
console.log(`here are all of updated users in the tuned in room`, res.allTunedIntoUserIds);
|
||||
console.log(`${res.userId} tuned into line ${res.lineId}`);
|
||||
|
||||
// TODO: if toggled in, make sure to update the current line member in the lines map so that
|
||||
// we can know to untune if user selects another line
|
||||
|
||||
// below, we are setting the list of tuned in folks based on fresh list from the server
|
||||
// better than just adding and removing? i think so, but have to handle not interrupting existing peer connections as this changes
|
||||
setRealTimeRoomMap((prevLinesMap) => {
|
||||
const newMap = { ...prevLinesMap };
|
||||
|
||||
if (newMap[res.lineId]) {
|
||||
newMap[res.lineId].tunedInMemberIds = res.allTunedIntoUserIds;
|
||||
|
||||
// if user is me, make sure to show me my updated line member association
|
||||
if (newMap[res.lineId].currentUserMember?.userId.toString() === res.userId) {
|
||||
newMap[res.lineId].currentUserMember.lastVisitDate = new Date();
|
||||
newMap[res.lineId].currentUserMember.state = res.toggledIn
|
||||
? LineMemberState.TUNED
|
||||
: LineMemberState.INBOX;
|
||||
}
|
||||
|
||||
// TODO: update the relevant lineMember (based on which userId is given): state and last visit date if current user is joining
|
||||
// and not just if it's the current user toggling in
|
||||
// right now, we just want user to know number of folks tuned and no need to expose who is toggle tuned...that lineMember can be stale
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
return newMap;
|
||||
if (draft[res.lineId].tunedInMemberIds) {
|
||||
draft[res.lineId].tunedInMemberIds.push(res.userId);
|
||||
} else {
|
||||
draft[res.lineId].tunedInMemberIds = [res.userId];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$ws.on(
|
||||
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
|
||||
(res: SomeoneUntunedFromLineResponse) => {
|
||||
console.log(`here are all of updated users in the tuned in room`, res.allTunedIntoUserIds);
|
||||
console.log(`${res.userId} untuned from ${res.lineId}`);
|
||||
|
||||
// TODO: if toggled in, make sure to update the current line member in the lines map so that
|
||||
// we can know to untune if user selects another line
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
setRealTimeRoomMap((prevLinesMap) => {
|
||||
const newMap = { ...prevLinesMap };
|
||||
if (draft[res.lineId].tunedInMemberIds) {
|
||||
draft[res.lineId].tunedInMemberIds = draft[res.lineId].tunedInMemberIds.filter(
|
||||
(userId) => userId !== res.userId,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// TODO: update the relevant lineMember (based on which userId is given): state and last visit date if current user is joining
|
||||
// remove them from the line connected list and tuned list if they are there
|
||||
$ws.on(
|
||||
ServerResponseChannels.SOMEONE_DISCONNECTED_FROM_LINE,
|
||||
(res: SomeoneDisconnectedResponse) => {
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newMap[res.lineId]) newMap[res.lineId].tunedInMemberIds = res.allTunedIntoUserIds;
|
||||
|
||||
return newMap;
|
||||
draft[res.lineId].connectedMemberIds = draft[res.lineId].connectedMemberIds?.filter(
|
||||
(userId) => userId !== res.userId,
|
||||
);
|
||||
draft[res.lineId].tunedInMemberIds = draft[res.lineId].tunedInMemberIds?.filter(
|
||||
(userId) => userId !== res.userId,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -118,18 +162,19 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild
|
||||
$ws.on(
|
||||
ServerResponseChannels.SOMEONE_STARTED_BROADCASTING,
|
||||
(res: UserStartedBroadcastingResponse) => {
|
||||
console.log('someone is starting to broadcast');
|
||||
console.log(`${res.userId} is starting to broadcast in ${res.lineId}`);
|
||||
|
||||
setRealTimeRoomMap((prevLinesMap) => {
|
||||
const newMap = { ...prevLinesMap };
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newMap[res.lineId])
|
||||
newMap[res.lineId].currentBroadcastersUserIds = [
|
||||
...(newMap[res.lineId].currentBroadcastersUserIds ?? []),
|
||||
res.userId,
|
||||
];
|
||||
|
||||
return newMap;
|
||||
if (draft[res.lineId].currentBroadcastersUserIds) {
|
||||
draft[res.lineId].currentBroadcastersUserIds.push(res.userId);
|
||||
} else {
|
||||
draft[res.lineId].currentBroadcastersUserIds = [res.userId];
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -137,18 +182,19 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild
|
||||
$ws.on(
|
||||
ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING,
|
||||
(res: UserStoppedBroadcastingResponse) => {
|
||||
setRealTimeRoomMap((prevLinesMap) => {
|
||||
const newMap = { ...prevLinesMap };
|
||||
console.log(`${res.userId} is STOPPED BROADCASTING in ${res.lineId}`);
|
||||
|
||||
if (newMap[res.lineId]?.currentBroadcastersUserIds) {
|
||||
newMap[res.lineId].currentBroadcastersUserIds = newMap[
|
||||
res.lineId
|
||||
].currentBroadcastersUserIds.filter(
|
||||
(broadcasterUserId) => broadcasterUserId !== res.userId,
|
||||
);
|
||||
updateRoomMap((draft) => {
|
||||
if (!draft[res.lineId]) {
|
||||
toast.error('there was a problem updating rooms!!!');
|
||||
return;
|
||||
}
|
||||
|
||||
return newMap;
|
||||
if (draft[res.lineId].currentBroadcastersUserIds) {
|
||||
draft[res.lineId].currentBroadcastersUserIds = draft[
|
||||
res.lineId
|
||||
].currentBroadcastersUserIds.filter((userId) => userId !== res.userId);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -157,30 +203,19 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild
|
||||
// ?perhaps only remove specific ones?
|
||||
$ws.removeAllListeners();
|
||||
};
|
||||
}, [realTimeRoomMap, $ws]);
|
||||
}, [roomMap, $ws, updateRoomMap]);
|
||||
|
||||
// converts the initial rooms to a map
|
||||
// converts the initial rooms fetch to a map
|
||||
useEffect(() => {
|
||||
if (rooms.value?.data?.masterLines?.length > 0) {
|
||||
setRealTimeRoomMap((prevMappings) => {
|
||||
// go through the lines from the persistent store
|
||||
|
||||
// get all of the id's and map assign to the main object
|
||||
|
||||
// ?prolly have no previous at this point...but I'm okay with override since this
|
||||
// ?useeffect is triggered on the refetching of the persistent store so we
|
||||
// ?are prolly looking to do a full app refresh and connection refresh
|
||||
const newMap = { ...prevMappings };
|
||||
|
||||
updateRoomMap((draft) => {
|
||||
rooms.value.data.masterLines.forEach((masterLine) => {
|
||||
const lineId = masterLine.lineDetails._id.toString();
|
||||
newMap[lineId] = masterLine;
|
||||
draft[lineId] = masterLine;
|
||||
});
|
||||
|
||||
return newMap;
|
||||
});
|
||||
}
|
||||
}, [rooms.value, setRealTimeRoomMap]);
|
||||
}, [rooms.value, updateRoomMap]);
|
||||
|
||||
/** show user line details on click of one line */
|
||||
const handleSelectLine = useCallback(
|
||||
@@ -192,10 +227,10 @@ export function RealTimeRoomProvider({ children }: { children: React.ReactChild
|
||||
);
|
||||
|
||||
return (
|
||||
<RealTimeRoomContext.Provider
|
||||
value={{ roomsMap: realTimeRoomMap, handleSelectLine, selectedLineId }}
|
||||
>
|
||||
<RealTimeRoomContext.Provider value={{ roomsMap: roomMap, handleSelectLine, selectedLineId }}>
|
||||
{children}
|
||||
|
||||
<pre>{JSON.stringify(roomMap)}</pre>
|
||||
</RealTimeRoomContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4743,6 +4743,11 @@ image-size@^0.7.4:
|
||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.5.tgz#269f357cf5797cb44683dfa99790e54c705ead04"
|
||||
integrity sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==
|
||||
|
||||
immer@^9.0.14:
|
||||
version "9.0.14"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48"
|
||||
integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
|
||||
@@ -8955,6 +8960,11 @@ url-parse-lax@^3.0.0:
|
||||
dependencies:
|
||||
prepend-http "^2.0.0"
|
||||
|
||||
use-immer@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/use-immer/-/use-immer-0.7.0.tgz#e3bfbb806b5e3ff6e37441be74c306d91c1e0962"
|
||||
integrity sha512-Re4hjrP3a/2ABZjAc0b7AK9s626bnO+H33RO2VUhiDZ2StBz5B663K6WNNlr4QtHWaGUmvLpwt3whFvvWuolQw==
|
||||
|
||||
username@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/username/-/username-5.1.0.tgz#a7f9325adce2d0166448cdd55d4985b1360f2508"
|
||||
|
||||
Reference in New Issue
Block a user