Assist add turn servers (#3229)

* fixed conflicts

* add offers

* add config to sicket query

* add config to sicket query

* add config init

* removed console logs

* removed wrong updates

* fixed conflicts

* add offers

* add config to sicket query

* add config to sicket query

* add config init

* removed console logs

* removed wrong updates

* ui: fix chat draggable, fix default params

---------

Co-authored-by: nick-delirium <nikita@openreplay.com>
This commit is contained in:
Andrey Babushkin 2025-03-28 18:27:01 +03:00 committed by GitHub
parent 437a25fb97
commit 421b3d1dc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 44 additions and 37 deletions

View file

@ -118,7 +118,7 @@ async function onConnect(socket) {
// Stats // Stats
startAssist(socket, socket.handshake.query.agentID); startAssist(socket, socket.handshake.query.agentID);
} }
socket.to(socket.handshake.query.roomId).emit(EVENTS_DEFINITION.emit.NEW_AGENT, socket.id, socket.handshake.query.agentInfo); socket.to(socket.handshake.query.roomId).emit(EVENTS_DEFINITION.emit.NEW_AGENT, socket.id, { ...socket.handshake.query.agentInfo, config: socket.handshake.query.config });
} }
// Set disconnect handler // Set disconnect handler

View file

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import cn from 'classnames'; import cn from 'classnames';
import Counter from 'App/components/shared/SessionItem/Counter'; import Counter from 'App/components/shared/SessionItem/Counter';
import Draggable from 'react-draggable'; import { useDraggable } from '@neodrag/react';
import type { LocalStream } from 'Player'; import type { LocalStream } from 'Player';
import { PlayerContext } from 'App/components/Session/playerContext'; import { PlayerContext } from 'App/components/Session/playerContext';
import ChatControls from '../ChatControls/ChatControls'; import ChatControls from '../ChatControls/ChatControls';
@ -25,6 +25,8 @@ function ChatWindow({
isPrestart, isPrestart,
}: Props) { }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
const dragRef = React.useRef<HTMLDivElement>(null);
useDraggable(dragRef, { bounds: 'body', defaultPosition: { x: 50, y: 200 } })
const { player } = React.useContext(PlayerContext); const { player } = React.useContext(PlayerContext);
const { toggleVideoLocalStream } = player.assistManager; const { toggleVideoLocalStream } = player.assistManager;
@ -39,11 +41,7 @@ function ChatWindow({
}, [localVideoEnabled]); }, [localVideoEnabled]);
return ( return (
<Draggable <div ref={dragRef}>
handle=".handle"
bounds="body"
defaultPosition={{ x: 50, y: 200 }}
>
<div <div
className={cn(stl.wrapper, 'fixed radius bg-white shadow-xl mt-16')} className={cn(stl.wrapper, 'fixed radius bg-white shadow-xl mt-16')}
style={{ width: '280px' }} style={{ width: '280px' }}
@ -102,7 +100,7 @@ function ChatWindow({
isPrestart={isPrestart} isPrestart={isPrestart}
/> />
</div> </div>
</Draggable> </div>
); );
} }

View file

@ -203,6 +203,7 @@ export default class AssistManager {
peerId: this.peerID, peerId: this.peerID,
query: document.location.search, query: document.location.search,
}), }),
config: JSON.stringify(this.getIceServers()),
}, },
})); }));
@ -317,7 +318,7 @@ export default class AssistManager {
this.callManager = new Call( this.callManager = new Call(
this.store, this.store,
socket, socket,
this.config, this.getIceServers(),
this.peerID, this.peerID,
this.getAssistVersion, this.getAssistVersion,
{ {
@ -357,6 +358,23 @@ export default class AssistManager {
}); });
} }
private getIceServers = () => {
if (this.config) {
return this.config;
}
return [
{
urls: [
'stun:stun.l.google.com:19302',
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
'stun:stun3.l.google.com:19302',
'stun:stun4.l.google.com:19302'
],
},
] as RTCIceServer[];
};
/** /**
* Sends event ping to stats service * Sends event ping to stats service
* */ * */

View file

@ -43,7 +43,7 @@ export default class Call {
constructor( constructor(
private store: Store<State & { tabs: Set<string> }>, private store: Store<State & { tabs: Set<string> }>,
private socket: Socket, private socket: Socket,
private config: RTCIceServer[] | null, private config: RTCIceServer[],
private peerID: string, private peerID: string,
private getAssistVersion: () => number, private getAssistVersion: () => number,
private agent: Record<string, any>, private agent: Record<string, any>,
@ -146,7 +146,7 @@ export default class Call {
// create pc with ice config // create pc with ice config
const pc = new RTCPeerConnection({ const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }], iceServers: this.config,
}); });
// If there is a local stream, add its tracks to the connection // If there is a local stream, add its tracks to the connection

View file

@ -27,6 +27,7 @@
"@codewonders/html2canvas": "^1.0.2", "@codewonders/html2canvas": "^1.0.2",
"@eslint/js": "^9.21.0", "@eslint/js": "^9.21.0",
"@medv/finder": "^4.0.2", "@medv/finder": "^4.0.2",
"@neodrag/react": "^2.3.0",
"@sentry/browser": "^5.21.1", "@sentry/browser": "^5.21.1",
"@svg-maps/world": "^1.0.1", "@svg-maps/world": "^1.0.1",
"@tanstack/react-query": "^5.56.2", "@tanstack/react-query": "^5.56.2",
@ -71,7 +72,6 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^15.1.2", "react-dnd-html5-backend": "^15.1.2",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-draggable": "^4.4.5",
"react-google-recaptcha": "^2.1.0", "react-google-recaptcha": "^2.1.0",
"react-i18next": "^15.4.1", "react-i18next": "^15.4.1",
"react-intersection-observer": "^9.13.1", "react-intersection-observer": "^9.13.1",

View file

@ -2584,6 +2584,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@neodrag/react@npm:^2.3.0":
version: 2.3.0
resolution: "@neodrag/react@npm:2.3.0"
checksum: 10c1/37f549ad0bdab8badb0799bf4e6f1714fe52a2ace6c09447a9dc97a9483a0fb40f75b35b121c78a1cba3a27ec9076a5db9672454af3a216d9efee8dcd34c6736
languageName: node
linkType: hard
"@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3": "@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3":
version: 2.1.8-no-fsevents.3 version: 2.1.8-no-fsevents.3
resolution: "@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3" resolution: "@nicolo-ribaudo/chokidar-2@npm:2.1.8-no-fsevents.3"
@ -5541,13 +5548,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"clsx@npm:^1.1.1":
version: 1.2.1
resolution: "clsx@npm:1.2.1"
checksum: 10c1/45d7148b63e9ec9c32bd31f8289f1c52f1ca6c3a392a0d60978c8590faa71f4a9a3acef0a71eb3492a672a3cebc6019230799bfc59ec2e96b5f32eb58fe0976f
languageName: node
linkType: hard
"clsx@npm:^2.0.0, clsx@npm:^2.1.0": "clsx@npm:^2.0.0, clsx@npm:^2.1.0":
version: 2.1.1 version: 2.1.1
resolution: "clsx@npm:2.1.1" resolution: "clsx@npm:2.1.1"
@ -11947,6 +11947,7 @@ __metadata:
"@eslint/js": "npm:^9.21.0" "@eslint/js": "npm:^9.21.0"
"@jest/globals": "npm:^29.7.0" "@jest/globals": "npm:^29.7.0"
"@medv/finder": "npm:^4.0.2" "@medv/finder": "npm:^4.0.2"
"@neodrag/react": "npm:^2.3.0"
"@openreplay/sourcemap-uploader": "npm:^3.0.10" "@openreplay/sourcemap-uploader": "npm:^3.0.10"
"@sentry/browser": "npm:^5.21.1" "@sentry/browser": "npm:^5.21.1"
"@svg-maps/world": "npm:^1.0.1" "@svg-maps/world": "npm:^1.0.1"
@ -12034,7 +12035,6 @@ __metadata:
react-dnd: "npm:^16.0.1" react-dnd: "npm:^16.0.1"
react-dnd-html5-backend: "npm:^15.1.2" react-dnd-html5-backend: "npm:^15.1.2"
react-dom: "npm:^19.0.0" react-dom: "npm:^19.0.0"
react-draggable: "npm:^4.4.5"
react-google-recaptcha: "npm:^2.1.0" react-google-recaptcha: "npm:^2.1.0"
react-i18next: "npm:^15.4.1" react-i18next: "npm:^15.4.1"
react-intersection-observer: "npm:^9.13.1" react-intersection-observer: "npm:^9.13.1"
@ -14004,19 +14004,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-draggable@npm:^4.4.5":
version: 4.4.6
resolution: "react-draggable@npm:4.4.6"
dependencies:
clsx: "npm:^1.1.1"
prop-types: "npm:^15.8.1"
peerDependencies:
react: ">= 16.3.0"
react-dom: ">= 16.3.0"
checksum: 10c1/b8ae807f4556b658ae149b6542af5222d75996da47c549db54be22276579549ca2cd2fd06ca5c0852fbd1b663853cc0568b68215bd6e62433b46a7e154ddf8e2
languageName: node
linkType: hard
"react-fit@npm:^2.0.0": "react-fit@npm:^2.0.0":
version: 2.0.1 version: 2.0.1
resolution: "react-fit@npm:2.0.1" resolution: "react-fit@npm:2.0.1"

View file

@ -20,6 +20,7 @@ import { gzip } from 'fflate'
type StartEndCallback = (agentInfo?: Record<string, any>) => ((() => any) | void) type StartEndCallback = (agentInfo?: Record<string, any>) => ((() => any) | void)
interface AgentInfo { interface AgentInfo {
config: string;
email: string; email: string;
id: number id: number
name: string name: string
@ -85,6 +86,7 @@ export default class Assist {
private remoteControl: RemoteControl | null = null; private remoteControl: RemoteControl | null = null;
private peerReconnectTimeout: ReturnType<typeof setTimeout> | null = null private peerReconnectTimeout: ReturnType<typeof setTimeout> | null = null
private agents: Record<string, Agent> = {} private agents: Record<string, Agent> = {}
private config: RTCIceServer[] | undefined
private readonly options: Options private readonly options: Options
private readonly canvasMap: Map<number, Canvas> = new Map() private readonly canvasMap: Map<number, Canvas> = new Map()
@ -254,7 +256,7 @@ export default class Assist {
return return
} }
if (args[0] !== 'webrtc_call_ice_candidate') { if (args[0] !== 'webrtc_call_ice_candidate') {
app.debug.log('Socket:', ...args) app.debug.log("Socket:", ...args);
}; };
socket.on('close', (e) => { socket.on('close', (e) => {
app.debug.warn('Socket closed:', e); app.debug.warn('Socket closed:', e);
@ -356,6 +358,9 @@ export default class Assist {
this.app.stop() this.app.stop()
this.app.clearBuffers() this.app.clearBuffers()
this.app.waitStatus(0) this.app.waitStatus(0)
.then(() => {
this.config = JSON.parse(info.config);
})
.then(() => { .then(() => {
this.app.allowAppStart() this.app.allowAppStart()
setTimeout(() => { setTimeout(() => {
@ -595,7 +600,7 @@ export default class Assist {
// create a new RTCPeerConnection with ice server config // create a new RTCPeerConnection with ice server config
const pc = new RTCPeerConnection({ const pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }], iceServers: this.config,
}); });
if (!callUI) { if (!callUI) {
@ -736,7 +741,7 @@ export default class Assist {
if (!this.canvasPeers[uniqueId]) { if (!this.canvasPeers[uniqueId]) {
this.canvasPeers[uniqueId] = new RTCPeerConnection({ this.canvasPeers[uniqueId] = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }], iceServers: this.config,
}); });
this.setupPeerListeners(uniqueId); this.setupPeerListeners(uniqueId);
@ -750,7 +755,6 @@ export default class Assist {
// Send offer via signaling server // Send offer via signaling server
socket.emit('webrtc_canvas_offer', { offer, id: uniqueId }); socket.emit('webrtc_canvas_offer', { offer, id: uniqueId });
} }
} }
} }