reogranized with a simple socket extension to data provider

This commit is contained in:
talksik
2022-05-07 07:56:36 -05:00
parent 309e74ff94
commit 0fb8bc2b57
6 changed files with 134 additions and 83 deletions
+34 -1
View File
@@ -1,6 +1,11 @@
import { Line, LineMember } from "@nirvana/core/models/line.model";
import {
Line,
LineMember,
LineMemberState,
} from "@nirvana/core/models/line.model";
import { client, collections } from "./database.service";
import NirvanaResponse from "@nirvana/core/responses/nirvanaResponse";
import { ObjectId } from "mongodb";
export class LineService {
@@ -109,4 +114,32 @@ export class LineService {
return null;
}
static async updateLineMemberState(
lineId: string,
userId: string,
newState: LineMemberState
) {
const query = { lineId, userId: new ObjectId(userId) };
const updateSet = { $set: { state: newState, lastVisitDate: new Date() } };
const updateRes = await collections.lineMembers?.findOneAndUpdate(
query,
updateSet
);
return updateRes;
}
static async updateLineMemberVisitDate(lineId: string, userId: string) {
const query = { lineId, userId: new ObjectId(userId) };
const updateSet = { $set: { lastVisitDate: new Date() } };
const updateRes = await collections.lineMembers?.findOneAndUpdate(
query,
updateSet
);
return updateRes;
}
}
+22 -2
View File
@@ -9,6 +9,8 @@ import SocketChannels, {
import GetAllSocketClients from "@nirvana/core/sockets/getAllActiveSocketClients";
import { JwtClaims } from "../middleware/auth";
import { LineMemberState } from "@nirvana/core/models/line.model";
import { LineService } from "../services/line.service";
import ReceiveSignal from "@nirvana/core/sockets/receiveSignal";
import SendSignal from "@nirvana/core/sockets/sendSignal";
import { UserService } from "../services/user.service";
@@ -79,7 +81,7 @@ export default function InitializeWs(io: any) {
});
/** TUNE | User tunes into the line either temporarily or toggled in */
socket.on(SocketChannels.TUNE_TO_LINE, (req: TuneToLine) => {
socket.on(SocketChannels.TUNE_TO_LINE, async (req: TuneToLine) => {
console.log(`${socket.id} user tuned into room for line ${req.lineId}`);
const roomName = `tunedLine:${req.lineId}`;
@@ -87,11 +89,29 @@ export default function InitializeWs(io: any) {
console.log(`${socket.id} now in rooms ${socket.rooms}`);
// persist tuning in if user is toggle tuning in
if (req.keepTunedIn) {
await LineService.updateLineMemberState(
req.lineId,
userInfo.userId,
LineMemberState.TUNED
);
} else {
// just updates the
await LineService.updateLineMemberVisitDate(
req.lineId,
userInfo.userId
);
}
const clientUserIdsInRoom = io.sockets.adapter.rooms
.get(roomName)
.map((socketId: any) => socketIdsToUserIds[socketId]);
io.in(roomName).emit(
// we want to notify everyone connected to the line even if they are not tuned in
const connectedLine = `connectedLine:${req.lineId}`;
io.in(connectedLine).emit(
SocketChannels.SOMEONE_TUNED_TO_LINE,
new SomeoneTuned(req.lineId, userInfo.userId, clientUserIdsInRoom)
);
+4
View File
@@ -61,3 +61,7 @@ export class UserBroadcastPull {
public isTurningOn: boolean = true
) {}
}
export class SocketEmitter<T> {
constructor(public channel: SocketChannels, data: T) {}
}
@@ -3,12 +3,13 @@ import {
ConnectToLine,
SomeoneConnected,
SomeoneTuned,
TuneToLine,
UserBroadcastPull,
UserBroadcastingPush,
} from "@nirvana/core/sockets/channels";
import React, { useContext } from "react";
import React, { useContext, useState } from "react";
import { Socket, io } from "socket.io-client";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect } from "react";
import MasterLineData from "@nirvana/core/models/masterLineData.model";
import SocketChannels from "@nirvana/core/sockets/channels";
@@ -18,35 +19,39 @@ import toast from "react-hot-toast";
import { useRecoilValue } from "recoil";
import { useUserLines } from "./index";
type LineIdToMasterLine = {
[lineId: string]: MasterLineData;
};
interface ILineDataContext {
// represents the modified and up to date lines data with availability from session
linesMap: LineIdToMasterLine;
relevantUsers: User[];
handleUserBroadcast: (lineId: string, isTurningOn: boolean) => void;
}
const LineDataContext = React.createContext<ILineDataContext>({
linesMap: {},
relevantUsers: [],
handleUserBroadcast: (lineId: string, isTurningOn: boolean = true) => {},
});
let $ws: Socket;
export function LineDataProvider({ children }) {
// TODO: have internal loading to prevent showing even router and all if something is not ready
// or have it within each property within the context value
// persistent store of lines
// ?just do simple synchronous axios/fetch in useEffect and manage isLoading ourselves?
const { data: basicUserLinesData } = useUserLines();
export function useSocketHandler(linesData: MasterLineData[]) {
const jwtToken = useRecoilValue($jwtToken);
const [linesMap, setLinesMap] = useState<LineIdToMasterLine>({});
useEffect(() => {
console.log(linesData);
if (linesData) {
setLinesMap((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 };
linesData.map((masterLine) => {
newMap[masterLine.lineDetails._id.toString()] = masterLine;
handleConnectToLine(masterLine.lineDetails._id.toString());
// tune into lines
});
return newMap;
});
}
}, [linesData, setLinesMap]);
useEffect(() => {
$ws = io("http://localhost:5000", {
query: { token: jwtToken },
@@ -99,53 +104,15 @@ export function LineDataProvider({ children }) {
`someone or myself buzz on or off in line ${pull.lineId}`
);
setLinesMap((prevLinesMap) => {
const newMap = { ...prevLinesMap };
const newMap = {};
// todo: check if it's the user or someone else broadcasting
// todo: check if it's the user or someone else broadcasting
if (newMap[pull.lineId])
newMap[pull.lineId].isUserBroadcasting = pull.isTurningOn;
return newMap;
});
if (newMap[pull.lineId])
newMap[pull.lineId].isUserBroadcasting = pull.isTurningOn;
}
);
}, [setLinesMap]);
// connect through ws to enrich basic lines data
useEffect(() => {
console.log("got basic user lines data!!!");
// ?need to calculate diff and only do stuff then?
// $ws.on(SocketChannels.CONNECT, console.log());
$ws.on("test", () => console.log("test"));
if (basicUserLinesData?.data?.masterLines.length > 0) {
setLinesMap((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 };
basicUserLinesData.data.masterLines.map((masterLine) => {
newMap[masterLine.lineDetails._id.toString()] = masterLine;
handleConnectToLine(masterLine.lineDetails._id.toString());
// tune into lines
});
return newMap;
});
}
}, [basicUserLinesData]);
}, []);
const handleConnectToLine = (lineId: string) => {
$ws.emit(SocketChannels.CONNECT_TO_LINE, new ConnectToLine(lineId));
@@ -160,7 +127,8 @@ export function LineDataProvider({ children }) {
// they already are in the socket room for updates including media connections and disconnections
// but set the flag so that the line row can know whether or not to start the webrtc process
// and know when to get out or disconnect from the webrtc when the flag turns off
// $ws.emit(SocketChannels.TUNE_INTO_LINE, new TuneIntoLine(lineId));
$ws.emit(SocketChannels.TUNE_TO_LINE, new TuneToLine(lineId, turnToggleOn));
};
/**
@@ -197,13 +165,45 @@ export function LineDataProvider({ children }) {
// update the specific line in lines map
// set the state to trigger the re-renders in the tree
},
[setLinesMap]
[$ws]
);
return {
linesMap,
handleConnectToLine,
handleTuneToLine,
handleUserBroadcast,
handleFetchMoreAudioBlocks,
};
}
export type LineIdToMasterLine = {
[lineId: string]: MasterLineData;
};
interface ILineDataContext {
// represents the modified and up to date lines data with availability from session
linesMap: LineIdToMasterLine;
relevantUsers: User[];
}
const LineDataContext = React.createContext<ILineDataContext>({
linesMap: {},
relevantUsers: [],
});
export function LineDataProvider({ children }) {
// TODO: have internal loading to prevent showing even router and all if something is not ready
// or have it within each property within the context value
// persistent store of lines
// ?just do simple synchronous axios/fetch in useEffect and manage isLoading ourselves?
const { data: basicUserLinesData } = useUserLines();
const { linesMap } = useSocketHandler(basicUserLinesData?.data?.masterLines);
const value: ILineDataContext = {
linesMap, // TODO send the updated map instead of this array
relevantUsers: [],
handleUserBroadcast,
};
return (
@@ -1,6 +0,0 @@
import SocketChannels from "@nirvana/core/sockets/channels";
import { io } from "socket.io-client";
const $ws = io("http://localhost:5000");
export default $ws;
@@ -25,7 +25,7 @@ export default function NirvanaTerminal() {
// simply using this query for specific data on loading
// todo: add these properties in context provider value although more work down the line for control
const { isLoading: isLoadingInitialLines } = useUserLines();
const { linesMap, handleUserBroadcast } = useLineDataProvider();
const { linesMap } = useLineDataProvider();
const allLines: MasterLineData[] = useMemo(() => {
const masterLines: MasterLineData[] = Object.values(linesMap);
@@ -59,7 +59,7 @@ export default function NirvanaTerminal() {
// todo: enable stream in this tuned in channel
if (lineId) handleUserBroadcast(lineId, true);
// if (lineId) handleUserBroadcast(lineId, true);
},
[]
);
@@ -70,7 +70,7 @@ export default function NirvanaTerminal() {
// todo: disable stream in this tuned in channel
if (lineId) handleUserBroadcast(lineId, false);
// if (lineId) handleUserBroadcast(lineId, false);
},
[]
);