Skip to content

Commit

Permalink
feat(dgw): shadowing player web-component (#1075)
Browse files Browse the repository at this point in the history
  • Loading branch information
irvingoujAtDevolution authored Oct 29, 2024
1 parent 4138b52 commit 5169f60
Show file tree
Hide file tree
Showing 18 changed files with 2,604 additions and 0 deletions.
24 changes: 24 additions & 0 deletions webapp/shadow-player/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
128 changes: 128 additions & 0 deletions webapp/shadow-player/demo-src/apiClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Base URL of the API
const TOKEN_SERVER_BASE_URL = 'http://localhost:8080';
const GATEWAY_BASE_URL = 'http://localhost:7171';

// Common request fields
interface CommonRequest {
validity_duration?: string;
kid?: string;
delegation_key_path?: string;
jet_gw_id?: string;
}

// Response type
interface TokenResponse {
token: string;
}

// Scope request interface
interface ScopeRequest extends CommonRequest {
scope: string;
}

export async function requestScopeToken(data: ScopeRequest): Promise<TokenResponse> {
try {
const response = await fetch(`${TOKEN_SERVER_BASE_URL}/scope`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

if (!response.ok) {
const errorResponse = await response.json();
throw new Error(`Error ${response.status}: ${JSON.stringify(errorResponse)}`);
}

return await response.json();
} catch (error) {
throw new Error(`Error: ${error.message}`);
}
}

// Function to list recordings
export async function listRealtimeRecordings(): Promise<string[]> {
const res = await requestScopeToken({ scope: 'gateway.recordings.read' });
try {
const response = await fetch(`${GATEWAY_BASE_URL}/jet/jrec/list/realtime`, {
method: 'GET',
headers: {
Authorization: `Bearer ${res.token}`,
},
});

if (!response.ok) {
const errorResponse = await response.json();
throw new Error(`Error ${response.status}: ${JSON.stringify(errorResponse)}`);
}

return await response.json();
} catch (error: any) {
throw new Error(`Error: ${error.message}`);
}
}

interface PullTokenRequest extends CommonRequest {
jet_rop: 'pull';
jet_aid: string;
}

export async function requestPullToken(data: PullTokenRequest): Promise<TokenResponse> {
try {
const response = await fetch(`${TOKEN_SERVER_BASE_URL}/jrec`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

if (!response.ok) {
const errorResponse = await response.json();
throw new Error(`Error ${response.status}: ${JSON.stringify(errorResponse)}`);
}

return await response.json();
} catch (error: any) {
throw new Error(`Error: ${error.message}`);
}
}

interface GetInfoFileResponse {
duration: number;
files: {
fileName: string;
startTime: number;
duration: number;
};
sessionId: string;
startTime: number;
}

export async function getInfoFile(uid: string): Promise<GetInfoFileResponse> {
const pullFileToken = await requestPullToken({ jet_rop: 'pull', jet_aid: uid });
try {
const response = await fetch(`${GATEWAY_BASE_URL}/jet/jrec/pull/${uid}/recording.json`, {
method: 'GET',
headers: {
Authorization: `Bearer ${pullFileToken.token}`,
},
});

if (!response.ok) {
const errorResponse = await response.json();
throw new Error(`Error ${response.status}: ${JSON.stringify(errorResponse)}`);
}

return await response.json();
} catch (error: any) {
throw new Error(`Error: ${error.message}`);
}
}

export async function getStreamingWebsocketUrl(uid: string): Promise<string> {
const fileInfo = await getInfoFile(uid);
const token = await requestPullToken({ jet_rop: 'pull', jet_aid: uid });
return `${GATEWAY_BASE_URL}/jet/jrec/realtime/${uid}/${fileInfo.files[0].fileName}?token=${token.token}`;
}
10 changes: 10 additions & 0 deletions webapp/shadow-player/demo-src/paly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getInfoFile, getStreamingWebsocketUrl } from './apiClient';
import { ShadowPlayer } from '../src/streamer';

// Function to play the selected stream
export async function playStream(id: string) {
const websocketUrl = await getStreamingWebsocketUrl(id);

const videoElement = document.getElementById('shadowPlayer') as ShadowPlayer;
videoElement.srcChange(websocketUrl);
}
54 changes: 54 additions & 0 deletions webapp/shadow-player/demo-src/ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

import { listRealtimeRecordings } from './apiClient';
import { playStream } from './paly';

// Function to populate the file list
async function populateFileList() {
const files = await listRealtimeRecordings();

const fileList = document.getElementById('fileList');
if (!fileList) {
console.error('File list not found');
return;
}

fileList.innerHTML = ''; // Clear existing items

files.forEach((file, index) => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';

const fileName = document.createElement('span');
fileName.className = 'file-name';
fileName.textContent = file;

const playButton = document.createElement('button');
playButton.className = 'play-button';
playButton.textContent = 'Play';
playButton.onclick = () => playStream(file);

fileItem.appendChild(fileName);
fileItem.appendChild(playButton);

fileList.appendChild(fileItem);
});
}

// Initialize the file list on page load
window.onload = populateFileList;

export function refreshList() {
// Logic to refresh the list can be added here
// For now, we'll just re-populate the list
populateFileList();
}

export const getElementNotNull = (id: string) => {
const element = document.getElementById(id);
if (!element) {
throw new Error(`Element with ID ${id} not found`);
}
return element;
};

getElementNotNull('refreshButton').onclick = refreshList;
129 changes: 129 additions & 0 deletions webapp/shadow-player/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Streaming Dashboard</title>
<style>
body {
margin: 0;
font-family: Arial, sans-serif;
}

.container {
display: flex;
height: 100vh;
}

.sidebar {
width: 30%;
background-color: #f4f4f4;
border-right: 1px solid #ddd;
display: flex;
flex-direction: column;
}

.sidebar-header {
padding: 20px;
background-color: #fff;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
}

.sidebar-header h2 {
margin: 0;
font-size: 18px;
}

.refresh-button {
padding: 8px 12px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}

.refresh-button:hover {
background-color: #0056b3;
}

.file-list {
flex: 1;
overflow-y: auto;
padding: 10px;
}

.file-item {
padding: 10px;
margin-bottom: 10px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}

.file-name {
font-size: 16px;
}

.play-button {
padding: 6px 10px;
background-color: #28a745;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}

.play-button:hover {
background-color: #218838;
}

.player-container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background-color: #e9ecef;
}

webm-stream-player {
width: 80%;
height: 80%;
background-color: #000;
}
</style>
</head>

<body>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<div class="sidebar-header">
<h2>Streaming Files</h2>
<button class="refresh-button" id="refreshButton">Refresh</button>
</div>
<div class="file-list" id="fileList">
<!-- File items will be populated here -->
</div>
</div>

<!-- Main Content -->
<div class="player-container">
<shawdow-player id="shadowPlayer"></shawdow-player>
</div>
</div>

<script type="module" src="/src/main.ts"></script>
<script type="module" src="index.ts"></script>

</body>

</html>
2 changes: 2 additions & 0 deletions webapp/shadow-player/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Demo for using the webm-stream-player element.
import './demo-src/ui';
Loading

0 comments on commit 5169f60

Please sign in to comment.