reogranized with a simple socket extension to data provider
This commit is contained in:
@@ -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 { client, collections } from "./database.service";
|
||||||
|
|
||||||
|
import NirvanaResponse from "@nirvana/core/responses/nirvanaResponse";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
export class LineService {
|
export class LineService {
|
||||||
@@ -109,4 +114,32 @@ export class LineService {
|
|||||||
|
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import SocketChannels, {
|
|||||||
|
|
||||||
import GetAllSocketClients from "@nirvana/core/sockets/getAllActiveSocketClients";
|
import GetAllSocketClients from "@nirvana/core/sockets/getAllActiveSocketClients";
|
||||||
import { JwtClaims } from "../middleware/auth";
|
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 ReceiveSignal from "@nirvana/core/sockets/receiveSignal";
|
||||||
import SendSignal from "@nirvana/core/sockets/sendSignal";
|
import SendSignal from "@nirvana/core/sockets/sendSignal";
|
||||||
import { UserService } from "../services/user.service";
|
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 */
|
/** 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}`);
|
console.log(`${socket.id} user tuned into room for line ${req.lineId}`);
|
||||||
|
|
||||||
const roomName = `tunedLine:${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}`);
|
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
|
const clientUserIdsInRoom = io.sockets.adapter.rooms
|
||||||
.get(roomName)
|
.get(roomName)
|
||||||
.map((socketId: any) => socketIdsToUserIds[socketId]);
|
.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,
|
SocketChannels.SOMEONE_TUNED_TO_LINE,
|
||||||
new SomeoneTuned(req.lineId, userInfo.userId, clientUserIdsInRoom)
|
new SomeoneTuned(req.lineId, userInfo.userId, clientUserIdsInRoom)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -61,3 +61,7 @@ export class UserBroadcastPull {
|
|||||||
public isTurningOn: boolean = true
|
public isTurningOn: boolean = true
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SocketEmitter<T> {
|
||||||
|
constructor(public channel: SocketChannels, data: T) {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import {
|
|||||||
ConnectToLine,
|
ConnectToLine,
|
||||||
SomeoneConnected,
|
SomeoneConnected,
|
||||||
SomeoneTuned,
|
SomeoneTuned,
|
||||||
|
TuneToLine,
|
||||||
UserBroadcastPull,
|
UserBroadcastPull,
|
||||||
UserBroadcastingPush,
|
UserBroadcastingPush,
|
||||||
} from "@nirvana/core/sockets/channels";
|
} from "@nirvana/core/sockets/channels";
|
||||||
import React, { useContext } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { Socket, io } from "socket.io-client";
|
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 MasterLineData from "@nirvana/core/models/masterLineData.model";
|
||||||
import SocketChannels from "@nirvana/core/sockets/channels";
|
import SocketChannels from "@nirvana/core/sockets/channels";
|
||||||
@@ -18,35 +19,39 @@ import toast from "react-hot-toast";
|
|||||||
import { useRecoilValue } from "recoil";
|
import { useRecoilValue } from "recoil";
|
||||||
import { useUserLines } from "./index";
|
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;
|
let $ws: Socket;
|
||||||
|
|
||||||
export function LineDataProvider({ children }) {
|
export function useSocketHandler(linesData: MasterLineData[]) {
|
||||||
// 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 jwtToken = useRecoilValue($jwtToken);
|
const jwtToken = useRecoilValue($jwtToken);
|
||||||
|
|
||||||
const [linesMap, setLinesMap] = useState<LineIdToMasterLine>({});
|
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(() => {
|
useEffect(() => {
|
||||||
$ws = io("http://localhost:5000", {
|
$ws = io("http://localhost:5000", {
|
||||||
query: { token: jwtToken },
|
query: { token: jwtToken },
|
||||||
@@ -99,53 +104,15 @@ export function LineDataProvider({ children }) {
|
|||||||
`someone or myself buzz on or off in line ${pull.lineId}`
|
`someone or myself buzz on or off in line ${pull.lineId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
setLinesMap((prevLinesMap) => {
|
const newMap = {};
|
||||||
const newMap = { ...prevLinesMap };
|
|
||||||
|
|
||||||
// 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])
|
if (newMap[pull.lineId])
|
||||||
newMap[pull.lineId].isUserBroadcasting = pull.isTurningOn;
|
newMap[pull.lineId].isUserBroadcasting = pull.isTurningOn;
|
||||||
|
|
||||||
return newMap;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}, [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) => {
|
const handleConnectToLine = (lineId: string) => {
|
||||||
$ws.emit(SocketChannels.CONNECT_TO_LINE, new ConnectToLine(lineId));
|
$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
|
// 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
|
// 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
|
// 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
|
// update the specific line in lines map
|
||||||
// set the state to trigger the re-renders in the tree
|
// 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 = {
|
const value: ILineDataContext = {
|
||||||
linesMap, // TODO send the updated map instead of this array
|
linesMap, // TODO send the updated map instead of this array
|
||||||
relevantUsers: [],
|
relevantUsers: [],
|
||||||
handleUserBroadcast,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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
|
// 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
|
// todo: add these properties in context provider value although more work down the line for control
|
||||||
const { isLoading: isLoadingInitialLines } = useUserLines();
|
const { isLoading: isLoadingInitialLines } = useUserLines();
|
||||||
const { linesMap, handleUserBroadcast } = useLineDataProvider();
|
const { linesMap } = useLineDataProvider();
|
||||||
|
|
||||||
const allLines: MasterLineData[] = useMemo(() => {
|
const allLines: MasterLineData[] = useMemo(() => {
|
||||||
const masterLines: MasterLineData[] = Object.values(linesMap);
|
const masterLines: MasterLineData[] = Object.values(linesMap);
|
||||||
@@ -59,7 +59,7 @@ export default function NirvanaTerminal() {
|
|||||||
|
|
||||||
// todo: enable stream in this tuned in channel
|
// 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
|
// todo: disable stream in this tuned in channel
|
||||||
|
|
||||||
if (lineId) handleUserBroadcast(lineId, false);
|
// if (lineId) handleUserBroadcast(lineId, false);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user