-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dgw): shadowing player web-component (#1075)
- Loading branch information
1 parent
4138b52
commit 5169f60
Showing
18 changed files
with
2,604 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; |
Oops, something went wrong.