File size: 2,415 Bytes
87cb242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4824a38
 
87cb242
4824a38
 
 
 
 
 
 
 
87cb242
 
 
 
 
 
 
 
 
 
 
4824a38
 
 
 
 
 
 
 
 
 
 
87cb242
 
 
4824a38
87cb242
4824a38
87cb242
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import dotenv from 'dotenv';
dotenv.config();

function require_env(key: string): string {
  const val = process.env[key];
  if (!val) throw new Error(`Missing required env variable: ${key}`);
  return val;
}

function optional_env(key: string, fallback: string): string {
  return process.env[key] || fallback;
}

export const CONFIG = {
  PORT: parseInt(optional_env('PORT', '7860'), 10),
  NODE_ENV: optional_env('NODE_ENV', 'production'),
  ALLOWED_ORIGINS: optional_env('ALLOWED_ORIGINS', '*').split(',').map(s => s.trim()),

  JWT_SECRET: require_env('JWT_SECRET'),

  REDIS_PRESENCE_URL: require_env('REDIS_PRESENCE_URL'),
  REDIS_MESSAGE_URL: require_env('REDIS_MESSAGE_URL'),

  MONGO_URI: require_env('MONGO_URI'),

  SUPABASE_URL: require_env('SUPABASE_URL'),
  SUPABASE_SERVICE_KEY: require_env('SUPABASE_SERVICE_KEY'),
  SUPABASE_BUCKET: optional_env('SUPABASE_BUCKET', 'media'),

  // STUN: comma-separated list of stun: URIs
  STUN_SERVERS: optional_env('STUN_SERVERS', 'stun:stun.l.google.com:19302')
    .split(',')
    .map(s => s.trim())
    .filter(Boolean),

  // TURN: comma-separated list of turn:/turns: URIs (all share same credentials)
  TURN_URLS: optional_env('TURN_URL', '')
    .split(',')
    .map(s => s.trim())
    .filter(Boolean),
  TURN_USERNAME: optional_env('TURN_USERNAME', ''),
  TURN_CREDENTIAL: optional_env('TURN_CREDENTIAL', ''),

  MAX_FILE_SIZE_BYTES: parseInt(optional_env('MAX_FILE_SIZE_MB', '99'), 10) * 1024 * 1024,
  MAX_FILE_COUNT: parseInt(optional_env('MAX_FILE_COUNT', '10'), 10),

  PRESENCE_TTL_S: parseInt(optional_env('PRESENCE_TTL_S', '60'), 10),
  OFFLINE_MSG_TTL_S: parseInt(optional_env('OFFLINE_MSG_TTL_S', '604800'), 10),
  HEARTBEAT_INTERVAL_MS: parseInt(optional_env('HEARTBEAT_INTERVAL_MS', '30000'), 10),
} as const;

interface RTCIceServerConfig {
  urls: string;
  username?: string;
  credential?: string;
}

/**
 * Builds the full ICE server array sent to clients on connect.
 * Supports multiple TURN URLs (comma-separated in env) — all share
 * the same username/credential pair (Metered format).
 */
export function buildIceServers(): RTCIceServerConfig[] {
  const servers: RTCIceServerConfig[] = CONFIG.STUN_SERVERS.map(url => ({ urls: url }));

  for (const url of CONFIG.TURN_URLS) {
    servers.push({
      urls: url,
      username: CONFIG.TURN_USERNAME,
      credential: CONFIG.TURN_CREDENTIAL,
    });
  }

  return servers;
}