AvanzaCast/packages/broadcast-panel/public/post_token_to_studio.html

134 lines
5.4 KiB
HTML

<!doctype html>
<html>
<head><meta charset="utf-8"><title>Post Token to Studio (production)</title></head>
<body>
<h3>Post Token to Studio (production)</h3>
<div>
<label>Backend API URL: <input id="backendUrl" value="https://avanzacast-servertokens.bfzqqk.easypanel.host" style="width:400px" /></label>
</div>
<div>
<label>Room: <input id="room" value="studio-demo" /></label>
<label>Studio URL: <input id="studio" value="https://avanzacast-studio.bfzqqk.easypanel.host" style="width:400px" /></label>
</div>
<div>
<button id="run">Open Studio & Send Token</button>
</div>
<pre id="log"></pre>
<script>
function log(msg){ try{ const p = document.getElementById('log'); p.textContent += msg + '\n'; console.log(msg); }catch(e){} }
function setHash(msg){ try{ window.location.hash = encodeURIComponent(msg.slice(0,800)); }catch(e){} }
function shortId(len = 8){ return Math.random().toString(36).slice(2, 2 + len) }
// Listen for ACK from studio (real flow)
let lastPopup = null;
window.addEventListener('message', (e) => {
try{
const data = e.data || {};
if (data?.type === 'LIVEKIT_ACK'){
log('[ACK] from ' + (e.origin || 'unknown') + ' status=' + JSON.stringify(data.status || data));
// Optionally close popup if ack received
try{ if (lastPopup && !lastPopup.closed) { lastPopup.close(); log('[ACK] closed popup'); } }catch(err){}
}
}catch(err){ console.warn('message handler error', err) }
}, false);
// helper: handshake with popup - send PING until READY or timeout
function handshakeAndSendToken(win, targetOrigin, payload, timeoutMs = 8000) {
return new Promise((resolve, reject) => {
if (!win || win.closed) return reject(new Error('popup not available'))
let settled = false
const start = Date.now()
function cleanup() {
window.removeEventListener('message', onMessage)
clearInterval(pinger)
}
function onMessage(e) {
try {
if (!e?.data) return
const d = e.data
// ensure origin matches expected origin
if (typeof targetOrigin === 'string' && targetOrigin !== '*' && e.origin !== targetOrigin) return
if (d?.type === 'LIVEKIT_READY') {
if (settled) return
settled = true
try {
win.postMessage(Object.assign({ type: 'LIVEKIT_TOKEN' }, payload), targetOrigin)
log('[HANDSHAKE] LIVEKIT_READY received - token posted')
cleanup()
return resolve({ status: 'sent' })
} catch (err) {
cleanup()
return reject(err)
}
}
} catch (err) { console.debug('handshake message error', err) }
}
// ping interval
const pinger = setInterval(()=>{
try{
if (!win || win.closed) throw new Error('popup closed')
win.postMessage({ type: 'LIVEKIT_PING' }, targetOrigin)
}catch(err){ /* ignore - listener will catch closed */ }
}, 400)
window.addEventListener('message', onMessage)
// overall timeout -> fallback to redirect
const timer = setTimeout(()=>{
if (settled) return
settled = true
cleanup()
return reject(new Error('handshake timeout'))
}, timeoutMs)
})
}
async function runOnce(){
try{
// Read backendUrl from URL params first, then fallback to input field
const urlParams = new URLSearchParams(window.location.search);
const backendUrlParam = urlParams.get('backendUrl');
const backendUrl = (backendUrlParam || document.getElementById('backendUrl').value).replace(/\/$/, '')
const room = document.getElementById('room').value
const studio = document.getElementById('studio').value.replace(/\/$/, '')
const user = sessionStorage.getItem('avanzacast_user') || 'guest-' + shortId(4)
log('user from sessionStorage: ' + user)
log('creating session via backend API: ' + backendUrl + '/api/session')
const res = await fetch(`${backendUrl}/api/session`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ room, username: user, ttl: 300 })
})
if (!res.ok) { log('backend API error '+res.status); setHash('backend API error '+res.status); return }
const data = await res.json()
log('session created: id=' + data.id + ', studioUrl=' + data.studioUrl + ', redirectUrl=' + data.redirectUrl)
// Use the redirectUrl provided by backend (should point to production domain with token)
const redirectUrl = data.redirectUrl || data.studioUrl
if (!redirectUrl) { log('no redirectUrl or studioUrl in response'); return }
log('redirecting to: ' + redirectUrl)
setHash('redirecting to production')
window.location.href = redirectUrl
}catch(e){ log('error: ' + e); setHash('error: '+String(e)) }
}
document.getElementById('run').addEventListener('click', runOnce)
// Auto-run if ?auto=1 in URL (useful for headless testing)
try{
const params = new URLSearchParams(window.location.search)
if (params.get('auto') === '1') {
setTimeout(() => { runOnce() }, 300)
}
}catch(e){}
</script>
</body>
</html>