From 0fb8bc2b5712d0c07065cc30f2177fe62be754a6 Mon Sep 17 00:00:00 2001 From: talksik Date: Sat, 7 May 2022 07:56:36 -0500 Subject: [PATCH] reogranized with a simple socket extension to data provider --- packages/api/services/line.service.ts | 35 ++++- packages/api/sockets/index.ts | 24 ++- packages/core/sockets/channels.ts | 4 + .../src/controller/lineDataProvider.tsx | 142 +++++++++--------- packages/desktop/src/controller/sockets.tsx | 6 - packages/desktop/src/pages/terminal/index.tsx | 6 +- 6 files changed, 134 insertions(+), 83 deletions(-) diff --git a/packages/api/services/line.service.ts b/packages/api/services/line.service.ts index 6e40f3d..7266a5b 100644 --- a/packages/api/services/line.service.ts +++ b/packages/api/services/line.service.ts @@ -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; + } } diff --git a/packages/api/sockets/index.ts b/packages/api/sockets/index.ts index 08dca08..7deeaa2 100644 --- a/packages/api/sockets/index.ts +++ b/packages/api/sockets/index.ts @@ -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) ); diff --git a/packages/core/sockets/channels.ts b/packages/core/sockets/channels.ts index 67011f4..b7bd5b5 100644 --- a/packages/core/sockets/channels.ts +++ b/packages/core/sockets/channels.ts @@ -61,3 +61,7 @@ export class UserBroadcastPull { public isTurningOn: boolean = true ) {} } + +export class SocketEmitter { + constructor(public channel: SocketChannels, data: T) {} +} diff --git a/packages/desktop/src/controller/lineDataProvider.tsx b/packages/desktop/src/controller/lineDataProvider.tsx index 9d8c1e6..faf22ea 100644 --- a/packages/desktop/src/controller/lineDataProvider.tsx +++ b/packages/desktop/src/controller/lineDataProvider.tsx @@ -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({ - 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({}); + 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({ + 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 ( diff --git a/packages/desktop/src/controller/sockets.tsx b/packages/desktop/src/controller/sockets.tsx index cba2f23..e69de29 100644 --- a/packages/desktop/src/controller/sockets.tsx +++ b/packages/desktop/src/controller/sockets.tsx @@ -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; diff --git a/packages/desktop/src/pages/terminal/index.tsx b/packages/desktop/src/pages/terminal/index.tsx index e2973e9..caa53e0 100644 --- a/packages/desktop/src/pages/terminal/index.tsx +++ b/packages/desktop/src/pages/terminal/index.tsx @@ -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); }, [] );