auth and socket connections linear and slow progress but cleaner?
This commit is contained in:
+128
-188
@@ -15,20 +15,20 @@ import {
|
||||
UntuneFromLineRequest,
|
||||
UserStartedBroadcastingResponse,
|
||||
UserStoppedBroadcastingResponse,
|
||||
} from "@nirvana/core/sockets/channels";
|
||||
} from '@nirvana/core/sockets/channels';
|
||||
|
||||
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";
|
||||
import { UserStatus } from "@nirvana/core/models/user.model";
|
||||
import { client } from "../services/database.service";
|
||||
import { loadConfig } from "../config";
|
||||
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';
|
||||
import { UserStatus } from '@nirvana/core/models/user.model';
|
||||
import { client } from '../services/database.service';
|
||||
import { loadConfig } from '../config';
|
||||
|
||||
const jwt = require("jsonwebtoken");
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
@@ -41,14 +41,15 @@ const userIdsToSocketIds: {
|
||||
} = {};
|
||||
|
||||
export default function InitializeWs(io: any) {
|
||||
console.log("initializing web sockets");
|
||||
console.log('initializing web sockets');
|
||||
|
||||
return io
|
||||
.use(function (socket: any, next: any) {
|
||||
console.log("authenticating user...");
|
||||
console.log('authenticating user...');
|
||||
|
||||
try {
|
||||
const { token } = socket.handshake.query;
|
||||
console.log(token);
|
||||
|
||||
// verify jwt token with our api secret
|
||||
var decoded: JwtClaims = jwt.verify(token, config.JWT_TOKEN_SECRET);
|
||||
@@ -58,171 +59,132 @@ export default function InitializeWs(io: any) {
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
next(new Error("WS Authentication Error"));
|
||||
next(new Error('WS Authentication Error'));
|
||||
}
|
||||
})
|
||||
.on("connection", function (socket: any) {
|
||||
.on('connection', function (socket: any) {
|
||||
const userInfo: JwtClaims = socket.userInfo;
|
||||
|
||||
socketIdsToUserIds[socket.id] = userInfo.userId.toString();
|
||||
userIdsToSocketIds[userInfo.userId.toString()] = socket.id;
|
||||
|
||||
console.log(
|
||||
`a user connected | user Id: ${userInfo.userId} and name: ${userInfo.name}`
|
||||
);
|
||||
console.log(`a user connected | user Id: ${userInfo.userId} and name: ${userInfo.name}`);
|
||||
|
||||
socket.on("test", () => {
|
||||
console.log("asdf");
|
||||
socket.on('test', () => {
|
||||
console.log('asdf');
|
||||
});
|
||||
|
||||
// ?verification that user is in a particular line to be tuned into it or just generally in it?
|
||||
|
||||
/** CONNECT | User wants to subscribe to live emissions of a line */
|
||||
socket.on(
|
||||
ServerRequestChannels.CONNECT_TO_LINE,
|
||||
(req: ConnectToLineRequest) => {
|
||||
// add this user to the room
|
||||
console.log(
|
||||
`${socket.id} user CONNECTED room for line ${Object.keys(
|
||||
socket.rooms
|
||||
)}`
|
||||
);
|
||||
socket.on(ServerRequestChannels.CONNECT_TO_LINE, (req: ConnectToLineRequest) => {
|
||||
// add this user to the room
|
||||
console.log(`${socket.id} user CONNECTED room for line ${Object.keys(socket.rooms)}`);
|
||||
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
socket.join(roomName);
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
socket.join(roomName);
|
||||
|
||||
console.log(`${socket.id} now in rooms ${socket.rooms}`);
|
||||
console.log(`${socket.id} now in rooms ${socket.rooms}`);
|
||||
|
||||
const clientUserIdsInRoom = [
|
||||
...(io.sockets.adapter.rooms.get(roomName) ?? []),
|
||||
].map(
|
||||
(otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]
|
||||
);
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE,
|
||||
new SomeoneConnectedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 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")
|
||||
);
|
||||
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}`
|
||||
socket.on(ServerRequestChannels.TUNE_INTO_LINE, async (req: TuneToLineRequest) => {
|
||||
console.log(`${socket.id} user TUNED into room for line ${req.lineId}`);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
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
|
||||
)
|
||||
} 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,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Notify all connected users when someone UNTUNES from a room
|
||||
* ?might not be needed, all users' memory of tuned in users is irrelevant? don't need real time? but UI will show # of users tuned in?
|
||||
*/
|
||||
socket.on(
|
||||
ServerRequestChannels.UNTUNE_FROM_LINE,
|
||||
async (req: UntuneFromLineRequest) => {
|
||||
const roomName = `tunedLine:${req.lineId}`;
|
||||
socket.leave(roomName);
|
||||
socket.on(ServerRequestChannels.UNTUNE_FROM_LINE, async (req: UntuneFromLineRequest) => {
|
||||
const roomName = `tunedLine:${req.lineId}`;
|
||||
socket.leave(roomName);
|
||||
|
||||
console.log("someone left room");
|
||||
console.log('someone left room');
|
||||
|
||||
const clientUserIdsInRoom = [
|
||||
...(io.sockets.adapter.rooms.get(roomName) ?? []),
|
||||
].map(
|
||||
(otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]
|
||||
);
|
||||
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}`;
|
||||
// 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
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.in(connectedLineRoomName).emit(
|
||||
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
|
||||
new SomeoneUntunedFromLineResponse(req.lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: use same pattern as tuning and untuning and send updated fresh list of current broadcasters but using another namespace/room for broadcasters in a line
|
||||
/** BROADCAST UPDATE | tell all connected, not just tuned into, that there is an update to someone broadcasting */
|
||||
socket.on(
|
||||
ServerRequestChannels.BROADCAST_TO_LINE,
|
||||
(req: StartBroadcastingRequest) => {
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
socket.on(ServerRequestChannels.BROADCAST_TO_LINE, (req: StartBroadcastingRequest) => {
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_STARTED_BROADCASTING,
|
||||
new UserStartedBroadcastingResponse(req.lineId, userInfo.userId)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_STARTED_BROADCASTING,
|
||||
new UserStartedBroadcastingResponse(req.lineId, userInfo.userId),
|
||||
);
|
||||
});
|
||||
|
||||
socket.on(
|
||||
ServerRequestChannels.STOP_BROADCAST_TO_LINE,
|
||||
(req: StopBroadcastingRequest) => {
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
socket.on(ServerRequestChannels.STOP_BROADCAST_TO_LINE, (req: StopBroadcastingRequest) => {
|
||||
const roomName = `connectedLine:${req.lineId}`;
|
||||
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING,
|
||||
new UserStoppedBroadcastingResponse(req.lineId, userInfo.userId)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING,
|
||||
new UserStoppedBroadcastingResponse(req.lineId, userInfo.userId),
|
||||
);
|
||||
});
|
||||
|
||||
// socket.on(SocketChannels.SEND_SIGNAL, async (payload: SendSignal) => {
|
||||
// console.log(payload);
|
||||
@@ -240,29 +202,23 @@ export default function InitializeWs(io: any) {
|
||||
// });
|
||||
|
||||
// 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];
|
||||
socket.on(ServerRequestChannels.RTC_CALL_REQUEST, (req: RtcCallRequest) => {
|
||||
const userSocketId = userIdsToSocketIds[req.userIdToCall];
|
||||
|
||||
io.to(userSocketId).emit(
|
||||
`${ServerResponseChannels.RTC_NEW_USER_JOINED_RESPONSE_PREFIX}:${req.lineId}`,
|
||||
new RtcNewUserResponse(userInfo.userId, req.simplePeerSignal)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.to(userSocketId).emit(
|
||||
`${ServerResponseChannels.RTC_NEW_USER_JOINED_RESPONSE_PREFIX}:${req.lineId}`,
|
||||
new RtcNewUserResponse(userInfo.userId, req.simplePeerSignal),
|
||||
);
|
||||
});
|
||||
|
||||
socket.on(
|
||||
ServerRequestChannels.RTC_ANSWER_REQUEST,
|
||||
(req: RtcAnswerRequest) => {
|
||||
const userSocketId = userIdsToSocketIds[req.userIdToCall];
|
||||
socket.on(ServerRequestChannels.RTC_ANSWER_REQUEST, (req: RtcAnswerRequest) => {
|
||||
const userSocketId = userIdsToSocketIds[req.userIdToCall];
|
||||
|
||||
io.to(userSocketId).emit(
|
||||
`${ServerResponseChannels.RTC_RECEIVING_ANSWER_RESPONSE_PREFIX}:${req.lineId}`,
|
||||
new RtcReceiveAnswerResponse(userInfo.userId, req.simplePeerSignal)
|
||||
);
|
||||
}
|
||||
);
|
||||
io.to(userSocketId).emit(
|
||||
`${ServerResponseChannels.RTC_RECEIVING_ANSWER_RESPONSE_PREFIX}:${req.lineId}`,
|
||||
new RtcReceiveAnswerResponse(userInfo.userId, req.simplePeerSignal),
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: not complete
|
||||
socket.on(ServerRequestChannels.GOING_INTO_FLOW_STATE, () => {
|
||||
@@ -272,17 +228,12 @@ export default function InitializeWs(io: any) {
|
||||
|
||||
for (const roomName of socket.rooms) {
|
||||
if (roomName !== socket.id) {
|
||||
const lineId = roomName.split(":")[1];
|
||||
if (roomName.includes("connectedLine")) {
|
||||
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) ?? []),
|
||||
]
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])]
|
||||
.filter((mappedSocketId) => mappedSocketId !== socket.id)
|
||||
.map(
|
||||
(otherUserSocketId: string) =>
|
||||
socketIdsToUserIds[otherUserSocketId]
|
||||
);
|
||||
.map((otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]);
|
||||
|
||||
// io.in(roomName).emit(
|
||||
// ServerResponseChannels.SOMEONE_GOING_INTO_FLOW_STATE,
|
||||
@@ -300,33 +251,24 @@ export default function InitializeWs(io: any) {
|
||||
// tell all connected people that I am disconnecting
|
||||
// tell tuned in folks that I am leaving the room
|
||||
// tell the tuned in folks the new list of
|
||||
socket.on("disconnecting", (reason: any) => {
|
||||
socket.on('disconnecting', (reason: any) => {
|
||||
console.log(reason);
|
||||
|
||||
console.log(socket.rooms);
|
||||
for (const roomName of socket.rooms) {
|
||||
if (roomName !== socket.id) {
|
||||
const lineId = roomName.split(":")[1];
|
||||
if (roomName.includes("tunedLine")) {
|
||||
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) ?? []),
|
||||
]
|
||||
const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])]
|
||||
.filter((mappedSocketId) => mappedSocketId !== socket.id)
|
||||
.map(
|
||||
(otherUserSocketId: string) =>
|
||||
socketIdsToUserIds[otherUserSocketId]
|
||||
);
|
||||
.map((otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId]);
|
||||
|
||||
io.in(roomName).emit(
|
||||
ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE,
|
||||
new SomeoneUntunedFromLineResponse(
|
||||
lineId,
|
||||
userInfo.userId,
|
||||
clientUserIdsInRoom
|
||||
)
|
||||
new SomeoneUntunedFromLineResponse(lineId, userInfo.userId, clientUserIdsInRoom),
|
||||
);
|
||||
} else if (roomName.includes("connectedLine")) {
|
||||
} 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));
|
||||
}
|
||||
@@ -335,17 +277,15 @@ export default function InitializeWs(io: any) {
|
||||
});
|
||||
|
||||
// ==== DISCONNECT ====
|
||||
socket.on("disconnect", () => {
|
||||
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('user disconnected');
|
||||
console.log(`list of sockets mappings in memory: ${socketIdsToUserIds}`);
|
||||
|
||||
console.log(socket.rooms);
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"react-hotkeys": "^2.0.0",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-query": "^3.34.16",
|
||||
"react-use": "^17.3.2",
|
||||
"recoil": "^0.6.1",
|
||||
"sass": "^1.51.0",
|
||||
"simple-peer": "^9.11.1",
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios';
|
||||
|
||||
import CreateLineRequest from '@nirvana/core/requests/createLine.request';
|
||||
import GetUserLinesResponse from '@nirvana/core/responses/getUserLines.response';
|
||||
import { Line } from '@nirvana/core/models/line.model';
|
||||
import LoginResponse from '../../../core/responses/login.response';
|
||||
import MasterLineData from '@nirvana/core/models/masterLineData.model';
|
||||
import NirvanaResponse from '../../../core/responses/nirvanaResponse';
|
||||
import { User } from '@nirvana/core/models';
|
||||
import UserDetailsResponse from '../../../core/responses/userDetails.response';
|
||||
import UserSearchResponse from '../../../core/responses/userSearch.response';
|
||||
|
||||
// export const localHost = process.env.REACT_APP_API_DOMAIN;
|
||||
|
||||
export const localHost = 'http://localhost:5000/api';
|
||||
|
||||
export default class NirvanaApi {
|
||||
// auth token from google that our backend will use
|
||||
static _jwtToken?: string;
|
||||
|
||||
static async fetch<T>(url: string, method: Method, privateRoute = false, body: object = null) {
|
||||
// use the auth token if it's a private route
|
||||
// error if no auth token and it's a private route
|
||||
// throw error and show message on anything that is an error from the backend
|
||||
|
||||
const fullUrl = localHost + url;
|
||||
|
||||
let res;
|
||||
if (privateRoute && !this._jwtToken) throw Error('No jwt token available!');
|
||||
|
||||
if (privateRoute && this._jwtToken) {
|
||||
res = await fetch(fullUrl, {
|
||||
method: method,
|
||||
headers: {
|
||||
Authorization: this._jwtToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: body ? JSON.stringify(body) : null,
|
||||
});
|
||||
} else {
|
||||
res = await fetch(fullUrl);
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
if (res.status === 401) throw new Error('You are not authorized here');
|
||||
|
||||
throw new Error('Something went wrong');
|
||||
}
|
||||
|
||||
return await res.json();
|
||||
}
|
||||
}
|
||||
|
||||
export async function serverCheck(): Promise<void> {
|
||||
return await NirvanaApi.fetch(`/status`, 'GET', false);
|
||||
}
|
||||
|
||||
export async function login(reqLoginTokens: {
|
||||
accessToken: string;
|
||||
idToken: string;
|
||||
}): Promise<LoginResponse> {
|
||||
return await NirvanaApi.fetch(
|
||||
`/user/login?access_token=${reqLoginTokens.accessToken}&id_token=${reqLoginTokens.idToken}`,
|
||||
'GET',
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
export async function authCheck(): Promise<void> {
|
||||
return await NirvanaApi.fetch(`/user/authcheck`, 'GET', true);
|
||||
}
|
||||
|
||||
export async function getUserDetails(): Promise<UserDetailsResponse> {
|
||||
return await NirvanaApi.fetch(`/user`, 'GET', true);
|
||||
}
|
||||
|
||||
export async function userSearch(searchQuery: string): Promise<UserSearchResponse> {
|
||||
return await NirvanaApi.fetch(`/search/users?query=${searchQuery}`, 'GET', true);
|
||||
}
|
||||
|
||||
export async function getUserLines(): Promise<NirvanaResponse<GetUserLinesResponse>> {
|
||||
return await NirvanaApi.fetch<NirvanaResponse<GetUserLinesResponse>>(`/lines`, 'GET', true);
|
||||
}
|
||||
|
||||
export async function getDmByUserId(otherUserId: string): Promise<Line> {
|
||||
return await NirvanaApi.fetch(`/lines/dm/${otherUserId}`, 'GET', true);
|
||||
}
|
||||
|
||||
export async function createLine(request: CreateLineRequest): Promise<NirvanaResponse<Line>> {
|
||||
return await NirvanaApi.fetch(`/lines`, 'POST', true, request);
|
||||
}
|
||||
@@ -1,18 +1,53 @@
|
||||
import React, { useContext, useState, useEffect } from 'react';
|
||||
import { User } from '@nirvana/core/models/user.model';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
import NirvanaApi, { getUserDetails } from '../api/NirvanaApi';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
interface IAuthProvider {
|
||||
user: User;
|
||||
user?: User;
|
||||
jwtToken?: string;
|
||||
setJwtToken?: (jwtToken: string) => void;
|
||||
}
|
||||
|
||||
const AuthContext = React.createContext<IAuthProvider>({
|
||||
user: null,
|
||||
});
|
||||
const AuthContext = React.createContext<IAuthProvider>({});
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
if (true) return <></>;
|
||||
const [jwtToken, setJwtToken] = useState<string>();
|
||||
const [userFetchState, fetchUser] = useAsyncFn(getUserDetails);
|
||||
|
||||
return <AuthContext.Provider value={{}}>{children}</AuthContext.Provider>;
|
||||
useEffect(() => {
|
||||
if (jwtToken) {
|
||||
console.warn(jwtToken);
|
||||
|
||||
// ?should this be set here? what's a better way of
|
||||
NirvanaApi._jwtToken = jwtToken;
|
||||
|
||||
fetchUser()
|
||||
.then((response) => {
|
||||
toast.success('authenticated user');
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error('problem in authenticating jwt token');
|
||||
});
|
||||
}
|
||||
}, [jwtToken, fetchUser]);
|
||||
|
||||
const handleSetJwtToken = useCallback(
|
||||
(newJwtToken: string) => {
|
||||
setJwtToken(newJwtToken);
|
||||
},
|
||||
[setJwtToken],
|
||||
);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{ user: userFetchState.value?.user, setJwtToken: handleSetJwtToken, jwtToken }}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default function useAuth() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import toast from 'react-hot-toast';
|
||||
import { io, Socket } from 'socket.io-client';
|
||||
import useAuth from './AuthProvider';
|
||||
|
||||
interface ISocketProvider {
|
||||
$ws: Socket;
|
||||
@@ -10,9 +12,17 @@ const SocketContext = React.createContext<ISocketProvider>({
|
||||
});
|
||||
|
||||
export function SocketProvider({ children }: { children: React.ReactNode }) {
|
||||
const { jwtToken } = useAuth();
|
||||
|
||||
const [$ws, set$ws] = useState<Socket>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!jwtToken) {
|
||||
toast.error('no jwt token!!!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const socketConnection = io('http://localhost:5000', {
|
||||
query: { token: jwtToken },
|
||||
transports: ['websocket'],
|
||||
@@ -21,10 +31,45 @@ export function SocketProvider({ children }: { children: React.ReactNode }) {
|
||||
reconnection: false, // ! TESTING THE PROBLEM WITH RECONNECTION CLIENT LISTENERS NOT ACTIVATING
|
||||
});
|
||||
|
||||
set$ws(socketConnection);
|
||||
}, [set$ws]);
|
||||
socketConnection.on('connect', () => {
|
||||
toast.success('sockets connected');
|
||||
});
|
||||
|
||||
if (!$ws) return <span>please wait for a solid connection</span>;
|
||||
socketConnection.io.on('close', () => {
|
||||
console.error(
|
||||
'SOCKET | there was a problem with your app...connection closed likely due to idling or manual disconnect',
|
||||
);
|
||||
|
||||
toast.error('sorry...this is our bad...please refresh with cmd + r');
|
||||
});
|
||||
|
||||
// client-side errors
|
||||
socketConnection.on('connect_error', (err) => {
|
||||
console.error(`SOCKETS | ${err.message}`);
|
||||
toast.error('sorry...this is our bad...please refresh with cmd + r');
|
||||
});
|
||||
|
||||
set$ws(socketConnection);
|
||||
|
||||
return () => {
|
||||
socketConnection.disconnect();
|
||||
};
|
||||
}, [set$ws, jwtToken]);
|
||||
|
||||
if (!$ws) {
|
||||
return (
|
||||
<div className="h-screen w-screen justify-center items-center bg-white flex flex-col">
|
||||
<span className="text-gray-400">
|
||||
{
|
||||
"Please wait for a solid connection. If that doesn't work, please click below or restart the application."
|
||||
}
|
||||
</span>
|
||||
<button onClick={() => console.warn('NOT IMPLEMENTED...manual reconnect button')}>
|
||||
Reconnect
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <SocketContext.Provider value={{ $ws }}>{children}</SocketContext.Provider>;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
import { AuthProvider } from '../providers/AuthProvider';
|
||||
import { ElectronProvider } from '../providers/ElectronProvider';
|
||||
import SocketProvider from '../providers/SocketProvider';
|
||||
import { SocketProvider } from '../providers/SocketProvider';
|
||||
import ProtectedRoute from './protected/ProtectedRoute';
|
||||
|
||||
export default function ElectronApp() {
|
||||
return (
|
||||
<ElectronProvider>
|
||||
<SocketProvider>
|
||||
<div> this is the bottom of the tree</div>
|
||||
</SocketProvider>
|
||||
<AuthProvider>
|
||||
<ProtectedRoute>
|
||||
<SocketProvider>yo its connected dawg</SocketProvider>
|
||||
</ProtectedRoute>
|
||||
</AuthProvider>
|
||||
|
||||
<Toaster
|
||||
position={'bottom-right'}
|
||||
toastOptions={{
|
||||
style: {
|
||||
borderRadius: '10px',
|
||||
background: '#333',
|
||||
color: '#fff',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ElectronProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import useAuth from '../../providers/AuthProvider';
|
||||
import Login from './login/Login';
|
||||
|
||||
export default function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const { user } = useAuth();
|
||||
|
||||
if (user) return;
|
||||
return <>hey</>;
|
||||
if (!user) return <Login />;
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import Channels, { STORE_ITEMS } from '../../electron/constants';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { $jwtToken } from '../../controller/recoil';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import Logo from '../../components/Logo';
|
||||
import { useLogin } from '../../controller/index';
|
||||
// import Logo from '../../components/Logo';
|
||||
import { login } from '../../../api/NirvanaApi';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
import Channels from '../../../electron/constants';
|
||||
import useAuth from '../../../providers/AuthProvider';
|
||||
|
||||
export default function Login() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const { setJwtToken } = useAuth();
|
||||
|
||||
const setJwtToken = useSetRecoilState($jwtToken);
|
||||
const [loginState, loginApiHandler] = useAsyncFn(login);
|
||||
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
window.electronAPI.once(
|
||||
@@ -19,15 +21,16 @@ export default function Login() {
|
||||
console.log('got tokens', tokens);
|
||||
|
||||
setIsLoading(true);
|
||||
// todo: implement refresh token procedure in api layer by sending refresh_token and such
|
||||
|
||||
const loginResponse = await mutateAsync({
|
||||
const loginResponse = await loginApiHandler({
|
||||
accessToken: tokens.access_token,
|
||||
idToken: tokens.id_token,
|
||||
});
|
||||
|
||||
const { jwtToken, userDetails } = loginResponse;
|
||||
|
||||
setJwtToken(jwtToken);
|
||||
|
||||
setIsLoading(false);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -35,8 +38,9 @@ export default function Login() {
|
||||
// return () => {
|
||||
// window.electronAPI.removeAllListeners(Channels.GOOGLE_AUTH_TOKENS);
|
||||
// };
|
||||
}, []);
|
||||
}, [loginApiHandler, setJwtToken]);
|
||||
|
||||
// take user to browser to complete authentication
|
||||
const continueAuth = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -50,7 +54,7 @@ export default function Login() {
|
||||
h-screen w-screen
|
||||
bg-zinc-700"
|
||||
>
|
||||
<Logo className="scale-50" />
|
||||
{/* <Logo className="scale-50" /> */}
|
||||
|
||||
{/* ! TESTING PURPOSES */}
|
||||
<div className={'text-white flex flex-col gap-5'}>
|
||||
|
||||
Reference in New Issue
Block a user