Skip to content

Commit

Permalink
fix(dgw): fallback to recording playback when shadowing is not possib…
Browse files Browse the repository at this point in the history
…le (#1181)
  • Loading branch information
irvingoujAtDevolution authored Jan 9, 2025
1 parent 651d8cf commit 8cb4c66
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
18 changes: 17 additions & 1 deletion webapp/player-project/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { GatewayAccessApi } from './gateway';
import { getPlayer } from './players/index.js';
import { getShadowPlayer } from './streamers/index.js';
import { cleanUpStreamers, getShadowPlayer } from './streamers/index.js';
import './ws-proxy.ts';
import { OnBeforeClose as BeforeWebsocketClose } from './ws-proxy.ts';

async function main() {
const { sessionId, token, gatewayAccessUrl, isActive } = getSessionDetails();
Expand All @@ -23,6 +25,20 @@ async function playSessionShadowing(gatewayAccessApi) {
try {
const recordingInfo = await gatewayAccessApi.fetchRecordingInfo();
const fileType = getFileType(recordingInfo);
BeforeWebsocketClose((closeEvent) => {
if (closeEvent.code !== 1000) {
// The session playback failed; attempt to play the recording as usual as a fallback.
cleanUpStreamers();
playStaticRecording(gatewayAccessApi);
return {
...closeEvent,
// This prevents extra handling by other listeners, particularly for asciinema-player in this scenario.
// For more details, see the asciinema-player WebSocket driver’s socket close handler.
// https://github.com/asciinema/asciinema-player/blob/c09e1d2625450a32e9e76063cdc315fd54ecdd9d/src/driver/websocket.js#L219
code: 1000,
};
}
});

getShadowPlayer(fileType).play(gatewayAccessApi);
} catch (error) {
Expand Down
11 changes: 10 additions & 1 deletion webapp/player-project/src/streamers/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GatewayAccessApi } from '../gateway';
import { removeTerminal } from '../terminal';
import { handleCast } from './cast';
import { handleWebm } from './webm';

export const getShadowPlayer = (fileType) => {
const player = {
play: (_: GatewayAccessApi) => {},
Expand All @@ -17,3 +17,12 @@ export const getShadowPlayer = (fileType) => {

return player;
};

export const cleanUpStreamers = () => {
// Remove all shadow-player elements.
const shadowPlayers = document.querySelectorAll('shadow-player');
for (const shadowPlayer of shadowPlayers) {
shadowPlayer.remove();
}
removeTerminal();
};
7 changes: 7 additions & 0 deletions webapp/player-project/src/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export function createTerminalDiv() {
document.body.appendChild(terminalDiv);
return terminalDiv;
}

export function removeTerminal() {
const terminalDiv = document.getElementById('terminal');
if (terminalDiv) {
terminalDiv.remove();
}
}
45 changes: 45 additions & 0 deletions webapp/player-project/src/ws-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
let beforeClose = (args: CloseEvent): CloseEvent => {
return args;
};

export const OnBeforeClose = (callback: (args: CloseEvent) => CloseEvent) => {
beforeClose = callback;
};

const WebSocketProxy = new Proxy(window.WebSocket, {
construct(target, args: [url: string | URL, protocols?: string | string[]]) {
console.log('Proxying WebSocket connection', ...args);
const ws = new target(...args); // Create the actual WebSocket instance

// Proxy for intercepting `addEventListener`
ws.addEventListener = new Proxy(ws.addEventListener, {
apply(target, thisArg, args) {
if (args[0] === 'close') {
console.log('Intercepted addEventListener for close event');
const transformedArgs = beforeClose(args as unknown as CloseEvent);
return target.apply(thisArg, transformedArgs);
}
return target.apply(thisArg, args);
},
});

// Proxy for intercepting `onclose`
return new Proxy(ws, {
set(target, prop, value) {
if (prop === 'onclose') {
console.log('Intercepted setting of onclose');
const transformedValue = (...args) => {
const transformedArgs = beforeClose(args as unknown as CloseEvent);
if (typeof value === 'function') {
value(transformedArgs); // Call the original handler
}
};
return Reflect.set(target, prop, transformedValue);
}
return Reflect.set(target, prop, value);
},
});
},
});

window.WebSocket = WebSocketProxy;

0 comments on commit 8cb4c66

Please sign in to comment.