From ae600d7cfc979669a7cbf568c55828164bf388a9 Mon Sep 17 00:00:00 2001 From: Gilgamesh Date: Fri, 24 Jan 2025 10:17:31 -0500 Subject: [PATCH 01/47] testing --- package.json | 10 ++--- .../main/WebRTC-composer/WebRTCComposer.tsx | 2 + .../WebRTC-composer/WebRTCServerEntryForm.tsx | 22 +++++++++-- .../WebRTCSessionEntryForm.tsx | 1 + .../controllers/webrtcPeerController.ts | 38 +++++++++++++++---- src/server/server.js | 2 +- webpack.config.js | 4 +- webpack.development.js | 9 +++-- 8 files changed, 64 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index f8133ee47..501d12bb3 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "gh-publish-mac": "electron-builder build --x64 --mac -p always", "gh-publish": "electron-builder build -mwl -p always", "check-types": "tsc", - "postinstall": "patch-package" + "postinstall": "NODE_OPTIONS=--no-node-snapshot patch-package" }, "build": { "npmRebuild": false, @@ -47,7 +47,7 @@ "preload.js", "src/server/*" ], - "nodeVersion": "16.15.0", + "nodeVersion": "18.18.0", "nsis": { "createDesktopShortcut": "always" }, @@ -91,7 +91,7 @@ "license": "MIT", "homepage": "http://www.getswell.io", "engines": { - "node": ">=16.15.0", + "node": ">=18.0.0", "npm": ">=7.0.0" }, "dependencies": { @@ -139,11 +139,12 @@ "graphql-tag": "^2.12.6", "graphql-ws": "^5.8.1", "highland": "^2.13.5", - "isolated-vm": "^4.6.0", + "isolated-vm": "^5.0.3", "jest-environment-jsdom": "^29.7.0", "mali": "^0.46.1", "ngrok": "^4.3.1", "node-fetch": "^3.3.0", + "node-gyp": "^11.0.0", "npm": "^8.7.0", "patch-package": "^6.4.7", "path": "^0.12.7", @@ -572,4 +573,3 @@ } ] } - diff --git a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx index cb45e5b61..3bbcb6087 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx @@ -28,6 +28,7 @@ export default function WebRTCComposer() { const [showRTCEntryForms, setShowRTCEntryForms] = useState(false); // Builds ReqRes object from properties in NewRequest + const composeReqRes = (): ReqRes => { return { id: uuid(), @@ -87,6 +88,7 @@ export default function WebRTCComposer() { style={{ overflowX: 'hidden' }} > + {showRTCEntryForms && ( <> diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 0145b8fc9..db0e05ea3 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -34,7 +34,7 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { { dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCOffer: value }) @@ -82,6 +82,7 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { className="button is-normal is-primary-100 add-request-button no-border-please" style={{ margin: '10px' }} onClick={() => { + console.log('newRequestWebRTCfromOclick:', newRequestWebRTC); webrtcPeerController.createOffer(newRequestWebRTC); }} > @@ -138,16 +139,29 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { Paste {/* ANSWER BUTTON IS WORK-IN-PROGRESS */} - {/* */} + + + {/* {warningMessage ?
{warningMessage.body}
: null} */} diff --git a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx index d9a8c29b1..61f72532f 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx @@ -131,6 +131,7 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { className="ml-1 is-rest button no-border-please" onClick={() => { setShowRTCEntryForms(true); + console.log('newRequestWebRTCFromCclick:', newRequestWebRTC); webrtcPeerController.createPeerConnection(newRequestWebRTC); }} > diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 626529729..18bb789a5 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -16,11 +16,11 @@ const webrtcPeerController = { newRequestWebRTC: RequestWebRTC ): Promise => { let servers = { - iceServers: [ + iceServers: [ { urls: [ - 'stun:stun1.1.google.com:19302', - 'stun:stun2.1.google.com:19302', + 'stun:stun.l.google.com:19302', + 'stun:stun.l.google.com:5349', ], }, ], @@ -73,7 +73,9 @@ const webrtcPeerController = { let localStream = peerConnection.createDataChannel('textChannel'); localStream.onopen = () => console.log('data channel opened'); localStream.onclose = () => console.log('data channel closed') - + console.log('peerConnection:', peerConnection) + console.log('localstream:', localStream) + console.log('newRequestWebRTCcheck:', newRequestWebRTC) appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, @@ -81,34 +83,53 @@ const webrtcPeerController = { webRTCLocalStream: localStream, }) ); - + peerConnection.onicecandidate = async ( event: RTCPeerConnectionIceEvent ): Promise => { + console.log('event:', event) if (event.candidate) { appDispatch( - newRequestWebRTCOfferSet( + newRequestWebRTCOfferSet( // newRequestWebRTCOfferSet mutates the newRequestWebRTC.webrtcOffer state JSON.stringify(peerConnection.localDescription) ) ); } + console.log('newRequestWebRTCCheck4:', newRequestWebRTC) }; + } }, createOffer: async (newRequestWebRTC: RequestWebRTC): Promise => { //grab the peer connection off the state to manipulate further + console.log('newRequestWebRTCCheck2:', newRequestWebRTC) let { webRTCpeerConnection } = newRequestWebRTC; + console.log('webRTCPeerConnect:', webRTCpeerConnection) let offer = await webRTCpeerConnection!.createOffer(); - await webRTCpeerConnection!.setLocalDescription(offer); + console.log('offer:', offer) + await webRTCpeerConnection!.setLocalDescription(offer); //what is this line doing that is not already done? + console.log('webRTCaftersetofLocalDes:', webRTCpeerConnection) appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCOffer: JSON.stringify(offer), }) ); + console.log('newRequestWebRTCCheck3:', newRequestWebRTC) }, + // need to include methodology to send offer to other peer + + // also need to send ice candidate to other peer + + // Ability to receive offer and candidate from other peer (using websockets) + + // peer should be able to accept offer and candidate + // peer should be able to set the offer received as the remote description + + + // work-in-progress createAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { let { webRTCpeerConnection, webRTCOffer } = newRequestWebRTC; @@ -121,12 +142,13 @@ const webrtcPeerController = { let answer = await webRTCpeerConnection.createAnswer(); await webRTCpeerConnection.setLocalDescription(answer); - appDispatch( + appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: JSON.stringify(answer), }) ); + console.log('newRequestWebRTCCheck5:', newRequestWebRTC) }, addAnswer: async (reqRes: ReqRes): Promise => { diff --git a/src/server/server.js b/src/server/server.js index fa07fd840..e7b03a62c 100644 --- a/src/server/server.js +++ b/src/server/server.js @@ -6,7 +6,7 @@ const cookieParser = require('cookie-parser'); const crypto = require('crypto'); dotenv.config(); -const port = 3000; +const port = 3001; const app = express(); const cors = require('cors'); app.use(express.urlencoded({ extended: true })); diff --git a/webpack.config.js b/webpack.config.js index c31f08d20..a336f60ca 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -129,8 +129,8 @@ module.exports = { 'base-uri': ["'self'"], 'default-src': [ "'self'", - 'http://localhost:3000', - 'ws://localhost:3000', + 'http://localhost:3001', + 'ws://localhost:3001', 'https://api.github.com', "'unsafe-inline'", "'unsafe-eval'", diff --git a/webpack.development.js b/webpack.development.js index 1b734d578..68efd2592 100644 --- a/webpack.development.js +++ b/webpack.development.js @@ -13,16 +13,16 @@ module.exports = merge(base, { compress: true, proxy: { '/webhookServer': { - target: 'http://localhost:3000', + target: 'http://localhost:3001', }, '/webhook': { - target: 'http://localhost:3000', + target: 'http://localhost:3001', }, '/api': { - target: 'http://localhost:3000', + target: 'http://localhost:3001', /** * @todo Change secure option to true, and refactor code to account for - * change + * change // https://github.com/electron/electron/issues/19775 ??? maybe this is the solution */ secure: false, }, @@ -31,6 +31,7 @@ module.exports = merge(base, { if (!devServer) { throw new Error('webpack-dev-server is not defined'); } + console.log('Setting up middlewares...:', middlewares); middlewares.unshift({ // unshift does not work, ends in infinite calls to this function name: 'run-in-electron', From e4dbac8eae5334989fca76d8a1c6553d87f8a4ce Mon Sep 17 00:00:00 2001 From: Gilgamesh Date: Fri, 24 Jan 2025 15:04:59 -0500 Subject: [PATCH 02/47] positioning of add answer --- .../main/WebRTC-composer/WebRTCComposer.tsx | 1 + .../WebRTC-composer/WebRTCServerEntryForm.tsx | 26 ++++++++++--------- .../controllers/webrtcPeerController.ts | 4 ++- webpack.development.js | 2 +- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx index 3bbcb6087..2d0a5fa00 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx @@ -63,6 +63,7 @@ export default function WebRTCComposer() { } const addNewRequest = (): void => { + console.log('newRequestWebRTCatANR:', newRequestWebRTC) if (!(checkValidSDP(newRequestWebRTC.webRTCOffer) && checkValidSDP(newRequestWebRTC.webRTCAnswer))){ return alert('Invalid offer or answer SDP') } diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index db0e05ea3..7752b6916 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -88,6 +88,19 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { > Get Offer + + + {/* Code box for Answer */}
@@ -139,17 +152,6 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { Paste {/* ANSWER BUTTON IS WORK-IN-PROGRESS */} - - {/* ANSWER BUTTON IS WORK-IN-PROGRESS */} +
); }; - +// update export default WebRTCTextContainer; From de251d6997a1220234c2d5cc5db6e19b33dfa647 Mon Sep 17 00:00:00 2001 From: Gilgamesh Date: Tue, 4 Feb 2025 10:02:36 -0500 Subject: [PATCH 11/47] Modified datachannel.onmessage event --- .../controllers/webrtcPeerController.ts | 50 ++++--------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index ef1a049c3..695ce5d69 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -79,10 +79,13 @@ const webrtcPeerController = { let localStream = peerConnection.createDataChannel('textChannel'); localStream.onopen = () => console.log('data channel opened!!!'); localStream.onclose = () => console.log('data channel closed :(') - localStream.onmessage = (event) => {console.log('message received:', event.data)}; - console.log('peerConnection:', peerConnection) - console.log('localstream:', localStream) - console.log('newRequestWebRTCcheck:', newRequestWebRTC) + + peerConnection.ondatachannel = (event) => { + const receiveChannel = event.channel; + receiveChannel.onmessage = (event) => {console.log('message received:', event.data)}; + }; + // console.log('peerConnection:', peerConnection) + // console.log('localstream:', localStream) appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, @@ -95,14 +98,12 @@ const webrtcPeerController = { peerConnection.onicecandidate = async ( event: RTCPeerConnectionIceEvent ): Promise => { - console.log('event:', event) if (event.candidate) { appDispatch( newRequestWebRTCOfferSet( JSON.stringify(peerConnection.localDescription) ) ); - // peerConnection.addIceCandidate(event.candidate) console.log('eventIceCandidate:', event.candidate.candidate) } @@ -128,18 +129,6 @@ const webrtcPeerController = { console.log('newRequestWebRTCCheckAfterOffer:', newRequestWebRTC) }, - // need to include methodology to send offer to other peer - - // also need to send ice candidate to other peer - - // Ability to receive offer and candidate from other peer (using websockets) - - // peer should be able to accept offer and candidate - // peer should be able to set the offer received as the remote description - - - - // work-in-progress ,,, this function is for the situation you are peer 2 and you receive an offer from peer 1 createAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { let { webRTCpeerConnection, webRTCOffer } = newRequestWebRTC; @@ -161,25 +150,16 @@ const webrtcPeerController = { addAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { let { webRTCpeerConnection } = newRequestWebRTC; - // console.log('webRtcPeerConnect:', webRTCpeerConnection) - // webRTCpeerConnection!.setRemoteDescription( - // JSON.parse(webRTCpeerConnection.webRTCAnswer) - // ); let answer = JSON.parse(newRequestWebRTC.webRTCAnswer); await webRTCpeerConnection!.setRemoteDescription(answer); - // appDispatch( - // newRequestWebRTCSet({ - // ...newRequestWebRTC, - // webRTCAnswer: JSON.stringify(answer), - // }) - // ); }, sendMessages: async (reqRes: ReqRes, messages: string): Promise => { let { request } = reqRes as { request: RequestWebRTCText }; - - - await (request).webRTCLocalStream!.send( + console.log('im here too'); + console.log('request from mesaages :', request); + + (request).webRTCLocalStream!.send( JSON.stringify({ data: messages }) ); }, @@ -249,14 +229,6 @@ const webrtcPeerController = { }; } }, - - sendText: async (reqRes: ReqRes): Promise => { - // let { request } = reqRes as { request: RequestWebRTCText }; - // let message = (request).webRTCLocalStream!.send( - // JSON.stringify({ data: 'hello' }) - // ); - - } }; From ac43ed4a5baac9ed44d03c33a271475925fa3e26 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 6 Feb 2025 14:55:28 -0500 Subject: [PATCH 12/47] fixed double-answer and answer in offer text box bug --- .../controllers/webrtcPeerController.ts | 73 ++++++++++--------- .../slices/newRequestSlice.ts | 11 ++- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 695ce5d69..3a7ca9cf9 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -2,6 +2,7 @@ import store, { appDispatch } from '../toolkit-refactor/store'; import { newRequestWebRTCSet, newRequestWebRTCOfferSet, + newRequestWebRTCAnswerSet, } from '../toolkit-refactor/slices/newRequestSlice'; import { ReqRes, @@ -20,12 +21,9 @@ const webrtcPeerController = { newRequestWebRTC: RequestWebRTC ): Promise => { let servers = { - iceServers: [ + iceServers: [ { - urls: [ - 'stun:stun.l.google.com:19302', - 'stun:stun.l.google.com:5349', - ], + urls: ['stun:stun.l.google.com:19302', 'stun:stun.l.google.com:5349'], }, ], }; @@ -36,7 +34,7 @@ const webrtcPeerController = { video: true, audio: false, }); - + if (document.getElementById('localstream')) { (document.getElementById('localstream')).srcObject = localStream; @@ -65,24 +63,32 @@ const webrtcPeerController = { peerConnection.onicecandidate = async ( event: RTCPeerConnectionIceEvent ): Promise => { - if (event.candidate) { + if (event.candidate && peerConnection.localDescription!.type === 'offer') { appDispatch( newRequestWebRTCOfferSet( - JSON.stringify(peerConnection.localDescription) + JSON.stringify(peerConnection.localDescription) + ) + ); + } else if (event.candidate && peerConnection.localDescription!.type === 'answer') { + appDispatch( + newRequestWebRTCAnswerSet( + JSON.stringify(peerConnection.localDescription) ) ); } }; } else if (newRequestWebRTC.webRTCDataChannel === 'Text') { - // + // let localStream = peerConnection.createDataChannel('textChannel'); localStream.onopen = () => console.log('data channel opened!!!'); - localStream.onclose = () => console.log('data channel closed :(') - + localStream.onclose = () => console.log('data channel closed :('); + peerConnection.ondatachannel = (event) => { const receiveChannel = event.channel; - receiveChannel.onmessage = (event) => {console.log('message received:', event.data)}; + receiveChannel.onmessage = (event) => { + console.log('message received:', event.data); + }; }; // console.log('peerConnection:', peerConnection) // console.log('localstream:', localStream) @@ -93,40 +99,44 @@ const webrtcPeerController = { webRTCLocalStream: localStream, }) ); - - + peerConnection.onicecandidate = async ( event: RTCPeerConnectionIceEvent ): Promise => { - if (event.candidate) { + if (event.candidate && peerConnection.localDescription!.type === 'offer') { //debugged appDispatch( newRequestWebRTCOfferSet( + //should we be adding a ...peerConnection here spreading out the rest of the peerConnection object? also why isn't this updating the newWebRTCRequest object? + JSON.stringify(peerConnection.localDescription) + ) + ); + } else if (event.candidate && peerConnection.localDescription!.type === 'answer') {//added this plus an answerSet reducer so the answer wasn't populating both the answer and offer text boxes (and being two different versions of the answer at that) + appDispatch( + newRequestWebRTCAnswerSet( JSON.stringify(peerConnection.localDescription) ) ); - console.log('eventIceCandidate:', event.candidate.candidate) - } }; - } }, // what in create offer triggers the ice candidate to be sent? createOffer: async (newRequestWebRTC: RequestWebRTC): Promise => { //grab the peer connection off the state to manipulate further let { webRTCpeerConnection } = newRequestWebRTC; - console.log('webRTCPeerConnect:', webRTCpeerConnection) + console.log('webRTCPeerConnect:', webRTCpeerConnection); let offer = await webRTCpeerConnection!.createOffer(); - console.log('offer:', offer) + console.log('offer:', offer); await webRTCpeerConnection!.setLocalDescription(offer); //what is this line doing that is not already done? - console.log('webRTCaftersetofLocalDes:', webRTCpeerConnection) + console.log('webRTCaftersetofLocalDes:', webRTCpeerConnection); appDispatch( - newRequestWebRTCSet({ // newRequestWebRTCSet mutates the newRequestWebRTC state to have the offer + newRequestWebRTCSet({ + // newRequestWebRTCSet mutates the newRequestWebRTC state to have the offer ...newRequestWebRTC, webRTCOffer: JSON.stringify(offer), }) ); - console.log('newRequestWebRTCCheckAfterOffer:', newRequestWebRTC) + console.log('newRequestWebRTCCheckAfterOffer:', newRequestWebRTC); }, createAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { @@ -140,12 +150,13 @@ const webrtcPeerController = { let answer = await webRTCpeerConnection.createAnswer(); await webRTCpeerConnection.setLocalDescription(answer); - appDispatch( + appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: JSON.stringify(answer), }) ); + console.log('newRequestWebRTCCheckAfterAnswer:', newRequestWebRTC); }, addAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { @@ -158,14 +169,12 @@ const webrtcPeerController = { let { request } = reqRes as { request: RequestWebRTCText }; console.log('im here too'); console.log('request from mesaages :', request); - + (request).webRTCLocalStream!.send( JSON.stringify({ data: messages }) ); }, - - dataStream: async (reqRes: ReqRes): Promise => { let { request, response } = reqRes as { request: RequestWebRTC; @@ -211,11 +220,10 @@ const webrtcPeerController = { let state = store.getState(); if (state.reqRes.currentResponse.response) { - let newWebRTCMessages = - (state.reqRes.currentResponse.response).webRTCMessages.concat( - messageObject - ); - let request = state.reqRes.currentResponse.request + let newWebRTCMessages = (( + state.reqRes.currentResponse.response + )).webRTCMessages.concat(messageObject); + let request = state.reqRes.currentResponse.request; appDispatch( responseDataSaved({ ...reqRes, @@ -229,7 +237,6 @@ const webrtcPeerController = { }; } }, - }; export default webrtcPeerController; diff --git a/src/client/toolkit-refactor/slices/newRequestSlice.ts b/src/client/toolkit-refactor/slices/newRequestSlice.ts index 09f8d5515..d9885e905 100644 --- a/src/client/toolkit-refactor/slices/newRequestSlice.ts +++ b/src/client/toolkit-refactor/slices/newRequestSlice.ts @@ -30,7 +30,6 @@ type NewRequestStore = { newRequestBody: NewRequestBody; newRequestSSE: NewRequestSSE; newRequestWebRTC: RequestWebRTC; - }; const initialState: NewRequestStore = { @@ -47,7 +46,7 @@ const initialState: NewRequestStore = { bodyIsNew: false, }, newRequestStreams: { - streamsArr: [], + streamsArr: [], count: 0, streamContent: [], selectedPackage: null, @@ -79,7 +78,7 @@ const initialState: NewRequestStore = { webRTCLocalStream: null, webRTCRemoteStream: null, webRTCMessages: [], - } + }, }; const newRequestSlice = createSlice({ @@ -101,11 +100,16 @@ const newRequestSlice = createSlice({ newRequestWebRTCSet: (state, action: PayloadAction) => { state.newRequestWebRTC = action.payload; + // console.log('newRequestWebRTCCheckAfterAnswerInReducer:', state.newRequestWebRTC.webRTCAnswer); }, newRequestWebRTCOfferSet: (state, action: PayloadAction) => { state.newRequestWebRTC.webRTCOffer = action.payload; }, + newRequestWebRTCAnswerSet: (state, action: PayloadAction) => { + state.newRequestWebRTC.webRTCAnswer = action.payload; + }, + //add one for answer //Before toolkit conversion was SET_NEW_REQUEST_STREAMS or setNewRequestStreams newRequestStreamsSet: (state, action: PayloadAction) => { @@ -188,6 +192,7 @@ export const { newRequestContentByProtocol, newRequestWebRTCSet, newRequestWebRTCOfferSet, + newRequestWebRTCAnswerSet, } = newRequestSlice.actions; export default newRequestSlice.reducer; From 2073521b6c3cb85116a2739caf8c8dd2b4269e35 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Thu, 6 Feb 2025 16:02:55 -0500 Subject: [PATCH 13/47] update --- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 67 +++++++++++-------- .../controllers/webrtcPeerController.ts | 54 +++++++-------- 2 files changed, 62 insertions(+), 59 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index ebb77b9fe..d5b0650eb 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -8,7 +8,10 @@ import React from 'react'; // import MenuItem from '@mui/material/MenuItem'; import { ReqRes, RequestWebRTC } from '../../../../types'; import TextCodeArea from '../sharedComponents/TextCodeArea'; -import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; +import { + useAppDispatch, + useAppSelector, +} from '../../../toolkit-refactor/hooks'; import { newRequestWebRTCSet } from '../../../toolkit-refactor/slices/newRequestSlice'; import webrtcPeerController from '../../../controllers/webrtcPeerController'; import { RootState } from '../../../toolkit-refactor/store'; @@ -35,12 +38,16 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { { - console.log('value:', value); + console.log('value before dispatch:', value); dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCOffer: value }) ); + console.log( + 'value after dispatch, Im assuming it is the same:', + value + ); }} placeholder={'Click "Get Offer" or paste in Offer SDP'} readOnly={true} @@ -68,15 +75,15 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { width: '58px', }} onClick={() => { - navigator.clipboard.readText().then((text) =>{ + navigator.clipboard.readText().then((text) => { console.log('text:', text); dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCOffer: text, }) - )} - ); + ); + }); }} > Paste @@ -92,18 +99,16 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { Get Offer - - + id="webRTButton" + className="button is-normal is-primary-100 add-request-button no-border-please" + style={{ margin: '10px' }} + onClick={() => { + console.log('newRequestWebRTCfromGAclick:', newRequestWebRTC); + webrtcPeerController.createAnswer(newRequestWebRTC); + }} + > + Get Answer + {/* Code box for Answer */}
@@ -115,6 +120,10 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: value }) ); + console.log( + 'newRequestWebRTC (though may not be updated bc async):', + newRequestWebRTC + ); }} placeholder={'Answer here'} readOnly={true} @@ -155,17 +164,17 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { Paste - + {/* {warningMessage ?
{warningMessage.body}
: null} */}
diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 695ce5d69..53a641e01 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -20,12 +20,9 @@ const webrtcPeerController = { newRequestWebRTC: RequestWebRTC ): Promise => { let servers = { - iceServers: [ + iceServers: [ { - urls: [ - 'stun:stun.l.google.com:19302', - 'stun:stun.l.google.com:5349', - ], + urls: ['stun:stun.l.google.com:19302', 'stun:stun.l.google.com:5349'], }, ], }; @@ -36,7 +33,7 @@ const webrtcPeerController = { video: true, audio: false, }); - + if (document.getElementById('localstream')) { (document.getElementById('localstream')).srcObject = localStream; @@ -74,15 +71,17 @@ const webrtcPeerController = { } }; } else if (newRequestWebRTC.webRTCDataChannel === 'Text') { - // + // let localStream = peerConnection.createDataChannel('textChannel'); localStream.onopen = () => console.log('data channel opened!!!'); - localStream.onclose = () => console.log('data channel closed :(') - + localStream.onclose = () => console.log('data channel closed :('); + peerConnection.ondatachannel = (event) => { const receiveChannel = event.channel; - receiveChannel.onmessage = (event) => {console.log('message received:', event.data)}; + receiveChannel.onmessage = (event) => { + console.log('message received:', event.data); + }; }; // console.log('peerConnection:', peerConnection) // console.log('localstream:', localStream) @@ -93,8 +92,7 @@ const webrtcPeerController = { webRTCLocalStream: localStream, }) ); - - + peerConnection.onicecandidate = async ( event: RTCPeerConnectionIceEvent ): Promise => { @@ -104,29 +102,28 @@ const webrtcPeerController = { JSON.stringify(peerConnection.localDescription) ) ); - console.log('eventIceCandidate:', event.candidate.candidate) - + console.log('eventIceCandidate:', event.candidate.candidate); } }; - } }, // what in create offer triggers the ice candidate to be sent? createOffer: async (newRequestWebRTC: RequestWebRTC): Promise => { //grab the peer connection off the state to manipulate further let { webRTCpeerConnection } = newRequestWebRTC; - console.log('webRTCPeerConnect:', webRTCpeerConnection) + console.log('webRTCPeerConnect:', webRTCpeerConnection); let offer = await webRTCpeerConnection!.createOffer(); - console.log('offer:', offer) + console.log('offer:', offer); await webRTCpeerConnection!.setLocalDescription(offer); //what is this line doing that is not already done? - console.log('webRTCaftersetofLocalDes:', webRTCpeerConnection) + console.log('webRTCaftersetofLocalDes:', webRTCpeerConnection); appDispatch( - newRequestWebRTCSet({ // newRequestWebRTCSet mutates the newRequestWebRTC state to have the offer + newRequestWebRTCSet({ + // newRequestWebRTCSet mutates the newRequestWebRTC state to have the offer ...newRequestWebRTC, webRTCOffer: JSON.stringify(offer), }) ); - console.log('newRequestWebRTCCheckAfterOffer:', newRequestWebRTC) + console.log('newRequestWebRTCCheckAfterOffer:', newRequestWebRTC); }, createAnswer: async (newRequestWebRTC: RequestWebRTC): Promise => { @@ -138,9 +135,10 @@ const webrtcPeerController = { await webRTCpeerConnection.setRemoteDescription(offer); let answer = await webRTCpeerConnection.createAnswer(); + console.log('answer:', answer); await webRTCpeerConnection.setLocalDescription(answer); - appDispatch( + appDispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: JSON.stringify(answer), @@ -158,14 +156,12 @@ const webrtcPeerController = { let { request } = reqRes as { request: RequestWebRTCText }; console.log('im here too'); console.log('request from mesaages :', request); - + (request).webRTCLocalStream!.send( JSON.stringify({ data: messages }) ); }, - - dataStream: async (reqRes: ReqRes): Promise => { let { request, response } = reqRes as { request: RequestWebRTC; @@ -211,11 +207,10 @@ const webrtcPeerController = { let state = store.getState(); if (state.reqRes.currentResponse.response) { - let newWebRTCMessages = - (state.reqRes.currentResponse.response).webRTCMessages.concat( - messageObject - ); - let request = state.reqRes.currentResponse.request + let newWebRTCMessages = (( + state.reqRes.currentResponse.response + )).webRTCMessages.concat(messageObject); + let request = state.reqRes.currentResponse.request; appDispatch( responseDataSaved({ ...reqRes, @@ -229,7 +224,6 @@ const webrtcPeerController = { }; } }, - }; export default webrtcPeerController; From 5ab39eb20f5c0784a2c82f5671e764c09c781a0e Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Tue, 11 Feb 2025 00:42:50 -0500 Subject: [PATCH 14/47] togglerefreshbuttons Co-authored-by: Rachel Dean --- package.json | 1 + src/assets/style/WebRtc.css | 92 ++++++++++++++ .../main/WebRTC-composer/WebRTCComposer.tsx | 1 - .../WebRTC-composer/WebRTCServerEntryForm.tsx | 34 +++++ .../WebRTCSessionEntryForm.tsx | 120 +++++++++++------- .../WebRTCTextContainer.tsx | 1 - .../main/sharedComponents/TextCodeArea.tsx | 3 + .../controllers/webrtcPeerController.ts | 51 +++++--- src/types.ts | 19 ++- 9 files changed, 253 insertions(+), 69 deletions(-) create mode 100644 src/assets/style/WebRtc.css diff --git a/package.json b/package.json index 501d12bb3..8c9ba0d36 100644 --- a/package.json +++ b/package.json @@ -155,6 +155,7 @@ "react-dom": "^18.0.0", "react-dropzone": "^12.1.0", "react-github-btn": "^1.2.2", + "react-icons": "^5.4.0", "react-redux": "^8.0.1", "react-router-dom": "^6.3.0", "react-split": "^2.0.14", diff --git a/src/assets/style/WebRtc.css b/src/assets/style/WebRtc.css new file mode 100644 index 000000000..61c44fec2 --- /dev/null +++ b/src/assets/style/WebRtc.css @@ -0,0 +1,92 @@ +.toggle-refresh-container { + display: flex; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +.refresh-button { + width: 70px; + height: 40px; + border-radius: 60px; + border-style: none; + background-color: #ccc; +} + +.refresh-button:hover { + box-shadow: 0px 6px 6px rgba(0, 0, 0, 0.5); +} + +.Audio-Toggle-Container { + display: flex; + justify-content: flex-start; + align-items: center; + gap: 10px; + padding-bottom: 5px; +} + +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +.slider:before { + position: absolute; + content: ''; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +input:checked + .slider { + background-color: #ccc; +} + +input:focus + .slider { + box-shadow: 0 0 1px #ccc; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +.slider.round { + border-radius: 10px; +} + +.slider.round:before { + border-radius: 50%; +} + +.is-3rem-footer.is-clickable.is-margin-top-auto { + display: flex; + justify-content: flex-end; + padding: 0; +} + diff --git a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx index a814b9eea..e0d5fccb0 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx @@ -28,7 +28,6 @@ export default function WebRTCComposer() { const [showRTCEntryForms, setShowRTCEntryForms] = useState(false); // Builds ReqRes object from properties in NewRequest - const composeReqRes = (): ReqRes => { return { id: uuid(), diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index d5b0650eb..6b1b63a12 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { useState } from 'react'; +import { MdRefresh } from 'react-icons/md'; + +// import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; +import '../../../../assets/style/WebRtc.css'; + // import dropDownArrow from '../../../../assets/icons/arrow_drop_down_white_192x192.png'; // import CodeMirror from '@uiw/react-codemirror'; // import { EditorView } from '@codemirror/view'; @@ -27,6 +33,8 @@ interface Props { } const WebRTCServerEntryForm: React.FC = (props: Props) => { + const [isToggled, setIsToggled] = useState(false); + const dispatch = useAppDispatch(); const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC @@ -34,6 +42,31 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { return (
+
+
+ + Audio + + +
+
+ +
+
= (props: Props) => { mode={'application/json'} value={newRequestWebRTC.webRTCAnswer || ''} height={'85px'} + width={'100%'} onChange={(value, viewUpdate) => { dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: value }) diff --git a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx index 24fe09be6..18800562e 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx @@ -1,9 +1,11 @@ import React, { useState } from 'react'; -import { NewRequestWebRTCSet, RequestWebRTC } from '../../../../types'; +import { NewRequestWebRTCSet, RequestWebRTC, ReqRes } from '../../../../types'; import webrtcPeerController from '../../../controllers/webrtcPeerController'; - import dropDownArrow from '../../../../assets/icons/arrow_drop_down_white_192x192.png'; -import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; +import { + useAppDispatch, + useAppSelector, +} from '../../../toolkit-refactor/hooks'; import { newRequestWebRTCSet } from '../../../toolkit-refactor/slices/newRequestSlice'; import { RootState } from '../../../toolkit-refactor/store'; @@ -16,15 +18,20 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC ); + const currentReqRes = useAppSelector( + (store: RootState) => store.reqRes.currentResponse + ) as ReqRes; - const isDark = useAppSelector((store: { ui: { isDark: boolean }}) => store.ui.isDark); + const isDark = useAppSelector( + (store: { ui: { isDark: boolean } }) => store.ui.isDark + ); const { setShowRTCEntryForms } = props; const [entryTypeDropdownIsActive, setEntryTypeDropdownIsActive] = useState(false); const [dataTypeDropdownIsActive, setDataTypeDropdownIsActive] = useState(false); - + // may have to have a connect button for peer 1 and a different one for peer 2 // this is because peer 2 does not need to create a data channel, rather they receive one from peer 1 @@ -63,10 +70,12 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { {newRequestWebRTC.webRTCEntryMode !== 'Manual' && ( { - dispatch(newRequestWebRTCSet({ - ...newRequestWebRTC, - webRTCEntryMode: 'Manual', - })); + dispatch( + newRequestWebRTCSet({ + ...newRequestWebRTC, + webRTCEntryMode: 'Manual', + }) + ); setEntryTypeDropdownIsActive(false); }} className="dropdown-item" @@ -78,10 +87,12 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { {newRequestWebRTC.webRTCEntryMode !== 'WS' && ( { - dispatch(newRequestWebRTCSet({ - ...newRequestWebRTC, - webRTCEntryMode: 'WS', - })); + dispatch( + newRequestWebRTCSet({ + ...newRequestWebRTC, + webRTCEntryMode: 'WS', + }) + ); setEntryTypeDropdownIsActive(false); }} className="dropdown-item" @@ -93,8 +104,8 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => {
= (props: Props) => { className="ml-1 is-rest button no-border-please" onClick={() => { setShowRTCEntryForms(true); - console.log('newRequestWebRTCFromConnect:', { newRequestWebRTC: newRequestWebRTC }); - webrtcPeerController.createPeerConnection(newRequestWebRTC); + console.log('newRequestWebRTCFromConnect:', { + newRequestWebRTC: newRequestWebRTC, + }); + webrtcPeerController.createPeerConnection( + newRequestWebRTC, + currentReqRes + ); }} > Connect @@ -144,49 +160,57 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { ); -} \ No newline at end of file +} diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 6b1b63a12..869bd3e0d 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -44,26 +44,33 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => {
- - Audio - - + {newRequestWebRTC.webRTCDataChannel === 'Video' && ( + <> + + Audio + + + + )}
+
From 781580c526230b4438bf7e407d1c576ba2650df2 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Tue, 11 Feb 2025 11:16:11 -0500 Subject: [PATCH 16/47] added reducer for reset, started building it into react component in webRTCServerEntryForm --- .../main/WebRTC-composer/WebRTCServerEntryForm.tsx | 7 ++++++- src/client/toolkit-refactor/slices/newRequestSlice.ts | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 6b1b63a12..3e53b6262 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -18,6 +18,7 @@ import { useAppDispatch, useAppSelector, } from '../../../toolkit-refactor/hooks'; +import { resetWebRTCconnection } from '../../../toolkit-refactor/slices/newRequestSlice.ts'; import { newRequestWebRTCSet } from '../../../toolkit-refactor/slices/newRequestSlice'; import webrtcPeerController from '../../../controllers/webrtcPeerController'; import { RootState } from '../../../toolkit-refactor/store'; @@ -39,6 +40,10 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC ); + const handleResetWebRTCconnection = () => { + dispatch(resetWebRTCconnection()); + console.log('WebRTC connection reset to initial state:'); + } return (
@@ -62,7 +67,7 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => {
-
diff --git a/src/client/toolkit-refactor/slices/newRequestSlice.ts b/src/client/toolkit-refactor/slices/newRequestSlice.ts index d9885e905..308c2e062 100644 --- a/src/client/toolkit-refactor/slices/newRequestSlice.ts +++ b/src/client/toolkit-refactor/slices/newRequestSlice.ts @@ -109,7 +109,9 @@ const newRequestSlice = createSlice({ state.newRequestWebRTC.webRTCAnswer = action.payload; }, - //add one for answer + resetWebRTCconnection: () => { + return initialState; + }, //Before toolkit conversion was SET_NEW_REQUEST_STREAMS or setNewRequestStreams newRequestStreamsSet: (state, action: PayloadAction) => { @@ -193,6 +195,7 @@ export const { newRequestWebRTCSet, newRequestWebRTCOfferSet, newRequestWebRTCAnswerSet, + resetWebRTCconnection, } = newRequestSlice.actions; export default newRequestSlice.reducer; From 7b3b220f9aaa1b985d085cd83a9d8ac8475c89a6 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Tue, 11 Feb 2025 14:21:41 -0500 Subject: [PATCH 17/47] toggle functionality test --- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 23 ++++++++++++++----- .../controllers/webrtcPeerController.ts | 9 +++++++- src/types.ts | 13 ++++++----- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 869bd3e0d..4cdb953e3 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { useState } from 'react'; +import React, { useState } from 'react'; import { MdRefresh } from 'react-icons/md'; // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; @@ -32,13 +31,25 @@ interface Props { // } | null; } -const WebRTCServerEntryForm: React.FC = (props: Props) => { - const [isToggled, setIsToggled] = useState(false); - +const WebRTCServerEntryForm: React.FC = () => { const dispatch = useAppDispatch(); + const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC ); + const [isToggled, setIsToggled] = useState(false); + + const handleToggleChange = () => { + const newToggleState = !isToggled; + setIsToggled(newToggleState); + + dispatch( + newRequestWebRTCSet({ + ...newRequestWebRTC, + enableAudio: newToggleState, + }) + ); + }; return (
@@ -58,7 +69,7 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { setIsToggled(!isToggled)} + onChange={handleToggleChange} /> => { + const enableAudio = + newRequestWebRTC.webRTCDataChannel === 'Video' + ? newRequestWebRTC.enableAudio ?? false + : false; + let servers = { iceServers: [ { @@ -30,7 +36,7 @@ const webrtcPeerController = { if (newRequestWebRTC.webRTCDataChannel === 'Video') { let localStream = await navigator.mediaDevices.getUserMedia({ video: true, - audio: false, + audio: enableAudio, }); if (document.getElementById('localstream')) { @@ -55,6 +61,7 @@ const webrtcPeerController = { webRTCpeerConnection: peerConnection, webRTCLocalStream: localStream, webRTCRemoteStream: remoteStream, + enableAudio, }) ); diff --git a/src/types.ts b/src/types.ts index 526e47dd1..b843d68f6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -324,12 +324,11 @@ export type ResponseWebRTC = ResponseWebRTCText; export interface ResponseWebRTCText { webRTCMessages: WebMessages[]; } - -export type RequestWebRTC = - | RequestWebRTCVideo - | RequestWebRTCText - | RequestWebRTCAudio; - +//Defines web rtc request type that can be audio video or text +//enable audio is a shared but optional property +export type RequestWebRTC = { + enableAudio?: boolean; +} & (RequestWebRTCVideo | RequestWebRTCText | RequestWebRTCAudio); export interface RequestWebRTCVideo { network: 'webrtc'; webRTCEntryMode: 'Manual' | 'WS'; @@ -340,6 +339,7 @@ export interface RequestWebRTCVideo { webRTCpeerConnection: RTCPeerConnection | null; webRTCLocalStream: MediaStream | null; webRTCRemoteStream: MediaStream | null; + enableAudio?: boolean; } export interface RequestWebRTCAudio { @@ -352,6 +352,7 @@ export interface RequestWebRTCAudio { webRTCpeerConnection: RTCPeerConnection | null; webRTCLocalStream: MediaStream | null; webRTCRemoteStream: MediaStream | null; + enableAudio?: boolean; } export interface RequestWebRTCText { From b6ced880eb1b5b4760be77dce9605b17720f2528 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Tue, 11 Feb 2025 15:30:45 -0500 Subject: [PATCH 18/47] functioning refresh button, useEffect and useRef additions, used code from Connect button; need to check some bugs switching between types of media having offer text persist between types. Co-authored-by: Kiki Hunt Co-authored by: Rachel Dean --- src/assets/style/WebRtc.css | 2 +- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/assets/style/WebRtc.css b/src/assets/style/WebRtc.css index 8fcd8cd45..2cd66aaea 100644 --- a/src/assets/style/WebRtc.css +++ b/src/assets/style/WebRtc.css @@ -11,7 +11,7 @@ height: 40px; border-radius: 30px; border-style: none; - background-color: #ccc; + background-color: #58a4b0; } .refresh-button:hover { diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 3d198bc09..9ed04a426 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useState } from 'react'; +import { useState, useRef, useEffect } from 'react'; import { MdRefresh } from 'react-icons/md'; // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; @@ -39,7 +39,12 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC ); - // const currentReqRes = {}; + const currentReqRes = useAppSelector( + (store: RootState) => store.reqRes.currentResponse + ) as ReqRes; + + const hasResetRef = useRef(false); + const handleResetWebRTCconnection = () => { dispatch(resetWebRTCconnection()); @@ -47,11 +52,17 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { console.log('newRequestWebRTCFromConnect:', { newRequestWebRTC: newRequestWebRTC, // This will be the empty reset state }); - webrtcPeerController.createPeerConnection(newRequestWebRTC, // fix this after tech talk - // currentReqRes - ); + hasResetRef.current = true; } + useEffect(() => {// so we only trigger a new peer connection here for the reset if the offer has been cleared specifically via our reset function + if (hasResetRef.current && newRequestWebRTC.webRTCOffer === '') { + console.log('Creating a new Peer Connection with reset state'); + webrtcPeerController.createPeerConnection(newRequestWebRTC, currentReqRes); + hasResetRef.current = false; + } + }, [newRequestWebRTC, currentReqRes]); + return (
From d227104b0f45b1b6d28d21d8a2b84d718f547397 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Tue, 11 Feb 2025 15:32:13 -0500 Subject: [PATCH 19/47] audio toggle beta --- .../main/WebRTC-composer/WebRTCSessionEntryForm.tsx | 1 + src/client/controllers/webrtcPeerController.ts | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx index 18800562e..e195cdc4d 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx @@ -186,6 +186,7 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, + enableAudio: newRequestWebRTC.enableAudio ?? false, webRTCDataChannel: 'Video', } as RequestWebRTC) ); diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 7839a46fc..a3ad0ef70 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -18,11 +18,8 @@ const webrtcPeerController = { createPeerConnection: async ( newRequestWebRTC: RequestWebRTC, currentReqRes: ReqRes - ): Promise => { - const enableAudio = - newRequestWebRTC.webRTCDataChannel === 'Video' - ? newRequestWebRTC.enableAudio ?? false - : false; + ) => { + const enableAudio = newRequestWebRTC.enableAudio ?? false; let servers = { iceServers: [ From 0afe133d66d2af854955a5b7f0193a5f64986791 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Wed, 12 Feb 2025 11:25:07 -0500 Subject: [PATCH 20/47] audio channel beta --- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 27 +++- .../WebRTCSessionEntryForm.tsx | 14 +- src/client/controllers/graphQLController.ts | 9 +- .../controllers/webrtcPeerController.ts | 121 ++++++++++-------- src/types.ts | 4 + 5 files changed, 106 insertions(+), 69 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 4cdb953e3..9c825fc10 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { MdRefresh } from 'react-icons/md'; // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; @@ -40,16 +40,35 @@ const WebRTCServerEntryForm: React.FC = () => { const [isToggled, setIsToggled] = useState(false); const handleToggleChange = () => { + // toggles state os is toggled const newToggleState = !isToggled; setIsToggled(newToggleState); dispatch( + //sends action to redux store + // when dispatched redux store updates state based on action newRequestWebRTCSet({ + //creates action takes object as argument ...newRequestWebRTC, - enableAudio: newToggleState, - }) + enableAudio: newToggleState, //updates Enableaudio property in newRequestWebRTC to match toggle state + }) //enable audio updated every time toggle state changes ); }; + //for testing audio only playback when other flaws are ruled out + const audioRef = useRef(null); + // creates reference html audio element + // where useRef persists values across renders without causing rerenders //initally set to null + // useEffect(() => { + // // play audio when conditions are met + // if (newRequestWebRTC.webRTCLocalStream && audioRef.current) { + // // if local stream and current audio arent null + // console.log('Local Mic Playing...'); + // audioRef.current.srcObject = newRequestWebRTC.webRTCLocalStream; // sets source of media to local stream + // audioRef.current + // .play() + // .catch((e) => console.warn('Electron Autoplay Issue', e)); // attempts to play it + // } // if error indicates it may be an issues with electron audioplayback vs video with audio + // }, [newRequestWebRTCSet.webRTCLocalStream]); // use effect runs whenever local stream changes return (
@@ -69,7 +88,7 @@ const WebRTCServerEntryForm: React.FC = () => { = (props: Props) => {
  • { + // when audio is clicked dispatch( + // dispatches an action to the redux store newRequestWebRTCSet({ - ...newRequestWebRTC, - webRTCDataChannel: 'Audio', + // creates action + ...newRequestWebRTC, // copies properties from newrequest webrtc to a new object + webRTCDataChannel: 'Audio', //updates data channel property audio + enableAudio: true, //overwrites enable audio property on new object } as RequestWebRTC) ); setShowRTCEntryForms(false); @@ -179,14 +183,16 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => {
  • )} - {newRequestWebRTC.webRTCDataChannel !== 'Video' && ( + {newRequestWebRTC.webRTCDataChannel !== 'Video' && ( //conditionally rendered video dropdown + //only displayed if current redux channel doesn equal weRTCDataChannel in redux store
  • { + // when user selects the dropdown dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, - enableAudio: newRequestWebRTC.enableAudio ?? false, + enableAudio: newRequestWebRTC.enableAudio ?? false, // sets audio to value in redux store or webRTCDataChannel: 'Video', } as RequestWebRTC) ); diff --git a/src/client/controllers/graphQLController.ts b/src/client/controllers/graphQLController.ts index c05d5b184..736e13b81 100644 --- a/src/client/controllers/graphQLController.ts +++ b/src/client/controllers/graphQLController.ts @@ -66,14 +66,11 @@ const graphQLController: GqlController = { .then((response) => { if (response.error) { this.handleError(response.reqResObj.error, response.reqResObj); - } - - else this.handleResponse(response.data, response.reqResObj); + } else this.handleResponse(response.data, response.reqResObj); }) .catch((err) => console.log('error in sendGqlToMain', err)); }, - openGraphQLConnectionAndRunCollection(reqResArray: ReqRes[]): void { // initialize response data let index = 0; @@ -105,7 +102,7 @@ const graphQLController: GqlController = { }); const runSingleGraphQLRequest = (reqResObj: ReqRes) => { - reqResObj.response.headers = {}; + reqResObj.response.headers = {}; reqResObj.response.events = []; reqResObj.response.cookies = []; reqResObj.connection = 'open'; @@ -297,7 +294,7 @@ const graphQLController: GqlController = { }; api.send('introspect', JSON.stringify(introspectionObject)); api.receive('introspect-reply', (data: IntrospectionQuery) => { - // console.log(data); + // console.log(data); if (data !== 'Error: Please enter a valid GraphQL API URI') { // formatted for Codemirror hint and lint const clientSchema = buildClientSchema(data); diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index a3ad0ef70..a8a806a7c 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -19,7 +19,7 @@ const webrtcPeerController = { newRequestWebRTC: RequestWebRTC, currentReqRes: ReqRes ) => { - const enableAudio = newRequestWebRTC.enableAudio ?? false; + const enableAudio = newRequestWebRTC.enableAudio ?? false; //if null set to false let servers = { iceServers: [ @@ -32,9 +32,10 @@ const webrtcPeerController = { if (newRequestWebRTC.webRTCDataChannel === 'Video') { let localStream = await navigator.mediaDevices.getUserMedia({ - video: true, - audio: enableAudio, - }); + // request access to user camera + video: true, // request access to video + audio: enableAudio, //if enable audio is true request access to audio //not if false + }); // from if (document.getElementById('localstream')) { (document.getElementById('localstream')).srcObject = @@ -61,31 +62,42 @@ const webrtcPeerController = { enableAudio, }) ); + } + if (newRequestWebRTC.webRTCDataChannel === 'Audio') { + let localStream = await navigator.mediaDevices.getUserMedia({ + // accesses user audio + video: false, + audio: true, + }); - peerConnection.onicecandidate = async ( - event: RTCPeerConnectionIceEvent - ): Promise => { - if ( - event.candidate && - peerConnection.localDescription!.type === 'offer' - ) { - appDispatch( - newRequestWebRTCOfferSet( - JSON.stringify(peerConnection.localDescription) - ) - ); - } else if ( - event.candidate && - peerConnection.localDescription!.type === 'answer' - ) { - appDispatch( - newRequestWebRTCAnswerSet( - JSON.stringify(peerConnection.localDescription) - ) - ); - } + console.log('Local Audio Tracks Captured:', localStream.getTracks()); + localStream.getTracks().forEach((track) => { + // iterates over tracks in local stream + console.log(`adding track: ${track.kind}`); + peerConnection.addTrack(track, localStream); // adds them to the peer connection using add track + }); + + let remoteStream = new MediaStream(); // initialize new media stream object + //to hold audio tracks from remote peer + peerConnection.ontrack = async (event) => { + // sets up an event handler fro on track event of peer connection object + console.log(`recieved remote track: ${event.track.kind}`); + event.streams[0].getTracks().forEach((track) => { + // iterates over each track recieved to the remote stream object// returns array of tracks + remoteStream.addTrack(track); + }); }; - } else if (newRequestWebRTC.webRTCDataChannel === 'Text') { + + appDispatch( + // update redux state + newRequestWebRTCSet({ + // new state object is created to update redux state + ...newRequestWebRTC, //copy properties from existing state object + webRTCRemoteStream: remoteStream, //remote stream overwritten + }) + ); + } + if (newRequestWebRTC.webRTCDataChannel === 'Text') { // const { request, response } = currentReqRes as { // request: RequestWebRTCText; // response: ResponseWebRTCText; @@ -133,40 +145,39 @@ const webrtcPeerController = { webRTCLocalStream: localStream, }) ); - - peerConnection.onicecandidate = async ( - event: RTCPeerConnectionIceEvent - ): Promise => { - if ( - event.candidate && - peerConnection.localDescription!.type === 'offer' - ) { - //debugged - appDispatch( - newRequestWebRTCOfferSet( - //should we be adding a ...peerConnection here spreading out the rest of the peerConnection object? also why isn't this updating the newWebRTCRequest object? - JSON.stringify(peerConnection.localDescription) - ) - ); - } else if ( - event.candidate && - peerConnection.localDescription!.type === 'answer' - ) { - //added this plus an answerSet reducer so the answer wasn't populating both the answer and offer text boxes (and being two different versions of the answer at that) - appDispatch( - newRequestWebRTCAnswerSet( - JSON.stringify(peerConnection.localDescription) - ) - ); - console.log('eventIceCandidate:', event.candidate.candidate); - } - }; } + peerConnection.onicecandidate = async ( + event: RTCPeerConnectionIceEvent + ) => { + // sets up event handler for onice canditates + if ( + event.candidate && + peerConnection.localDescription!.type === 'offer' + ) { + // checks for canidate and if event type is offer + appDispatch( + newRequestWebRTCOfferSet( + JSON.stringify(peerConnection.localDescription) + ) + ); // dispatches action to set a new WebRTC offer request + } else if ( + event.candidate && + peerConnection.localDescription!.type === 'answer' + ) { + // checks for canditate with description type answer + appDispatch( + newRequestWebRTCAnswerSet( + JSON.stringify(peerConnection.localDescription) + ) + ); //dispatches action to create answer + } + }; }, // what in create offer triggers the ice candidate to be sent? createOffer: async (newRequestWebRTC: RequestWebRTC): Promise => { //grab the peer connection off the state to manipulate further let { webRTCpeerConnection } = newRequestWebRTC; + if (!webRTCpeerConnection) return; console.log('webRTCPeerConnect:', webRTCpeerConnection); let offer = await webRTCpeerConnection!.createOffer(); console.log('offer:', offer); diff --git a/src/types.ts b/src/types.ts index b843d68f6..adfdcad9a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -323,6 +323,10 @@ export type ResponseWebRTC = ResponseWebRTCText; export interface ResponseWebRTCText { webRTCMessages: WebMessages[]; + + events?: any[]; + headers?: Record; + cookies?: any[]; } //Defines web rtc request type that can be audio video or text //enable audio is a shared but optional property From 8fa272d5f6207a24769f959a58c59a6eafbed991 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Wed, 12 Feb 2025 12:02:32 -0500 Subject: [PATCH 21/47] get offer fix --- .../main/WebRTC-composer/WebRTCServerEntryForm.tsx | 5 +++++ src/client/controllers/webrtcPeerController.ts | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 9c825fc10..a96339176 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -163,6 +163,11 @@ const WebRTCServerEntryForm: React.FC = () => { style={{ margin: '10px' }} onClick={() => { console.log('newRequestWebRTCfromOclick:', newRequestWebRTC); + if (!newRequestWebRTC.webRTCpeerConnection) { + console.warn( + 'webRTCpeerConnection is NULL! createPeerConnection may not have run.' + ); + } webrtcPeerController.createOffer(newRequestWebRTC); }} > diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index a8a806a7c..6163c4650 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -93,6 +93,8 @@ const webrtcPeerController = { newRequestWebRTCSet({ // new state object is created to update redux state ...newRequestWebRTC, //copy properties from existing state object + webRTCpeerConnection: peerConnection, + webRTCLocalStream: localStream, webRTCRemoteStream: remoteStream, //remote stream overwritten }) ); @@ -176,6 +178,12 @@ const webrtcPeerController = { // what in create offer triggers the ice candidate to be sent? createOffer: async (newRequestWebRTC: RequestWebRTC): Promise => { //grab the peer connection off the state to manipulate further + console.log('checking peer connection inside createOffer'); + console.log( + 'webRTCpeerConnection exists:', + !!newRequestWebRTC.webRTCpeerConnection + ); + let { webRTCpeerConnection } = newRequestWebRTC; if (!webRTCpeerConnection) return; console.log('webRTCPeerConnect:', webRTCpeerConnection); From a5d5df5844f2d7473cbaa1833f58435ba0958422 Mon Sep 17 00:00:00 2001 From: catmons Date: Wed, 12 Feb 2025 15:57:25 -0500 Subject: [PATCH 22/47] added guide tour feature --- package.json | 7 +- .../main/WebRTC-composer/WebRTCComposer.tsx | 28 ++- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 185 ++++++++++++------ .../WebRTCTextContainer.tsx | 7 +- 4 files changed, 153 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index 8c9ba0d36..80b4b1592 100644 --- a/package.json +++ b/package.json @@ -98,8 +98,8 @@ "@apollo/client": "^3.5.0", "@apollo/server": "^4.6.0", "@emotion/cache": "^11.11.0", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@graphql-tools/schema": "^8.3.10", "@grpc/grpc-js": "^1.6.7", "@grpc/proto-loader": "^0.6.9", @@ -156,6 +156,7 @@ "react-dropzone": "^12.1.0", "react-github-btn": "^1.2.2", "react-icons": "^5.4.0", + "react-joyride": "^2.9.3", "react-redux": "^8.0.1", "react-router-dom": "^6.3.0", "react-split": "^2.0.14", @@ -184,7 +185,7 @@ "@babel/runtime": "^7.17.9", "@mui/icons-material": "^5.6.2", "@mui/lab": "5.0.0-alpha.137", - "@mui/material": "5.14.2", + "@mui/material": "^5.14.2", "@playwright/test": "^1.21.1", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.0.0", diff --git a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx index e0d5fccb0..4ba8a55e4 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx @@ -14,7 +14,10 @@ import NewRequestButton from '../sharedComponents/requestButtons/NewRequestButto import { Box } from '@mui/material'; import WebRTCVideoBox from './WebRTCVideoBox'; import { RootState } from '../../../toolkit-refactor/store'; -import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; +import { + useAppDispatch, + useAppSelector, +} from '../../../toolkit-refactor/hooks'; import { composerFieldsReset } from '../../../toolkit-refactor/slices/newRequestSlice'; import { setWorkspaceActiveTab } from '../../../toolkit-refactor/slices/uiSlice'; import { reqResItemAdded } from '../../../toolkit-refactor/slices/reqResSlice'; @@ -40,7 +43,7 @@ export default function WebRTCComposer() { checkSelected: false, request: newRequestWebRTC, response: { - webRTCMessages: [] + webRTCMessages: [], }, checked: false, minimized: false, @@ -56,15 +59,20 @@ export default function WebRTCComposer() { ) return true; } catch { - return false + return false; } return false; - } + }; const addNewRequest = (): void => { - console.log('newRequestWebRTCatANR:', newRequestWebRTC) - if (!(checkValidSDP(newRequestWebRTC.webRTCOffer) && checkValidSDP(newRequestWebRTC.webRTCAnswer))){ - return alert('Invalid offer or answer SDP') + console.log('newRequestWebRTCatANR:', newRequestWebRTC); + if ( + !( + checkValidSDP(newRequestWebRTC.webRTCOffer) && + checkValidSDP(newRequestWebRTC.webRTCAnswer) + ) + ) { + return alert('Invalid offer or answer SDP'); } // let localStream = peerConnection.createDataChannel('textChannel'); // // localStream.onopen = () => console.log('data channel opened'); @@ -77,7 +85,7 @@ export default function WebRTCComposer() { // addHistory removed because RTCPeerConnection objects cant typically be cloned // historyController.addHistoryToIndexedDb(reqRes); - console.log('reqRes:', reqRes) + console.log('reqRes:', reqRes); dispatch(reqResItemAdded(reqRes)); dispatch(composerFieldsReset()); setShowRTCEntryForms(false); @@ -94,7 +102,7 @@ export default function WebRTCComposer() { className="is-flex-grow-3 add-vertical-scroll container-margin" style={{ overflowX: 'hidden' }} > - + {showRTCEntryForms && ( <> @@ -112,4 +120,4 @@ export default function WebRTCComposer() {
  • ); -} \ No newline at end of file +} diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 6b1b63a12..0cb500701 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useEffect } from 'react'; +import Joyride from 'react-joyride'; import { useState } from 'react'; import { MdRefresh } from 'react-icons/md'; @@ -34,12 +35,65 @@ interface Props { const WebRTCServerEntryForm: React.FC = (props: Props) => { const [isToggled, setIsToggled] = useState(false); - + const [run, setRun] = useState(true); const dispatch = useAppDispatch(); const newRequestWebRTC: RequestWebRTC = useAppSelector( (store: RootState) => store.newRequest.newRequestWebRTC ); + const steps = [ + { + target: '.get-offer-button', + content: 'Caller: Generate an offer by clicking “Get Offer”.', + placement: 'bottom', + }, + { + target: '.copy-offer-button', // Target the "Copy" button in the Offer code box + content: + 'Caller: Copy to clipboard, paste and send to recipient (email recommended).', + placement: 'bottom', + }, + { + target: '.offer-paste-button', + content: 'Recipient: Copy the offer received and paste into the top box', + }, + { + target: '.get-answer-btn', + content: "Recipient: Click 'Get Answer' and copy it.", + }, + // { + // target: ".answer-input-box", + // content: "Caller: Paste the answer here.", + // }, + // { + // target: ".add-answer-btn", + // content: "Caller: Click 'Add Answer' to establish the connection.", + // }, + // { + // target: ".add-to-workspace-btn-caller", + // content: "Caller: Click 'Add to Workspace'.", + // }, + // { + // target: ".add-to-workspace-btn-recipient", + // content: "Recipient: Click 'Add to Workspace'.", + // }, + // { + // target: ".send-btn-caller", + // content: "Caller: Click 'Send'.", + // }, + // { + // target: ".send-btn-recipient", + // content: "Recipient: Click 'Send'.", + // }, + ]; + // Use useEffect to start the joyride after the component mounts + useEffect(() => { + // Delay the start of Joyride to ensure everything is rendered + const timer = setTimeout(() => setRun(true), 500); + + return () => clearTimeout(timer); // Clear the timer on cleanup + }, []); + return (
    @@ -85,63 +139,76 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { placeholder={'Click "Get Offer" or paste in Offer SDP'} readOnly={true} /> - - - - +
    + + + + + + +
    {/* Code box for Answer */}
    diff --git a/src/client/components/main/response-composer/webRTCResponseComponents/WebRTCTextContainer.tsx b/src/client/components/main/response-composer/webRTCResponseComponents/WebRTCTextContainer.tsx index 9c9edffd5..51ea1f882 100644 --- a/src/client/components/main/response-composer/webRTCResponseComponents/WebRTCTextContainer.tsx +++ b/src/client/components/main/response-composer/webRTCResponseComponents/WebRTCTextContainer.tsx @@ -1,5 +1,8 @@ import React, { useState } from 'react'; -import { useAppDispatch, useAppSelector } from '../../../../toolkit-refactor/hooks'; +import { + useAppDispatch, + useAppSelector, +} from '../../../../toolkit-refactor/hooks'; import { RootState } from '../../../../toolkit-refactor/store'; import { stepperClasses } from '@mui/material'; import { @@ -64,7 +67,7 @@ const WebRTCTextContainer = () => { ); // console.log('request:', request); // console.log('currentReqRes:', currentReqRes); - webrtcPeerController.sendMessages(currentReqRes, messageInput); + //webrtcPeerController.sendMessages(currentReqRes, messageInput); ( document.getElementById('webrtc-message-input') as HTMLInputElement ).value = ''; From 55418b71b5a0b2db66805d89885b7be90398bed3 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Wed, 12 Feb 2025 17:26:46 -0500 Subject: [PATCH 23/47] video toggle update --- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index a96339176..50cece388 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState } from 'react'; import { MdRefresh } from 'react-icons/md'; // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; @@ -43,6 +43,10 @@ const WebRTCServerEntryForm: React.FC = () => { // toggles state os is toggled const newToggleState = !isToggled; setIsToggled(newToggleState); + console.log( + 'Dispatching newRequestWebRTCSet with enableAudio:', + newToggleState + ); dispatch( //sends action to redux store @@ -53,22 +57,11 @@ const WebRTCServerEntryForm: React.FC = () => { enableAudio: newToggleState, //updates Enableaudio property in newRequestWebRTC to match toggle state }) //enable audio updated every time toggle state changes ); + console.log( + 'enableAudio Redux state just after dispatch:', + newRequestWebRTC.enableAudio + ); }; - //for testing audio only playback when other flaws are ruled out - const audioRef = useRef(null); - // creates reference html audio element - // where useRef persists values across renders without causing rerenders //initally set to null - // useEffect(() => { - // // play audio when conditions are met - // if (newRequestWebRTC.webRTCLocalStream && audioRef.current) { - // // if local stream and current audio arent null - // console.log('Local Mic Playing...'); - // audioRef.current.srcObject = newRequestWebRTC.webRTCLocalStream; // sets source of media to local stream - // audioRef.current - // .play() - // .catch((e) => console.warn('Electron Autoplay Issue', e)); // attempts to play it - // } // if error indicates it may be an issues with electron audioplayback vs video with audio - // }, [newRequestWebRTCSet.webRTCLocalStream]); // use effect runs whenever local stream changes return (
    From ae67d7f4c08667e278dd35777f857d16a4bc783f Mon Sep 17 00:00:00 2001 From: catmons Date: Wed, 12 Feb 2025 20:47:30 -0500 Subject: [PATCH 24/47] guide tour phase 1 complete --- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 168 +++++++++--------- 1 file changed, 81 insertions(+), 87 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 0cb500701..c0de84414 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -56,35 +56,26 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { { target: '.offer-paste-button', content: 'Recipient: Copy the offer received and paste into the top box', + placement: 'bottom', }, { target: '.get-answer-btn', content: "Recipient: Click 'Get Answer' and copy it.", + placement: 'bottom', + }, + { + target: '.answer-paste-button', + content: 'Caller: Paste the answer here.', + }, + { + target: '.add-answer-btn', + content: + "Caller: Click 'Add Answer' to establish the connection. Then click 'Add to Workspace' button below", + }, + { + target: '.add-to-workspace-btn', + content: "Caller: Click 'Add to Workspace'.", }, - // { - // target: ".answer-input-box", - // content: "Caller: Paste the answer here.", - // }, - // { - // target: ".add-answer-btn", - // content: "Caller: Click 'Add Answer' to establish the connection.", - // }, - // { - // target: ".add-to-workspace-btn-caller", - // content: "Caller: Click 'Add to Workspace'.", - // }, - // { - // target: ".add-to-workspace-btn-recipient", - // content: "Recipient: Click 'Add to Workspace'.", - // }, - // { - // target: ".send-btn-caller", - // content: "Caller: Click 'Send'.", - // }, - // { - // target: ".send-btn-recipient", - // content: "Recipient: Click 'Send'.", - // }, ]; // Use useEffect to start the joyride after the component mounts useEffect(() => { @@ -209,74 +200,77 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { Get Answer
    -
    - {/* Code box for Answer */} -
    - { - dispatch( - newRequestWebRTCSet({ ...newRequestWebRTC, webRTCAnswer: value }) - ); - console.log( - 'newRequestWebRTC (though may not be updated bc async):', - newRequestWebRTC - ); - }} - placeholder={'Answer here'} - readOnly={true} - /> - - + ); + console.log( + 'newRequestWebRTC (though may not be updated bc async):', + newRequestWebRTC + ); + }} + placeholder={'Answer here'} + readOnly={true} + /> + + - - {/* {warningMessage ?
    {warningMessage.body}
    : null} */} + + {/* {warningMessage ?
    {warningMessage.body}
    : null} */} +
    ); From 2a279169dbad4af34105d31deacf4c2a6e3776cb Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 10:53:26 -0500 Subject: [PATCH 25/47] merging deployment-test branch --- docs/DEV-README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/DEV-README.md b/docs/DEV-README.md index e869a175a..f5f7447d9 100644 --- a/docs/DEV-README.md +++ b/docs/DEV-README.md @@ -19,7 +19,7 @@ Thank you for your consideration and let's work together on making Swell one of - TypeScript + JavaScript - React -- Redux +- Redux Toolkit - SASS - Node - Express @@ -111,6 +111,7 @@ From a functionality standpoint: - HTTP/2 stress testing with `GET` requests - GraphQL stress testing with `Query` - Mock server for HTTP/2 (`Express`) +- WebRTC video/audio and text channel testing - Ability to store historical requests and create/delete workspaces - Frontend conversion to TypeScript - From a codebase standpoint: @@ -140,9 +141,9 @@ endeavour. The impacts to the product are: As you iterate the product, keep in mind the footprint your new feature(s) could add to the codebase. Could you re-use some of the existing modules? Can you even refactor and/or remove the obsolete code to help maintain the health of the codebase? -There are many parts of the codebase that break DRY principles, and with such a large application, really keep in mind that when you add features to ask if it is completely necessary. Past iterators added an experimental feature(s) without it fully working and the following team(s) would add their own experimental feature. Fixing features the past teams couldn't get to is not only a great way to learn these technologies but also a great thing to talk about in interviews. "I fixed the webRTC feature that has been stagnant for 5 years", "I addressed the technical debt and reorganized the state...", or "Increased the quality of typeScript". These all show maturity as a developer and will allow us to focus the entire time of OSP on the final 20% problems. +There are many parts of the codebase that break DRY principles, and with such a large application, really keep in mind when you add features to ask if it is completely necessary. Past iterators added an experimental feature(s) without it fully working and the following team(s) would add their own experimental feature. Fixing features the past teams couldn't get to is not only a great way to learn these technologies but also a great thing to talk about in interviews. "I fixed the webRTC feature that has been stagnant for 5 years", "I addressed the technical debt and reorganized the state...", or "Increased the quality of typeScript". These all show maturity as a developer and will allow us to focus the entire time of OSP on the final 20% problems. -Legacy Components - As a part of a clean up effort, all files that are no longer being used have been moved to the legacy component folder. Examples of these files come from the migration to shared components. The original location of the components is mentioned in the comments of the relocated files. +Legacy Components - As a part of a cleanup effort, all files that are no longer being used have been moved to the legacy component folder. Examples of these files come from the migration to shared components. The original location of the components is mentioned in the comments of the relocated files. ### _Ensure consistent redux state management_ @@ -250,7 +251,7 @@ Finally, if future iterators would like to completely cover the list of API-test --- -## Backlog from Iteration Group v1.18 +## Backlog from Iteration Groups v1.18 and v1.19 - Fix/Update GitHub Actions for Unit Testing - Create a feature/function/endpoint to delete a mock route @@ -267,7 +268,7 @@ Finally, if future iterators would like to completely cover the list of API-test - Convert WebRTCSessionEntryForm to MUI - Convert WebRTC components to all use material UI as per line 7 of WebRTCComposer.tsx - Combine newRequestSlice.ts and newRequestFieldSlice.ts -- Update Excalidraw if necessary with new features/redux changes +- Update Excalidraw as necessary with new features/redux changes - ErrorBoundary.tsx may not be functional or necessary (Leave for now) --- From 78bc5c4b5c1805a2fd8f3dfcfabcd049e22e1a7f Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 11:05:01 -0500 Subject: [PATCH 26/47] changed yaml branch back to master from dev --- .github/workflows/createPackages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/createPackages.yml b/.github/workflows/createPackages.yml index 141ff7718..6451f1da5 100644 --- a/.github/workflows/createPackages.yml +++ b/.github/workflows/createPackages.yml @@ -3,7 +3,7 @@ name: Master Workflow on: push: branches: - - dev + - master jobs: tests: From 16eff445236cd0b20a0331def899cf14b01505d5 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 11:26:32 -0500 Subject: [PATCH 27/47] changed node version in yaml --- .github/workflows/createPackages.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/createPackages.yml b/.github/workflows/createPackages.yml index 6451f1da5..185d3d46b 100644 --- a/.github/workflows/createPackages.yml +++ b/.github/workflows/createPackages.yml @@ -9,7 +9,7 @@ jobs: tests: strategy: matrix: - node-version: [16] + node-version: [18.20.6] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -40,15 +40,15 @@ jobs: - name: Use Node.js uses: actions/setup-node@v2 with: - node-version: '16.15' + node-version: '18.20.6' - name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} with: - tag_name: v1.16.0 # Replace with your desired tag or version number - release_name: Release v1.16.0 # Replace with your desired release name + tag_name: v1.19.0 # Replace with your desired tag or version number + release_name: Release v1.19.0 # Replace with your desired release name draft: true body: | @@ -67,7 +67,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v2 with: - node-version: '16.15' + node-version: '18.20.6' - name: Install Dependencies run: npm install @@ -89,7 +89,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v2 with: - node-version: '16.15' # Use the specific version of Node that your project requires + node-version: '18.20.6' # Use the specific version of Node that your project requires - name: Install Dependencies run: npm install @@ -118,7 +118,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v2 with: - node-version: '16.15' # Use the specific version of Node that your project requires + node-version: '18.20.6' # Use the specific version of Node that your project requires - name: Install Dependencies run: npm install From 0daf5894da21aadf5e8c76ef30b2adc81aa89896 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 12:01:00 -0500 Subject: [PATCH 28/47] trying to update versions --- .github/workflows/unit-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index c6c1dea01..f0e75c9ec 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -6,7 +6,7 @@ jobs: tests: strategy: matrix: - node-version: [16] + node-version: [18.20.6] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -21,4 +21,4 @@ jobs: - name: Run unit tests uses: coactions/setup-xvfb@v1 with: - run: npm run test-jest \ No newline at end of file + run: npm run test-jest From af29f17cac766060b2eec0c3432e6079145ceab3 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 12:14:56 -0500 Subject: [PATCH 29/47] added step to codeql-analysis yml --- .github/workflows/codeql-analysis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1c3e9b9ec..641a44a92 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,6 +30,11 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 + + - name: Use Node.js 18 # Add this step + uses: actions/setup-node@v3 + with: + node-version: 18.20.6 # Or your preferred 18.x version # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From 38647fe42f00eda6c287169033d440deaa94b3cb Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 12:40:36 -0500 Subject: [PATCH 30/47] more changes to the yml files, codeql specifically --- .github/workflows/codeql-analysis.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 641a44a92..5bf240180 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,10 +31,22 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - - name: Use Node.js 18 # Add this step + - name: Use Node.js 18 uses: actions/setup-node@v3 with: node-version: 18.20.6 # Or your preferred 18.x version + + - name: Print Node.js version + run: node -v + + - name: Install dependencies + run: npm ci # Or npm install if you prefer + + - name: Build project + run: | + make boostrap + make release + npm run build # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -48,19 +60,15 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # - name: Autobuild + # uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release + # uses a compiled language (we moved the "below" lines up to 42 and edited them) - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 From 3417405590e55a80fd1ae4768af7779573935a3c Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 12:48:22 -0500 Subject: [PATCH 31/47] explicitly naming node versions instead of dynamic updating; deleted package json lock file, cleared cache, reinstalled --- .github/workflows/createPackages.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/createPackages.yml b/.github/workflows/createPackages.yml index 185d3d46b..f368347f7 100644 --- a/.github/workflows/createPackages.yml +++ b/.github/workflows/createPackages.yml @@ -15,10 +15,10 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js 18.20.6 uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: 18.20.6 - name: Install dependencies run: npm i && npm ci - name: Run unit tests From 69ba84414c52ddbca657b5bd5bb2fceb585f78dc Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 13:24:20 -0500 Subject: [PATCH 32/47] further changes --- .github/workflows/createPackages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/createPackages.yml b/.github/workflows/createPackages.yml index f368347f7..43c43f881 100644 --- a/.github/workflows/createPackages.yml +++ b/.github/workflows/createPackages.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v3 - - name: Use Node.js 18.20.6 + - name: Use Node.js 18.20.6 # this used to be dynamically updated, but kept pulling an old version number. you'll have to manually update these throughout this file to be safe. uses: actions/setup-node@v3 with: node-version: 18.20.6 From e70eadcea14bfb58b40059e5abbf61ee812382ef Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 13:34:01 -0500 Subject: [PATCH 33/47] added set NODE_OPTIONS for windows tests --- .github/workflows/unit-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f0e75c9ec..13304f121 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -17,7 +17,9 @@ jobs: with: node-version: ${{ matrix.node-version }} - name: Install dependencies - run: npm i && npm ci + run: | + set NODE_OPTIONS=-no-node-snapshot + npm i && npm ci - name: Run unit tests uses: coactions/setup-xvfb@v1 with: From 8fcef8ac5ecc41b894fd5d1e377b196bcd5d6f87 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 13:41:08 -0500 Subject: [PATCH 34/47] more windows updates --- .github/workflows/unit-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 13304f121..a56d2d9b6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -17,9 +17,9 @@ jobs: with: node-version: ${{ matrix.node-version }} - name: Install dependencies - run: | - set NODE_OPTIONS=-no-node-snapshot - npm i && npm ci + env: + NODE_OPTIONS: --no-node-snapshot + run: npm i && npm ci - name: Run unit tests uses: coactions/setup-xvfb@v1 with: From 7322ce81443be1d1ad74c360db8b792a5feaa054 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 13:54:40 -0500 Subject: [PATCH 35/47] more windows changes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68a88646b..684904085 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "gh-publish-mac": "electron-builder build --x64 --mac -p always", "gh-publish": "electron-builder build -mwl -p always", "check-types": "tsc", - "postinstall": "NODE_OPTIONS=--no-node-snapshot patch-package" + "postinstall": "patch-package" }, "build": { "npmRebuild": false, From 80d98894f858e1bae31d325f58b083981f3eadc3 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 14:04:54 -0500 Subject: [PATCH 36/47] changed node_options to node_env --- .github/workflows/unit-tests.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index a56d2d9b6..c266e5ebf 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -18,7 +18,7 @@ jobs: node-version: ${{ matrix.node-version }} - name: Install dependencies env: - NODE_OPTIONS: --no-node-snapshot + NODE_ENV: --no-node-snapshot run: npm i && npm ci - name: Run unit tests uses: coactions/setup-xvfb@v1 diff --git a/package.json b/package.json index 684904085..b427f2480 100644 --- a/package.json +++ b/package.json @@ -146,7 +146,7 @@ "node-fetch": "^3.3.0", "node-gyp": "^11.0.0", "npm": "^8.7.0", - "patch-package": "^6.4.7", + "patch-package": "^6.5.1", "path": "^0.12.7", "prop-types": "^15.8.1", "react": "^18.0.0", From 4719c48e12a2d3aa5a733b31ae7367598936658d Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 14:10:03 -0500 Subject: [PATCH 37/47] separated out patches step --- .github/workflows/unit-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index c266e5ebf..7ad54fa6a 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -17,9 +17,11 @@ jobs: with: node-version: ${{ matrix.node-version }} - name: Install dependencies + run: npm i && npm ci + - name: Apply patches env: NODE_ENV: --no-node-snapshot - run: npm i && npm ci + run: npx patch-package - name: Run unit tests uses: coactions/setup-xvfb@v1 with: From dcb7bb2383ceb7355b338c6d52946d21c06c4969 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Thu, 13 Feb 2025 14:15:29 -0500 Subject: [PATCH 38/47] Audio Channel working beta and toggle fix Co-authored-by: Isaac Mbambo --- .../main/WebRTC-composer/WebRTCAudioBox.tsx | 27 ++++++ .../main/WebRTC-composer/WebRTCComposer.tsx | 17 ++-- .../WebRTC-composer/WebRTCServerEntryForm.tsx | 40 ++++++--- .../controllers/webrtcPeerController.ts | 90 ++++++++++++++----- 4 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 src/client/components/main/WebRTC-composer/WebRTCAudioBox.tsx diff --git a/src/client/components/main/WebRTC-composer/WebRTCAudioBox.tsx b/src/client/components/main/WebRTC-composer/WebRTCAudioBox.tsx new file mode 100644 index 000000000..6d5fe2ec5 --- /dev/null +++ b/src/client/components/main/WebRTC-composer/WebRTCAudioBox.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +// possibly not the best practice implementation for audio playback ? +interface Props { + streamType: 'localstream' | 'remotestream'; +} +const WebRTCAudioBox: React.FC = (props: Props) => { + const { streamType } = props; + return ( + + ); +}; + +export default WebRTCAudioBox; + diff --git a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx index d3f689428..ee021e3d0 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCComposer.tsx @@ -13,6 +13,7 @@ import NewRequestButton from '../sharedComponents/requestButtons/NewRequestButto // Import MUI components import { Box } from '@mui/material'; import WebRTCVideoBox from './WebRTCVideoBox'; +import WebRTCAudioBox from './WebRTCAudioBox'; import { RootState } from '../../../toolkit-refactor/store'; import { useAppDispatch, @@ -109,12 +110,18 @@ export default function WebRTCComposer() {
    - {newRequestWebRTC.webRTCDataChannel === 'Video' && ( -
    - -
    - )}
    + {newRequestWebRTC.webRTCDataChannel === 'Video' && ( +
    + +
    + )} + + {newRequestWebRTC.webRTCDataChannel === 'Audio' && ( +
    + +
    + )} )}
    diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 50cece388..19feda51f 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { MdRefresh } from 'react-icons/md'; // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; @@ -38,15 +38,22 @@ const WebRTCServerEntryForm: React.FC = () => { (store: RootState) => store.newRequest.newRequestWebRTC ); const [isToggled, setIsToggled] = useState(false); + const currentReqRes = useAppSelector( + (store: RootState) => store.reqRes.currentResponse + ) as ReqRes; + + useEffect(() => { + setIsToggled(newRequestWebRTC.enableAudio as boolean); + }, [newRequestWebRTC.enableAudio]); const handleToggleChange = () => { // toggles state os is toggled const newToggleState = !isToggled; setIsToggled(newToggleState); - console.log( - 'Dispatching newRequestWebRTCSet with enableAudio:', - newToggleState - ); + // console.log( + // 'Dispatching newRequestWebRTCSet with enableAudio for handleToggleChange:', + // newToggleState + // ); dispatch( //sends action to redux store @@ -57,12 +64,19 @@ const WebRTCServerEntryForm: React.FC = () => { enableAudio: newToggleState, //updates Enableaudio property in newRequestWebRTC to match toggle state }) //enable audio updated every time toggle state changes ); - console.log( - 'enableAudio Redux state just after dispatch:', - newRequestWebRTC.enableAudio + + // console.log( + // 'enableAudio Redux state just after dispatch:', + // newRequestWebRTC.enableAudio + // ); + webrtcPeerController.createPeerConnection( + { + ...newRequestWebRTC, + enableAudio: newToggleState, + }, + currentReqRes ); }; - return (
    @@ -107,10 +121,10 @@ const WebRTCServerEntryForm: React.FC = () => { dispatch( newRequestWebRTCSet({ ...newRequestWebRTC, webRTCOffer: value }) ); - console.log( - 'value after dispatch, Im assuming it is the same:', - value - ); + // console.log( + // 'value after dispatch, Im assuming it is the same:', + // value + // ); }} placeholder={'Click "Get Offer" or paste in Offer SDP'} readOnly={true} diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 6163c4650..9b0d9c553 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -19,6 +19,8 @@ const webrtcPeerController = { newRequestWebRTC: RequestWebRTC, currentReqRes: ReqRes ) => { + // const enableAudio = + // store.getState().newRequest.newRequestWebRTC.enableAudio ?? false; const enableAudio = newRequestWebRTC.enableAudio ?? false; //if null set to false let servers = { @@ -35,7 +37,7 @@ const webrtcPeerController = { // request access to user camera video: true, // request access to video audio: enableAudio, //if enable audio is true request access to audio //not if false - }); // from + }); if (document.getElementById('localstream')) { (document.getElementById('localstream')).srcObject = @@ -62,28 +64,52 @@ const webrtcPeerController = { enableAudio, }) ); - } - if (newRequestWebRTC.webRTCDataChannel === 'Audio') { + peerConnection.onicecandidate = async ( + event: RTCPeerConnectionIceEvent + ): Promise => { + if ( + event.candidate && + peerConnection.localDescription!.type === 'offer' + ) { + appDispatch( + newRequestWebRTCOfferSet( + JSON.stringify(peerConnection.localDescription) + ) + ); + } else if ( + event.candidate && + peerConnection.localDescription!.type === 'answer' + ) { + appDispatch( + newRequestWebRTCAnswerSet( + JSON.stringify(peerConnection.localDescription) + ) + ); + } + }; + } else if (newRequestWebRTC.webRTCDataChannel === 'Audio') { let localStream = await navigator.mediaDevices.getUserMedia({ - // accesses user audio - video: false, - audio: true, - }); + // request access to user camera + video: false, // request access to video + audio: true, //if enable audio is true request access to audio //not if false + }); // from + + if (document.getElementById('localstream')) { + (document.getElementById('localstream')).srcObject = + localStream; + } - console.log('Local Audio Tracks Captured:', localStream.getTracks()); localStream.getTracks().forEach((track) => { // iterates over tracks in local stream - console.log(`adding track: ${track.kind}`); - peerConnection.addTrack(track, localStream); // adds them to the peer connection using add track - }); + peerConnection.addTrack(track, localStream); + }); // adds them to the peer connection using add track - let remoteStream = new MediaStream(); // initialize new media stream object - //to hold audio tracks from remote peer + let remoteStream = new MediaStream(); //initialize new media stream object peerConnection.ontrack = async (event) => { - // sets up an event handler fro on track event of peer connection object - console.log(`recieved remote track: ${event.track.kind}`); + // adds them to the peer connection using add track event.streams[0].getTracks().forEach((track) => { - // iterates over each track recieved to the remote stream object// returns array of tracks + // sets up an event handler for on track event of peer connection object + // returns array of tracks remoteStream.addTrack(track); }); }; @@ -91,15 +117,37 @@ const webrtcPeerController = { appDispatch( // update redux state newRequestWebRTCSet({ - // new state object is created to update redux state - ...newRequestWebRTC, //copy properties from existing state object + //new state object is created to update redux object + ...newRequestWebRTC, // copy properties from existing object webRTCpeerConnection: peerConnection, webRTCLocalStream: localStream, - webRTCRemoteStream: remoteStream, //remote stream overwritten + webRTCRemoteStream: remoteStream, // remote stream overwritten }) ); - } - if (newRequestWebRTC.webRTCDataChannel === 'Text') { + peerConnection.onicecandidate = async ( + event: RTCPeerConnectionIceEvent + ): Promise => { + if ( + event.candidate && + peerConnection.localDescription!.type === 'offer' + ) { + appDispatch( + newRequestWebRTCOfferSet( + JSON.stringify(peerConnection.localDescription) + ) + ); + } else if ( + event.candidate && + peerConnection.localDescription!.type === 'answer' + ) { + appDispatch( + newRequestWebRTCAnswerSet( + JSON.stringify(peerConnection.localDescription) + ) + ); + } + }; + } else if (newRequestWebRTC.webRTCDataChannel === 'Text') { // const { request, response } = currentReqRes as { // request: RequestWebRTCText; // response: ResponseWebRTCText; From 4d4145d079e50fa313f21c7e5fb46b64ae14f68c Mon Sep 17 00:00:00 2001 From: catmons Date: Thu, 13 Feb 2025 14:56:50 -0500 Subject: [PATCH 39/47] add all changes --- .../components/main/WebRTC-composer/WebRTCServerEntryForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 317921084..48b0d7f61 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import Joyride from 'react-joyride'; import { useState, useRef, useEffect } from 'react'; import { MdRefresh } from 'react-icons/md'; From 7d2683a869b9c7eb20beab9caf39992c4765bd72 Mon Sep 17 00:00:00 2001 From: Kiki Hunt Date: Thu, 13 Feb 2025 15:21:15 -0500 Subject: [PATCH 40/47] WebSocket Temporary Disable for Deployment Co-authored-by: Isaac Mbambo --- .../main/WebRTC-composer/WebRTCSessionEntryForm.tsx | 4 ++-- src/client/components/navbar/ProtocolSelect.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx index 5e049cb3b..e14b4a9c0 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx @@ -83,7 +83,7 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { Manual )} - + {/* //use this if you want to enable websocket feature as signaling server {newRequestWebRTC.webRTCEntryMode !== 'WS' && ( { @@ -99,7 +99,7 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { > WS - )} + )} */}
    Date: Thu, 13 Feb 2025 15:43:25 -0500 Subject: [PATCH 41/47] dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0706e5e9c..20a01f7a4 100644 --- a/package.json +++ b/package.json @@ -595,3 +595,4 @@ } ] } + From 0e53ec8a4756421561570fc67cf08ea01550992c Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 16:13:55 -0500 Subject: [PATCH 42/47] ws comments --- .../controllers/webrtcPeerController.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 9b0d9c553..263caebf7 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -31,6 +31,33 @@ const webrtcPeerController = { ], }; let peerConnection = new RTCPeerConnection(servers); + // ? if you want to attempt to build a websocket with a live connection through ngrok, + // ? give it a shot - we attempted below, this may be helpful, probably isn't (-Isaac M) + + // let wsIp = newRequestWebRTC.webRTCWebsocketServer; + // const socket = io('http://localhost:3000'); + + // socket.on('connect', async () => { + // // try { + // // const url = await ngrok.connect({ + // // proto: 'http', + // // addr: 3000, + // // }); + // // console.log(`ngrok tunnel opened at: ${url}`); + // // // client.emit('ngrokUrl', url); + // // } catch (err) { + // // console.error('Failed to create ngrok tunnel:', err); + // // } + // console.log('Connected to server'); + // }); + + // socket.on('disconnect', () => { + // console.log('Disconnected from server'); + // }); + + // socket.on('message', (message: string) => { + // console.log('Message:', message); + // }); if (newRequestWebRTC.webRTCDataChannel === 'Video') { let localStream = await navigator.mediaDevices.getUserMedia({ From d8fa415f8c6669b63de20eb62d5dadda28e12997 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 16:16:56 -0500 Subject: [PATCH 43/47] more ws hints --- src/client/controllers/webrtcPeerController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/controllers/webrtcPeerController.ts b/src/client/controllers/webrtcPeerController.ts index 263caebf7..f2fae20dc 100644 --- a/src/client/controllers/webrtcPeerController.ts +++ b/src/client/controllers/webrtcPeerController.ts @@ -231,6 +231,8 @@ const webrtcPeerController = { event.candidate && peerConnection.localDescription!.type === 'offer' ) { + // ? more websocket hints below (-Isaac) + // ? // socket.emit('offer', JSON.stringify(peerConnection.localDescription)); // checks for canidate and if event type is offer appDispatch( newRequestWebRTCOfferSet( From 2578fb22fd0d45cac38be78d9ff10f34cf8a9f95 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 16:38:13 -0500 Subject: [PATCH 44/47] typescript error --- src/client/components/Versions.tsx | 12 ++++++++++++ .../main/WebRTC-composer/WebRTCServerEntryForm.tsx | 10 ++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/client/components/Versions.tsx b/src/client/components/Versions.tsx index b018d5e85..632d05620 100644 --- a/src/client/components/Versions.tsx +++ b/src/client/components/Versions.tsx @@ -1,6 +1,18 @@ import * as React from 'react'; import { useState } from 'react'; +declare global { + interface Window { + api: { + versions: { + electron: string; + chrome: string; + node: string; + }; + }; + } +} + function Versions(): JSX.Element { const [versions] = useState(window.api.versions); diff --git a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx index 0a8cc541e..d67af1f17 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCServerEntryForm.tsx @@ -2,6 +2,8 @@ import React from 'react'; import Joyride from 'react-joyride'; import { useState, useRef, useEffect } from 'react'; import { MdRefresh } from 'react-icons/md'; +import { Placement } from 'react-joyride'; + // import '/Users/katharinehunt/Swell/src/assets/style/WebRtcEntry.css'; import '../../../../assets/style/WebRtc.css'; @@ -88,23 +90,23 @@ const WebRTCServerEntryForm: React.FC = (props: Props) => { { target: '.get-offer-button', content: 'Caller: Generate an offer by clicking “Get Offer”.', - placement: 'bottom', + placement: 'bottom' as Placement, }, { target: '.copy-offer-button', // Target the "Copy" button in the Offer code box content: 'Caller: Copy to clipboard, paste and send to recipient (email recommended).', - placement: 'bottom', + placement: 'bottom' as Placement, }, { target: '.offer-paste-button', content: 'Recipient: Copy the offer received and paste into the top box', - placement: 'bottom', + placement: 'bottom' as Placement, }, { target: '.get-answer-btn', content: "Recipient: Click 'Get Answer' and copy it.", - placement: 'bottom', + placement: 'bottom' as Placement, }, { target: '.answer-paste-button', From c173504ae978d579bbb6e2a803f69242c7d2a8f0 Mon Sep 17 00:00:00 2001 From: Gilgamesh Date: Thu, 13 Feb 2025 16:55:54 -0500 Subject: [PATCH 45/47] updated ux of buttons in webrtc --- .../main/WebRTC-composer/WebRTCSessionEntryForm.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx index e14b4a9c0..6719900ed 100644 --- a/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx +++ b/src/client/components/main/WebRTC-composer/WebRTCSessionEntryForm.tsx @@ -49,19 +49,19 @@ const WebRTCSessionEntryForm: React.FC = (props: Props) => { id="rest-method" aria-haspopup="true" aria-controls="dropdown-menu" - onClick={() => - setEntryTypeDropdownIsActive(!entryTypeDropdownIsActive) - } + // onClick={() => + // setEntryTypeDropdownIsActive(!entryTypeDropdownIsActive) + // } > {newRequestWebRTC.webRTCEntryMode} - + {/* - + */}
    From 548fad8831e90ea06304017e4b04381af2662c32 Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 18:35:58 -0500 Subject: [PATCH 46/47] readme updates --- README.md | 43 ++++++++++++++++++++++++++++++++++----- docs/DEV-README.md | 50 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 95e429273..52ebff3e5 100755 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Swell is a one-stop shop for sending and monitoring your API requests: - Send and monitor streams over HTTP/2 (including SSEs) and WebSockets - Create GraphQL queries, introspections, mutations, and subscriptions +- Test WebRTC applications over video, audio and text channels - Stress testing HTTP/2 and GraphQL endpoints - Create your own HTTP/2 mock server - Store workspaces of multiple requests for later use @@ -67,6 +68,34 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W See [tRPC docs](https://trpc.io/docs/) for more information on sending tRPC requests or setting up a tRPC server. + +- _WebRTC_: Swell makes it easy to test WebRTC applications for video, audio and text channels. Currently Swell supports manual entry of SDPs. + + ### Walkthrough for setting up a text channel connection using the app's generated offer and answer: + + - Step 1 + Caller: Generate an offer by clicking “Get Offer.” Copy the offer to your computer's clipboard and send it to recipient (we recommend sending by email). + - Step 2 + Recipient: Copy the offer you received from the caller and paste it into the offer box (the top text box) + - Step 3 + Recipient: Click “Get answer” button, generate an answer and copy it to your computer's clipboard. Send it to caller (email recommended) + - Step 4 + Caller: Copy answer to your computer's clipboard and paste it into the answer box (bottom text box). + - Step 5 + Caller: Click the “add answer” button. Now the connection is open! + - Step 6 + Caller: Click “add to workspace” button. + - Step 7 + Recipient: Click “add to workspace” button. + - Step 8 + Caller: Click "Send" button on the left-hand side of the app. + - Step 9 + Recipient: Click "Send" button on the left-hand side of the app. + - Step 10 + Send and receive text messages via the response panel at the bottom of the app. + + + ## Additional features - _Stress testing for HTTP/2 and GraphQL_: Test your server backend with Swell's stress testing feature to ensure your server can manage expected and unexpected loads accordingly @@ -91,6 +120,7 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W + ## Experimental Features - _Mock Server_: Swell allows you to create your own HTTP/2 mock server to facilitate front-end development without depending on a fully built backend server. @@ -98,9 +128,6 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W - _Webhooks_: Swell includes user-defined HTTP callback connection testing designed to test other server's connection to the web and ability to send data. The test insures that when an event occurs, the source site makes an HTTP request to the URL configured for the webhook. -- _WebRTC_: Swell makes it easy to test WebRTC applications for both video and text channels. Currently Swell supports manual entry of SDPs. - - - _OpenAPI_: Swell supports the enumeration and execution of REST and RPC API requests as defined in a user-provided OpenAPI document. @@ -110,7 +137,7 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W - React - React Router - Material UI -- Redux +- Redux Toolkit - Apollo Client - Websockets - gRPC-js @@ -124,6 +151,12 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W - Playwright ## Authors + +- **Isaac Mbambo** - [IM236](https://github.com/IM236) +- **Kiki Hunt** - [Iloveeverything](https://github.com/Iloveeverything) +- **Ting Lee** - [tingEng](https://github.com/tingEng) +- **Rachel Dean** - [rchldn](https://github.com/rchldn) +- **Kadeem Reid** - [Kadeem929](https://github.com/Kadeem929) - **Karol Krzywon** - [kkrzywon](https://github.com/kkrzywon) - **Howard Sun** - [howardCodeGit](https://github.com/howardCodeGit) - **Carter Sarkela** - [CarterSarkela](https://github.com/CarterSarkela) @@ -215,4 +248,4 @@ We highly encourage you to check out the `DEV-README.md` in the `docs` folder. W ## License -This project is licensed under the MIT License +This project is licensed under the MIT License \ No newline at end of file diff --git a/docs/DEV-README.md b/docs/DEV-README.md index f5f7447d9..8ba6b52af 100644 --- a/docs/DEV-README.md +++ b/docs/DEV-README.md @@ -43,10 +43,23 @@ Thank you for your consideration and let's work together on making Swell one of ## How to download and test the application locally? 1. Fork and/or clone the repository into your local machine -2. In your terminal: +2. Update dependencies + - `isolated-vm` combined fix: There is a problem with `vm2` (a sandbox); it has vulnerabilities and was discontinued. An alternative is `isolated-vm` which uses the chromium browser's v8 engine. The prior version of `isolated-vm` on Swell's package.json was only compatible with Node 16. In order to upgrade to the latest version we ran the commands as + - We are using Node 18 instead of the most recent version of Node because of C++ compatibility with the Xcode command line. + - `node-gyp` is a tool for compiling native add-on modules for Node.js. It is often used when installing certain npm packages that require native code compilation. + + 1. If you have them, delete node modules, package-lock.json and dist folders + 2. `cd` into User directory; + 3. `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash` (installing nvm package so you can manage versions, and making it so you can run `nvm install` command inside of the terminal) + 4. While still in user folder: `source ~/.bashrc # or ~/.zshrc or ~/.bash_profile` + 5. `vm install 18` + 6. `nvm use 18` + 7. `npm install -g node-gyp` + +3. In your terminal: - `npm install`, then - `npm run dev` -3. Wait for the electron application to start up (it may take a bit) +4. Wait for the electron application to start up (it may take a bit) There is E2E testing available via `npm run test`. Note that not all tests in the E2E test suite work currently. Please refer to `./test/testSuite.js` and `./test/subSuites` for more details. @@ -111,7 +124,7 @@ From a functionality standpoint: - HTTP/2 stress testing with `GET` requests - GraphQL stress testing with `Query` - Mock server for HTTP/2 (`Express`) -- WebRTC video/audio and text channel testing +- WebRTC testing for text, video, and audio channel connections - Ability to store historical requests and create/delete workspaces - Frontend conversion to TypeScript - From a codebase standpoint: @@ -213,12 +226,34 @@ Currently, the HTTP/2 mock server has the ability to create a server that is acc In a recent iteration, the WebRTC feature was changed from STUN Server testing to Client RTC Connection testing, allowing Swell to test if another client is able to create an RTC connection to transmit text and video data. Because the RTCPeerConnection has to be initiated before we generate the SDP, this connection is set up differently from the other networks. Other networks purely need the primitive strings as input, and the response is created on click of `Send` (in the workspace panel). For WebRTC, the connection object is created as an input, and when the user clicks `Send` then the data transmitted data is allowed to be displayed (although data is being transmitted through the connection even before `Send` is clicked). This means the WebRTC ReqRes can't really be saved in history or re-connected beyond the first connection. -Areas for improvement: +In the repo’s [excalidraw](https://excalidraw.com/#room=18f1f977e8cd6361eaa1,4vr1DznwcnD-uKM_X7ZhiA) are the following diagrams specific to WebRTC: +- WebRTC Connectivity Diagram outlining the steps in a WebRTC connection and getting to media flow +- Front-end Interface Components explaining each component +- Flow of React/Redux (reacts to events in client to update store) +- WebRTC Front-end Format Experiments + + + + +#### Areas for improvement: -- Currently, our WebRTC only works as the connection initiator. The next step would be the `Add Answer` button which allows Swell to be on the receiver end of the connection. - Currently, our WebRTC end-to-end testing is read-only from the previous implementation. It would be a highly valuable addition to modify the old testing to test the current implementation of webRTC. Integration testing has been started but needs to be finished. Relevant files include - End-to-End:'test/**tests**/subSuites/webRTCTest.js' - Integration: 'test/**tests**/IntegrationTests/webRTCIntegrationTests' +- Front-end/UI improvements – see the excalidraw’s WebRTC Front-end Format Experiments diagram for ideas + Examples: + - Buttons could be named more intuitively and placed in more obvious places for the user to figure out the workflow + - Currently, when testing a video connection, users have to scroll all the way down in the server entry form container to see if their own camera is working. A redesign could help this be more clear + - Ability to rename an individual workspace once added to the left pane (switching between testing four different ‘text’ channels would be easier if you could rename each channel) + - The React Joyride tour could use slight improvement - the last few buttons are in different containers/files and harder for the tour to reach intuitively + - Improve styling for Joyride tour to be consistent with Swell colors and fonts +- The current port is hardcoded - a group could modify this part of the code to test the application on ports other than the default to ensure proper functionality across different ports +- The websocket feature of WebRTC is currently incomplete and commented out (both frontend and backend) and could be implemented +- Currently our WebRTC testing feature is on par with or less robust than other WebRTC testing apps. A group could focus on making it more competitive by adding tracking of certain metrics (including jitter, packet loss, geographically-driven latency, differences across different browsers and devices, emulating losing a wifi connection and switching to mobile data, etc) +- The electron app currently has a large file size not due to the code itself but the use of Electron. We briefly explored transitioning the app to Tauri or Neutralino but held off further research after rescoping. Transitioning to a new cross-platform desktop application framework would have a tangible benefit (even our iteration group members had storage issues while working on project) +- A complete testing overhaul could be a great focus for a new group– many testing fixes were added in the process of developing new features but the quality and consistency of some of the testing may be questionable. Focusing just on testing could result in more purposeful and effective testing + + --- @@ -367,7 +402,4 @@ Things to consider updating: - Ensure the download links are pointing to the latest version - Any videos/screenshots that have been updated - Any new feature(s) you want to showcase -- Add your names, headshots, and relevant information in the `contributors` section - ---- - +- Add your names, headshots, and relevant information in the `contributors` section \ No newline at end of file From 08dd9d6391a579abd22e0d4c1cd144c745adccef Mon Sep 17 00:00:00 2001 From: Rachel Dean Date: Thu, 13 Feb 2025 18:44:07 -0500 Subject: [PATCH 47/47] added changelog --- docs/DEV-README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/DEV-README.md b/docs/DEV-README.md index 8ba6b52af..d8ac783f4 100644 --- a/docs/DEV-README.md +++ b/docs/DEV-README.md @@ -286,6 +286,24 @@ Finally, if future iterators would like to completely cover the list of API-test --- +## v1.19.0 changelog (WebRTC fixes and updates): + +- WebRTC has officially been moved from “experimental features” to “core features”! + - Text channel improvements: + - Added “Add Answer” button and functionality to be able to complete a channel connection + - Completed functionality for two-way communication via text channel + - Debugged messaging in response window - now the remote user’s incoming messages are visible + - Video channel improvements: + - Enabled audio on video calls + - Added an audio toggle button for turning audio on and off + - Audio-only channel completed + - Finished implementing an audio channel begun by a previous group +- Updated dependencies and versions to un-deprecate the app and make it usable (see “How to download and test the application locally?”) +- Added a React Joyride tour to introduce users to the app and ease their introduction to it +- Added a refresh button to restart testing at any point with a new connection + +--- + ## Backlog from Iteration Groups v1.18 and v1.19 - Fix/Update GitHub Actions for Unit Testing