testapp: Add WebSocket blocking functionality

v2compatibility
CSantosM 2026-03-26 18:41:55 +01:00
parent 60878b7e12
commit cc403f944e
3 changed files with 98 additions and 3 deletions

View File

@ -183,3 +183,21 @@ mat-checkbox {
mat-checkbox:first-of-type { mat-checkbox:first-of-type {
margin-left: 0; margin-left: 0;
} }
/* WebSocket blocking button styles */
.ws-block-btn {
color: #ff9800 !important;
}
.ws-block-btn:hover {
color: #f57c00 !important;
}
.ws-block-persistent-btn {
color: #f44336 !important;
}
.ws-block-persistent-btn:hover {
color: #d32f2f !important;
}

View File

@ -124,9 +124,15 @@
<button class="message-btn" (click)="sendMessage()" title="Broadcast message"> <button class="message-btn" (click)="sendMessage()" title="Broadcast message">
<mat-icon aria-label="Send message button" style="font-size: 20px">chat</mat-icon> <mat-icon aria-label="Send message button" style="font-size: 20px">chat</mat-icon>
</button> </button>
<button class="network-drop-btn" (click)="simulateNetworkDrop()" title="Simulate network drop"> <button class="network-drop-btn" (click)="simulateNetworkDropGracefully()" title="Simulate graceful network drop">
<mat-icon aria-label="Simulate network drop button" style="font-size: 20px">wifi_off</mat-icon> <mat-icon aria-label="Simulate network drop button" style="font-size: 20px">wifi_off</mat-icon>
</button> </button>
<button class="ws-block-btn" (click)="simulateNetworkDropIntermittently()" title="Simulate intermitent network drop">
<mat-icon aria-label="Block WebSocket once" style="font-size: 20px">wifi_3_bar_alert</mat-icon>
</button>
<button class="ws-block-persistent-btn" (click)="simulateHardNetworkDrop()" title="Simulate hard network drop">
<mat-icon aria-label="Block WebSocket persistently" style="font-size: 20px">signal_wifi_off</mat-icon>
</button>
<button class="leave-btn" (click)="leaveSession()" title="Leave session"> <button class="leave-btn" (click)="leaveSession()" title="Leave session">
<mat-icon aria-label="Leave button">clear</mat-icon> <mat-icon aria-label="Leave button">clear</mat-icon>
</button> </button>

View File

@ -161,6 +161,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
republishPossible: boolean = false; republishPossible: boolean = false;
openviduError: any; openviduError: any;
// WebSocket blocking state
private originalWebSocketCtor: typeof WebSocket;
constructor( constructor(
private changeDetector: ChangeDetectorRef, private changeDetector: ChangeDetectorRef,
private dialog: MatDialog, private dialog: MatDialog,
@ -288,11 +291,79 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.subscribers = []; this.subscribers = [];
} }
private async simulateNetworkDrop(): Promise<void> { async simulateNetworkDropGracefully(): Promise<void> {
const jsonRpClient = this.OV.session.localParticipant.engine; const jsonRpClient = this.OV.session.localParticipant.engine;
await jsonRpClient.close(); await jsonRpClient.close();
} }
/**
* Block the WebSocket connection by closing it immediately.
* This simulates a transient network failure that may trigger reconnection.
*/
async simulateNetworkDropIntermittently(): Promise<void> {
if (!this.session) {
console.log('[WebSocket] No active session');
return;
}
try {
const signalClient = this.OV.session.localParticipant.engine.client;
if (!signalClient || !signalClient.ws) {
console.log('[WebSocket] Could not access WebSocket connection');
return;
}
signalClient.ws.close();
console.log('[WebSocket] Closed once (quick reconnect expected)');
} catch (error) {
console.error('[WebSocket] blockWebSocket error:', error);
}
}
/**
* Block WebSocket connections persistently by replacing the WebSocket constructor.
* All new socket connection attempts will be immediately closed.
* This simulates a persistent network blocking condition.
*/
async simulateHardNetworkDrop(): Promise<void> {
if (!this.session) {
console.log('[WebSocket] No active session');
return;
}
// Close current WebSocket if exists
try {
const signalClient = this.OV.session.localParticipant.engine.client;
if (signalClient && signalClient.ws) {
console.log('[WebSocket] Closing current WebSocket...');
signalClient.ws.close({ closeCode: 1000, reason: 'Simulating persistent WebSocket block' });
}
} catch (error) {
console.error('[WebSocket] Error closing current WebSocket:', error);
}
// Replace WebSocket constructor to block new connections
this.originalWebSocketCtor = window.WebSocket;
console.log('[WebSocket] Enabling persistent WebSocket block...');
const self = this;
(window as any).WebSocket = class BlockedWebSocket {
constructor(url: string | URL, protocols?: string | string[]) {
const wsInstance = new self.originalWebSocketCtor(url, protocols);
// Check if it's a signal WebSocket and block it
const urlStr = String(url).toLowerCase();
if (urlStr.startsWith('ws://') || urlStr.startsWith('wss://')) {
setTimeout(() => {
if (wsInstance.readyState === 0 || wsInstance.readyState === 1) {
wsInstance.close(4000, 'Simulated persistent WebSocket block');
}
}, 0);
}
return wsInstance;
}
} as typeof WebSocket;
}
updateEventList(eventName: string, eventContent: string, event: Event) { updateEventList(eventName: string, eventContent: string, event: Event) {
const eventInterface: OpenViduEvent = { eventName, eventContent, event }; const eventInterface: OpenViduEvent = { eventName, eventContent, event };
this.events.push(eventInterface); this.events.push(eventInterface);