225 lines
5.7 KiB
JavaScript
225 lines
5.7 KiB
JavaScript
class GameStreamingApp {
|
|
constructor() {
|
|
this.apps = [];
|
|
this.init();
|
|
}
|
|
|
|
async init() {
|
|
try {
|
|
await this.loadApps();
|
|
this.renderApps();
|
|
} catch (error) {
|
|
this.showError('Failed to load applications: ' + error.message);
|
|
}
|
|
}
|
|
|
|
async loadApps() {
|
|
try {
|
|
const response = await fetch('/api/apps');
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
this.apps = this.processAppsData(data);
|
|
} catch (error) {
|
|
console.error('Error loading apps:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
processAppsData(data) {
|
|
const apps = [];
|
|
if (data.apps) {
|
|
Object.keys(data.apps).forEach(serverName => {
|
|
data.apps[serverName].forEach(app => {
|
|
apps.push({
|
|
...app,
|
|
server: serverName
|
|
});
|
|
});
|
|
});
|
|
}
|
|
return apps;
|
|
}
|
|
|
|
renderApps() {
|
|
const contentDiv = document.getElementById('content');
|
|
|
|
if (this.apps.length === 0) {
|
|
contentDiv.innerHTML = '<div class="error">No applications found.</div>';
|
|
return;
|
|
}
|
|
|
|
const appsContainer = document.createElement('div');
|
|
appsContainer.className = 'apps-container';
|
|
|
|
this.apps.forEach(app => {
|
|
const appBox = this.createAppBox(app);
|
|
appsContainer.appendChild(appBox);
|
|
});
|
|
|
|
contentDiv.innerHTML = '';
|
|
contentDiv.appendChild(appsContainer);
|
|
}
|
|
|
|
createAppBox(app) {
|
|
const appBox = document.createElement('div');
|
|
appBox.className = 'app-box';
|
|
appBox.dataset.id = app.id;
|
|
appBox.dataset.server = app.server;
|
|
|
|
appBox.innerHTML = `
|
|
<div class="app-artwork">
|
|
<div class="play-button"></div>
|
|
</div>
|
|
<div class="app-title">${app.title}</div>
|
|
<div class="app-server">${app.server}</div>
|
|
`;
|
|
|
|
// Add click event listener
|
|
appBox.addEventListener('click', (e) => this.handleAppClick(e, app));
|
|
|
|
// Add click animation
|
|
appBox.addEventListener('mousedown', () => {
|
|
appBox.classList.add('clicked');
|
|
});
|
|
|
|
appBox.addEventListener('mouseup', () => {
|
|
setTimeout(() => {
|
|
appBox.classList.remove('clicked');
|
|
}, 150);
|
|
});
|
|
|
|
appBox.addEventListener('mouseleave', () => {
|
|
appBox.classList.remove('clicked');
|
|
});
|
|
|
|
return appBox;
|
|
}
|
|
|
|
async handleAppClick(event, app) {
|
|
event.preventDefault();
|
|
|
|
try {
|
|
console.log(`Starting stream for ${app.title} on ${app.server}`);
|
|
|
|
// Create the POST request payload
|
|
const payload = {
|
|
id: app.id,
|
|
server: app.server,
|
|
server_mode: {
|
|
fps: 60,
|
|
height: 1280,
|
|
width: 720
|
|
},
|
|
stream_config: {
|
|
bitrate_kbps: 5120,
|
|
mode: {
|
|
fps: 60,
|
|
height: 1280,
|
|
width: 720
|
|
}
|
|
}
|
|
};
|
|
|
|
// Make POST request to start stream
|
|
const response = await fetch('/api/stream/start', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(payload)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const streamData = await response.json();
|
|
console.log('Stream started:', streamData);
|
|
|
|
if (streamData.url && streamData.cert_hash) {
|
|
await this.connectToStream(streamData.url, streamData.cert_hash);
|
|
} else {
|
|
throw new Error('Response was missing required parameters');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error starting stream:', error);
|
|
alert('Failed to start stream: ' + error.message);
|
|
}
|
|
}
|
|
|
|
async connectToStream(url, cert_hash) {
|
|
const buffer = new Uint8Array(cert_hash);
|
|
console.log('Hash: ', buffer);
|
|
try {
|
|
console.log(`Connecting to stream`);
|
|
|
|
// Check if WebTransport is supported
|
|
if (!window.WebTransport) {
|
|
throw new Error('WebTransport is not supported in this browser');
|
|
}
|
|
|
|
//const url = new URL();
|
|
const transport = new WebTransport(url, {
|
|
serverCertificateHashes: [
|
|
{
|
|
algorithm: "sha-256",
|
|
value: buffer,
|
|
}
|
|
]
|
|
});
|
|
|
|
console.log('Connecting to WebTransport at ', url);
|
|
// Wait for the connection to be ready
|
|
await transport.ready;
|
|
console.log('WebTransport connection established');
|
|
|
|
|
|
console.log('Creating WebTransport bidirectional stream');
|
|
const stream = await transport.createBidirectionalStream();
|
|
console.log('Bidirectional stream created');
|
|
|
|
const reader = stream.readable.getReader();
|
|
|
|
// Handle incoming data
|
|
async function readData() {
|
|
while (true) {
|
|
const { value, done } = await reader.read();
|
|
if (done) break;
|
|
console.log(value)
|
|
//console.log(`Received: ${new TextDecoder().decode(value)}`);
|
|
}
|
|
}
|
|
|
|
readData();
|
|
|
|
// Handle connection close
|
|
transport.closed.then(() => {
|
|
console.log('WebTransport connection closed');
|
|
}).catch((error) => {
|
|
console.error('WebTransport connection closed with error:', error);
|
|
});
|
|
|
|
// You can add more WebTransport handling logic here
|
|
// For example, handling incoming streams, sending data, etc.
|
|
|
|
} catch (error) {
|
|
console.error('Error connecting to stream:', error);
|
|
alert('Failed to connect to stream: ' + error.message);
|
|
}
|
|
}
|
|
|
|
showError(message) {
|
|
const contentDiv = document.getElementById('content');
|
|
contentDiv.innerHTML = `<div class="error">${message}</div>`;
|
|
}
|
|
}
|
|
|
|
// Initialize the app when the page loads
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
new GameStreamingApp();
|
|
});
|
|
|