feat: add environment configuration files and update WHIP server URL handling
This commit is contained in:
parent
bc97ee0a68
commit
62a6697d7d
21
.env.example
Normal file
21
.env.example
Normal file
@ -0,0 +1,21 @@
|
||||
# Environment variables for local development
|
||||
# Set your YouTube Data API v3 key here (do NOT commit real keys to public repos)
|
||||
YOUTUBE_API_KEY="AIzaSyABiXKk-1tcoR0wQnccZfutBDi0ijTr0Ko"
|
||||
REACT_APP_CORE_URL=https://restreamer.nextream.sytes.net
|
||||
#REACT_APP_YTDLP_URL=http://100.73.244.28:8080
|
||||
REACT_APP_YTDLP_URL=http://144.217.82.82:8282
|
||||
REACT_APP_YTDLP_URL_TITLES=http://100.73.244.28:8080
|
||||
# URL que la UI usa para construir el input WHEP del Core.
|
||||
# Apunta al mismo dominio del UI — Caddy proxea /whep/* → egress server.
|
||||
REACT_APP_WHIP_SERVER_URL=https://djmaster.nextream.sytes.net
|
||||
# Vars REACT_APP_ expuestas al browser (CRA las inyecta en el bundle).
|
||||
# La UI llama a IngressClient directamente sin intermediario Node.
|
||||
REACT_APP_LIVEKIT_API_KEY=APIBTqTGxf9htMK
|
||||
REACT_APP_LIVEKIT_API_SECRET=0dOHWPffwneaPg7OYpe4PeAes21zLJfeYJB9cKzSTtXW
|
||||
REACT_APP_LIVEKIT_WS_URL=wss://livekit-server.nextream.sytes.net
|
||||
LIVEKIT_INGRESS_INTERNAL_URL=http://192.168.1.20:8088
|
||||
LIVEKIT_INGRESS_HOST=192.168.1.20:8088
|
||||
UI_BASE_URL=https://djmaster.nextream.sytes.net
|
||||
# Destino local del proxy de desarrollo para /api/whip/* y /whep/* (CRA setupProxy).
|
||||
# NO confundir con REACT_APP_WHIP_SERVER_URL (esa es la URL pública para el frontend).
|
||||
WHIP_API_TARGET=http://localhost:3005
|
||||
@ -1,8 +1,8 @@
|
||||
# Local overrides (gitignored). Put real secrets here on your development machine.
|
||||
REACT_APP_YOUTUBE_API_KEY="AIzaSyABiXKk-1tcoR0wQnccZfutBDi0ijTr0Ko"
|
||||
REACT_APP_CORE_URL=https://restreamer.nextream.sytes.net
|
||||
REACT_APP_WHIP_BASE_URL=http://192.168.1.15:8555
|
||||
REACT_APP_YTDLP_URL=http://144.217.82.82:8282
|
||||
REACT_APP_CORE_URL=http://192.168.1.20:8080
|
||||
REACT_APP_WHIP_BASE_URL=http://192.168.1.20:8555
|
||||
REACT_APP_YTDLP_URL=http://192.168.1.20:8282
|
||||
REACT_APP_YTDLP_URL_TITLES=http://100.73.244.28:8080
|
||||
REACT_APP_FB_SERVER_URL=http://localhost:3002
|
||||
REACT_APP_LIVEKIT_API_KEY=APIBTqTGxf9htMK
|
||||
|
||||
121
nginx-examples/djmaster.http.conf.template
Normal file
121
nginx-examples/djmaster.http.conf.template
Normal file
@ -0,0 +1,121 @@
|
||||
# djmaster HTTP-only Nginx template
|
||||
# Use this when another front-facing proxy/terminator handles TLS and you want
|
||||
# Nginx to listen on port 80 (cleartext) and proxy to local backends.
|
||||
|
||||
# Map for websocket upgrade handling
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${UI_HOST};
|
||||
|
||||
client_max_body_size 512M;
|
||||
client_body_timeout 300s;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Frontend (UI) — proxy to your UI backend (webpack dev or static server)
|
||||
# Set UI_BACKEND_HOST to 192.168.1.15 (or 127.0.0.1) when rendering
|
||||
location / {
|
||||
proxy_pass http://${UI_BACKEND_HOST}:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
# WebSocket endpoint (HMR / app ws) — ensure upgrades are forwarded
|
||||
location /ws {
|
||||
proxy_pass http://${UI_BACKEND_HOST}:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Microserver for OAuth and config persistence
|
||||
location /fb-server/ {
|
||||
proxy_pass http://${MICROSERVER_HOST}:3002/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
# WHIP Ingest API and WHEP relay (egress). If your egress listens elsewhere,
|
||||
# adjust ${WHIP_HOST} and ports accordingly.
|
||||
location /api/whip/ {
|
||||
proxy_pass http://${WHIP_HOST}:3005/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location /whep/ {
|
||||
proxy_pass http://${WHIP_HOST}:3005/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
# WHIP ingest (POST with SDP) — forward to livekit-ingress/internal target
|
||||
location /w/ {
|
||||
proxy_pass http://${LIVEKIT_INGRESS_HOST}/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
# yt-dlp stream extractor and metadata proxies
|
||||
location /yt-stream/ {
|
||||
proxy_pass http://${YTDLP_HOST}/;
|
||||
proxy_set_header Host ${YTDLP_HOST};
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location /yt-titles/ {
|
||||
proxy_pass http://${YTDLP_TITLES_HOST}/;
|
||||
proxy_set_header Host ${YTDLP_TITLES_HOST};
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
# Basic security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
}
|
||||
@ -21,13 +21,51 @@
|
||||
* FB_SERVER_URL = '' (leave empty — Caddy proxies /fb-server → localhost:3002)
|
||||
*/
|
||||
window.__RESTREAMER_CONFIG__ = {
|
||||
CORE_ADDRESS: '',
|
||||
CORE_ADDRESS: 'http://192.168.1.20:8080',
|
||||
YTDLP_URL: '',
|
||||
YTDLP_TITLES_URL: '',
|
||||
FB_SERVER_URL: '',
|
||||
// URL pública del servidor egress (WHIP ingest + WHEP relay).
|
||||
// Ej: 'https://llmchats-whep.zuqtxy.easypanel.host'
|
||||
WHIP_SERVER_URL: '',
|
||||
// Se fija explícitamente para respetar las variables locales.
|
||||
WHIP_SERVER_URL: 'http://192.168.1.20:8555',
|
||||
// Optional: override the WHIP port used when deriving from CORE_ADDRESS
|
||||
WHIP_PORT: '',
|
||||
};
|
||||
|
||||
// Derive WHIP_SERVER_URL at runtime if not explicitly provided.
|
||||
(function () {
|
||||
try {
|
||||
var cfg = window.__RESTREAMER_CONFIG__ || {};
|
||||
|
||||
// helper to derive from a base URL and a port
|
||||
function deriveFrom(base, port) {
|
||||
if (!base) return '';
|
||||
try {
|
||||
var u = new URL(base);
|
||||
var p = port && port.length ? port : '8555';
|
||||
return u.protocol + '//' + u.hostname + (p ? ':' + p : '');
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if ((!cfg.WHIP_SERVER_URL || cfg.WHIP_SERVER_URL.length === 0)) {
|
||||
// prefer explicit CORE_ADDRESS runtime value
|
||||
if (cfg.CORE_ADDRESS && cfg.CORE_ADDRESS.length) {
|
||||
var derived = deriveFrom(cfg.CORE_ADDRESS, cfg.WHIP_PORT);
|
||||
if (derived) cfg.WHIP_SERVER_URL = derived;
|
||||
} else if (window && window.location && window.location.origin) {
|
||||
// fallback to current origin
|
||||
var derived2 = deriveFrom(window.location.origin, cfg.WHIP_PORT);
|
||||
if (derived2) cfg.WHIP_SERVER_URL = derived2;
|
||||
}
|
||||
}
|
||||
|
||||
window.__RESTREAMER_CONFIG__ = cfg;
|
||||
} catch (e) {
|
||||
// no-op
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
186
scripts/check-whip-obs-live.js
Normal file
186
scripts/check-whip-obs-live.js
Normal file
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-whip-obs-live.js
|
||||
*
|
||||
* Verifica de forma E2E que un publisher WHIP (ej. OBS) está enviando al
|
||||
* endpoint proporcionado. Realiza:
|
||||
* - OPTIONS al endpoint WHIP (comprobación básica)
|
||||
* - GET al endpoint /whip/<key>/sdp (si está disponible)
|
||||
* - Polling a Core: GET <CORE_URL>/api/v3/whip para detectar el stream activo
|
||||
*
|
||||
* Uso:
|
||||
* node scripts/check-whip-obs-live.js --url "http://192.168.1.15:8555/whip/06a2..." --token heavy666 --core http://192.168.1.15:8080 --timeout 30
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
|
||||
function parseArgs() {
|
||||
const out = {};
|
||||
const argv = process.argv.slice(2);
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const a = argv[i];
|
||||
if (a.startsWith('--')) {
|
||||
const k = a.replace(/^--/, '');
|
||||
const v = (argv[i+1] && !argv[i+1].startsWith('--')) ? argv[++i] : 'true';
|
||||
out[k] = v;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function request(url, { method = 'GET', headers = {}, body, timeout = 15000 } = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
const lib = u.protocol === 'https:' ? https : http;
|
||||
const raw = body;
|
||||
const opts = {
|
||||
hostname: u.hostname,
|
||||
port: u.port || (u.protocol === 'https:' ? 443 : 80),
|
||||
path: u.pathname + (u.search || ''),
|
||||
method,
|
||||
headers: { ...headers },
|
||||
timeout,
|
||||
rejectUnauthorized: false,
|
||||
};
|
||||
|
||||
const req = lib.request(opts, (res) => {
|
||||
let buf = '';
|
||||
res.on('data', (c) => (buf += c));
|
||||
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: buf }));
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.on('timeout', () => { req.destroy(new Error('timeout')); });
|
||||
if (raw) req.write(raw);
|
||||
req.end();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = parseArgs();
|
||||
|
||||
const WHIP_URL = args.url || process.env.WHIP_URL;
|
||||
const TOKEN = args.token || process.env.WHIP_TOKEN || '';
|
||||
const CORE_URL = args.core || process.env.CORE_URL || process.env.REACT_APP_CORE_URL || 'http://127.0.0.1:8080';
|
||||
const TIMEOUT = parseInt(args.timeout || process.env.WHIP_CHECK_TIMEOUT || '30', 10);
|
||||
const INTERVAL = parseInt(args.interval || process.env.WHIP_CHECK_INTERVAL || '3', 10);
|
||||
|
||||
if (!WHIP_URL) {
|
||||
console.error('Usage: node scripts/check-whip-obs-live.js --url <WHIP_URL> [--token <token>] [--core <CORE_URL>]');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
console.log('\nWHIP E2E live check');
|
||||
console.log(` WHIP URL: ${WHIP_URL}`);
|
||||
if (TOKEN) console.log(` token: ${TOKEN}`);
|
||||
console.log(` Core: ${CORE_URL}`);
|
||||
console.log(` Poll timeout: ${TIMEOUT}s (interval ${INTERVAL}s)`);
|
||||
|
||||
// Extract stream key
|
||||
let streamKey = null;
|
||||
try {
|
||||
const u = new URL(WHIP_URL);
|
||||
const parts = u.pathname.split('/').filter(Boolean);
|
||||
streamKey = parts[parts.length - 1];
|
||||
} catch (e) {
|
||||
console.error('Invalid WHIP_URL:', e.message);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// OPTIONS (OBS does this first)
|
||||
try {
|
||||
const urlWithToken = TOKEN ? (WHIP_URL + (WHIP_URL.includes('?') ? '&' : '?') + 'token=' + encodeURIComponent(TOKEN)) : WHIP_URL;
|
||||
console.log('\n1) OPTIONS → WHIP endpoint (discovery)');
|
||||
const opt = await request(urlWithToken, {
|
||||
method: 'OPTIONS',
|
||||
headers: {
|
||||
'Origin': args.origin || 'http://localhost:3000',
|
||||
'Access-Control-Request-Method': 'POST',
|
||||
'Access-Control-Request-Headers': 'content-type',
|
||||
},
|
||||
timeout: 10000,
|
||||
});
|
||||
console.log(` HTTP ${opt.status}`);
|
||||
console.log(' Allow:', opt.headers['allow'] || opt.headers['access-control-allow-methods'] || '(none)');
|
||||
} catch (e) {
|
||||
console.error(' OPTIONS failed:', e.message);
|
||||
}
|
||||
|
||||
// GET /whip/<key>/sdp (relay SDP) — may or may not be implemented
|
||||
try {
|
||||
const base = (() => { const u = new URL(WHIP_URL); return u.origin; })();
|
||||
const sdpUrl = base + '/whip/' + encodeURIComponent(streamKey) + '/sdp' + (TOKEN ? ('?token=' + encodeURIComponent(TOKEN)) : '');
|
||||
console.log('\n2) GET /whip/<key>/sdp (relay SDP)');
|
||||
const r = await request(sdpUrl, { method: 'GET', timeout: 8000 });
|
||||
console.log(` GET ${sdpUrl} → HTTP ${r.status}`);
|
||||
if (r.body && r.body.length) console.log(' Body length:', r.body.length);
|
||||
} catch (e) {
|
||||
console.error(' GET /sdp failed:', e.message);
|
||||
}
|
||||
|
||||
// Poll Core /api/v3/whip for active publishers
|
||||
console.log('\n3) Poll Core /api/v3/whip looking for active stream key');
|
||||
const start = Date.now();
|
||||
let found = false;
|
||||
const whipApi = (CORE_URL.replace(/\/$/, '') + '/api/v3/whip');
|
||||
// Build optional auth header
|
||||
const headers = {};
|
||||
if (process.env.CORE_AUTH) {
|
||||
headers['Authorization'] = process.env.CORE_AUTH;
|
||||
} else if (process.env.CORE_USER && process.env.CORE_PASS) {
|
||||
const token = Buffer.from(process.env.CORE_USER + ':' + process.env.CORE_PASS).toString('base64');
|
||||
headers['Authorization'] = 'Basic ' + token;
|
||||
}
|
||||
|
||||
while ((Date.now() - start) / 1000 < TIMEOUT) {
|
||||
try {
|
||||
const res = await request(whipApi, { method: 'GET', headers, timeout: 5000 });
|
||||
if (res.status === 200) {
|
||||
let list = [];
|
||||
try { list = JSON.parse(res.body); } catch (e) { /* ignore */ }
|
||||
if (Array.isArray(list)) {
|
||||
const hit = list.find((it) => String(it.name) === String(streamKey));
|
||||
if (hit) {
|
||||
console.log(` ✅ Stream detected in Core /api/v3/whip: ${streamKey}`);
|
||||
console.log(' → published_at:', hit.published_at || '(unknown)');
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
process.stdout.write('.');
|
||||
}
|
||||
} else {
|
||||
process.stdout.write('?');
|
||||
}
|
||||
} else {
|
||||
process.stdout.write('x');
|
||||
}
|
||||
} catch (e) {
|
||||
process.stdout.write('!');
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, INTERVAL * 1000));
|
||||
}
|
||||
|
||||
console.log('');
|
||||
if (!found) {
|
||||
console.error(`\n✗ Stream not detected within ${TIMEOUT}s. Si OBS ya está enviando, verifica:`);
|
||||
console.error('- Que el stream key usado en OBS coincida exactamente');
|
||||
console.error('- Que Core esté exponiendo /api/v3/whip sin autenticación o proveas credenciales');
|
||||
console.error('- Logs del Core/egress para errores de ingest');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\nE2E check completo — stream activo.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error('Fatal:', e.message || e);
|
||||
process.exit(2);
|
||||
});
|
||||
@ -37,9 +37,11 @@ if (urlParams.has('address')) {
|
||||
window.location.pathname.replace(/\/ui\/.*$/, '');
|
||||
} else if (process.env.REACT_APP_CORE_URL && process.env.REACT_APP_CORE_URL.trim() !== '') {
|
||||
// 4. .env / .env.local — CRA injects at build time.
|
||||
// Use window.location.origin so all /api/* and /memfs/* calls go through
|
||||
// the CRA dev proxy (setupProxy.js) which forwards them to REACT_APP_CORE_URL.
|
||||
address = window.location.origin;
|
||||
// Prefer the explicit REACT_APP_CORE_URL build-time value so the UI
|
||||
// connects to the configured Core directly instead of relying on
|
||||
// window.location.origin. This ensures the UI respects the user's
|
||||
// REACT_APP_CORE_URL setting from .env.local or the build environment.
|
||||
address = process.env.REACT_APP_CORE_URL.trim().replace(/\/$/, '');
|
||||
} else {
|
||||
// 5. Same-origin production (Core and UI on the same host/port)
|
||||
address = window.location.origin;
|
||||
|
||||
@ -142,7 +142,11 @@ class API {
|
||||
}
|
||||
}
|
||||
|
||||
this._error(res.err.message);
|
||||
// Avoid noisy console.error for expected 404 responses (e.g. probe cleanup).
|
||||
// Keep logging for other HTTP errors.
|
||||
if (response.status !== 404) {
|
||||
this._error(res.err.message);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -15,6 +15,28 @@ import * as Version from '../version';
|
||||
import API from './api';
|
||||
import { anonymize } from './anonymizer';
|
||||
|
||||
// Helper: derive WHIP base URL
|
||||
function computeWhipBaseFromEnv() {
|
||||
// If explicit override provided, use it
|
||||
try {
|
||||
const envOverride = (process && process.env && process.env.REACT_APP_WHIP_BASE_URL) ? process.env.REACT_APP_WHIP_BASE_URL : '';
|
||||
if (envOverride && envOverride.length) return envOverride.replace(/\/$/, '');
|
||||
|
||||
// Otherwise derive from REACT_APP_CORE_URL by reusing hostname and swapping port
|
||||
const core = (process && process.env && process.env.REACT_APP_CORE_URL) ? process.env.REACT_APP_CORE_URL : '';
|
||||
if (core && core.length) {
|
||||
const coreUrl = new URL(core);
|
||||
const whipPort = (process && process.env && process.env.REACT_APP_WHIP_PORT) ? process.env.REACT_APP_WHIP_PORT : '8555';
|
||||
const portSuffix = whipPort ? ':' + whipPort : '';
|
||||
return coreUrl.protocol + '//' + coreUrl.hostname + portSuffix;
|
||||
}
|
||||
} catch (e) {
|
||||
// fallthrough
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
class Restreamer {
|
||||
constructor(address) {
|
||||
try {
|
||||
@ -990,10 +1012,9 @@ class Restreamer {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Allow overriding the public host:port via REACT_APP_WHIP_BASE_URL.
|
||||
// Useful when the Core reports the wrong public IP (e.g. behind NAT)
|
||||
// and you want the OBS URL to show a specific host, e.g. a LAN IP.
|
||||
const override = process.env.REACT_APP_WHIP_BASE_URL;
|
||||
// Allow overriding the public host:port via REACT_APP_WHIP_BASE_URL
|
||||
// or derive it from REACT_APP_CORE_URL (reuse domain, change port).
|
||||
const override = computeWhipBaseFromEnv();
|
||||
if (override && val) {
|
||||
const base = override.replace(/\/$/, '') + '/whip/';
|
||||
val.base_publish_url = base;
|
||||
@ -1010,8 +1031,8 @@ class Restreamer {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Same host override as WhipUrl().
|
||||
const override = process.env.REACT_APP_WHIP_BASE_URL;
|
||||
// Same host override as WhipUrl() — consider env override or derive from CORE_URL.
|
||||
const override = computeWhipBaseFromEnv();
|
||||
if (override && val) {
|
||||
const base = override.replace(/\/$/, '') + '/whip/';
|
||||
val.publish_url = base + name;
|
||||
|
||||
@ -118,6 +118,18 @@ function getWhipServerUrl() {
|
||||
if (process.env.REACT_APP_WHIP_SERVER_URL) {
|
||||
return String(process.env.REACT_APP_WHIP_SERVER_URL).replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
// If WHIP server URL not provided, derive from REACT_APP_CORE_URL by reusing
|
||||
// the core's hostname and swapping the port (default WHIP port 8555).
|
||||
if (process.env.REACT_APP_CORE_URL) {
|
||||
try {
|
||||
const coreUrl = new URL(process.env.REACT_APP_CORE_URL);
|
||||
const whipPort = process.env.REACT_APP_WHIP_PORT || '8555';
|
||||
return coreUrl.protocol + '//' + coreUrl.hostname + (whipPort ? ':' + whipPort : '');
|
||||
} catch (e) {
|
||||
// ignore and fallback
|
||||
}
|
||||
}
|
||||
// Fallback: mismo origen del UI (útil si egress corre detrás del mismo proxy)
|
||||
const loc = window.location;
|
||||
return (loc.origin || `${loc.protocol}//${loc.host}`);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user