134 lines
5.4 KiB
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>
|