Files
gamestream-webtransport-proxy/gamestream-webtransport-proxy/webroot/index.js
T
restitux a11b4deb31 meta: WebTransport now works
- added a small frontend for starting
- added logic to serve the frontend
- split out the gamestream logic into a separate process
- added logic to scaffold the separate proxy process
2025-07-20 14:08:47 -06:00

206 lines
5.2 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');
// 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();
});