mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-25 08:48:13 +02:00
feat: enable FORCE_TURN_RELAY to diagnose turn connectivity for local deployment setups (#272)
* filter out local sdp candidates on non local environment * feat: add FORCE_TURN_RELAY variable * add FORCE_TURN_RELAY option in docker-compose * fix: fix github workflow
This commit is contained in:
parent
01c201bf09
commit
e2fe1f3cd4
17 changed files with 410 additions and 37 deletions
|
|
@ -12,6 +12,8 @@ export async function GET() {
|
|||
let apiVersion = "unknown";
|
||||
let deploymentMode = "oss";
|
||||
let authProvider = "local";
|
||||
let turnEnabled = false;
|
||||
let forceTurnRelay = false;
|
||||
|
||||
try {
|
||||
const response = await healthApiV1HealthGet();
|
||||
|
|
@ -20,6 +22,8 @@ export async function GET() {
|
|||
apiVersion = data.version;
|
||||
deploymentMode = data.deployment_mode;
|
||||
authProvider = data.auth_provider;
|
||||
turnEnabled = Boolean(data.turn_enabled);
|
||||
forceTurnRelay = Boolean(data.force_turn_relay);
|
||||
}
|
||||
} catch {
|
||||
apiVersion = "unavailable";
|
||||
|
|
@ -30,5 +34,7 @@ export async function GET() {
|
|||
api: apiVersion,
|
||||
deploymentMode,
|
||||
authProvider,
|
||||
turnEnabled,
|
||||
forceTurnRelay,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { client } from "@/client/client.gen";
|
|||
import { getTurnCredentialsApiV1TurnCredentialsGet, validateUserConfigurationsApiV1UserConfigurationsUserValidateGet, validateWorkflowApiV1WorkflowWorkflowIdValidatePost } from "@/client/sdk.gen";
|
||||
import { TurnCredentialsResponse } from "@/client/types.gen";
|
||||
import { WorkflowValidationError } from "@/components/flow/types";
|
||||
import { useAppConfig } from "@/context/AppConfigContext";
|
||||
import logger from '@/lib/logger';
|
||||
|
||||
import { sdpFilterCodec } from "../utils";
|
||||
|
|
@ -48,6 +49,7 @@ export const useWebSocketRTC = ({ workflowId, workflowRunId, accessToken, initia
|
|||
const [isStarting, setIsStarting] = useState(false);
|
||||
const [feedbackMessages, setFeedbackMessages] = useState<FeedbackMessage[]>([]);
|
||||
const initialContext = initialContextVariables || {};
|
||||
const { config: appConfig } = useAppConfig();
|
||||
|
||||
const {
|
||||
audioInputs,
|
||||
|
|
@ -123,6 +125,16 @@ export const useWebSocketRTC = ({ workflowId, workflowRunId, accessToken, initia
|
|||
iceServers
|
||||
};
|
||||
|
||||
// Diagnostic: when the backend is started with FORCE_TURN_RELAY=true,
|
||||
// restrict the browser to relay-only candidates so media must traverse
|
||||
// TURN. Lets you verify TURN connectivity end-to-end — a TURN
|
||||
// misconfiguration surfaces as an ICE failure instead of silently
|
||||
// falling back to host/srflx.
|
||||
if (appConfig?.forceTurnRelay) {
|
||||
config.iceTransportPolicy = 'relay';
|
||||
logger.info('FORCE_TURN_RELAY is on — restricting browser ICE to relay candidates only');
|
||||
}
|
||||
|
||||
const pc = new RTCPeerConnection(config);
|
||||
|
||||
// Set up ICE candidate trickling
|
||||
|
|
@ -528,24 +540,30 @@ export const useWebSocketRTC = ({ workflowId, workflowRunId, accessToken, initia
|
|||
setConnectionStatus('connecting');
|
||||
|
||||
try {
|
||||
// Fetch time-limited TURN credentials from backend API
|
||||
try {
|
||||
const turnResponse = await getTurnCredentialsApiV1TurnCredentialsGet({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
if (turnResponse.data) {
|
||||
turnCredentialsRef.current = turnResponse.data;
|
||||
logger.info(`TURN credentials obtained, TTL: ${turnResponse.data.ttl}s`);
|
||||
} else if (turnResponse.response.status === 503) {
|
||||
// TURN not configured on server - this is OK, we'll use STUN only
|
||||
logger.info('TURN server not configured, using STUN only');
|
||||
} else {
|
||||
logger.warn(`Failed to fetch TURN credentials: ${turnResponse.response.status}`);
|
||||
// Fetch time-limited TURN credentials from backend API only if the
|
||||
// server reports a TURN server is configured. Skipping the request
|
||||
// avoids a 503 on OSS local deployments that don't run coturn.
|
||||
if (appConfig?.turnEnabled === false) {
|
||||
logger.info('TURN server disabled in app config, using STUN only');
|
||||
} else {
|
||||
try {
|
||||
const turnResponse = await getTurnCredentialsApiV1TurnCredentialsGet({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
if (turnResponse.data) {
|
||||
turnCredentialsRef.current = turnResponse.data;
|
||||
logger.info(`TURN credentials obtained, TTL: ${turnResponse.data.ttl}s`);
|
||||
} else if (turnResponse.response.status === 503) {
|
||||
// TURN not configured on server - this is OK, we'll use STUN only
|
||||
logger.info('TURN server not configured, using STUN only');
|
||||
} else {
|
||||
logger.warn(`Failed to fetch TURN credentials: ${turnResponse.response.status}`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn('Failed to fetch TURN credentials, continuing without TURN:', e);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn('Failed to fetch TURN credentials, continuing without TURN:', e);
|
||||
}
|
||||
|
||||
// Validate API keys
|
||||
|
|
|
|||
|
|
@ -1812,6 +1812,14 @@ export type HealthResponse = {
|
|||
* Auth Provider
|
||||
*/
|
||||
auth_provider: string;
|
||||
/**
|
||||
* Turn Enabled
|
||||
*/
|
||||
turn_enabled: boolean;
|
||||
/**
|
||||
* Force Turn Relay
|
||||
*/
|
||||
force_turn_relay: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ interface AppConfig {
|
|||
apiVersion: string;
|
||||
deploymentMode: string;
|
||||
authProvider: string;
|
||||
turnEnabled: boolean;
|
||||
forceTurnRelay: boolean;
|
||||
}
|
||||
|
||||
interface AppConfigContextType {
|
||||
|
|
@ -19,6 +21,8 @@ const defaultConfig: AppConfig = {
|
|||
apiVersion: 'unknown',
|
||||
deploymentMode: 'oss',
|
||||
authProvider: 'local',
|
||||
turnEnabled: false,
|
||||
forceTurnRelay: false,
|
||||
};
|
||||
|
||||
const AppConfigContext = createContext<AppConfigContextType>({
|
||||
|
|
@ -39,6 +43,8 @@ export function AppConfigProvider({ children }: { children: ReactNode }) {
|
|||
apiVersion: data.api || 'unknown',
|
||||
deploymentMode: data.deploymentMode || 'oss',
|
||||
authProvider: data.authProvider || 'local',
|
||||
turnEnabled: Boolean(data.turnEnabled),
|
||||
forceTurnRelay: Boolean(data.forceTurnRelay),
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue