mirror of
https://github.com/wukko/cobalt.git
synced 2025-05-25 11:02:13 +02:00
api: move env loading into separate file
This commit is contained in:
parent
1c6defa8dd
commit
068cae3986
@ -1,76 +1,9 @@
|
|||||||
import { Constants } from "youtubei.js";
|
|
||||||
import { getVersion } from "@imput/version-info";
|
import { getVersion } from "@imput/version-info";
|
||||||
import { services } from "./processing/service-config.js";
|
import { loadEnvs, validateEnvs } from "./core/env.js";
|
||||||
import { supportsReusePort } from "./misc/cluster.js";
|
|
||||||
|
|
||||||
const version = await getVersion();
|
const version = await getVersion();
|
||||||
|
|
||||||
const disabledServices = process.env.DISABLED_SERVICES?.split(',') || [];
|
let env = loadEnvs();
|
||||||
const enabledServices = new Set(Object.keys(services).filter(e => {
|
|
||||||
if (!disabledServices.includes(e)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const forceLocalProcessingOptions = ["never", "session", "always"];
|
|
||||||
|
|
||||||
const env = {
|
|
||||||
apiURL: process.env.API_URL || '',
|
|
||||||
apiPort: process.env.API_PORT || 9000,
|
|
||||||
tunnelPort: process.env.API_PORT || 9000,
|
|
||||||
|
|
||||||
listenAddress: process.env.API_LISTEN_ADDRESS,
|
|
||||||
freebindCIDR: process.platform === 'linux' && process.env.FREEBIND_CIDR,
|
|
||||||
|
|
||||||
corsWildcard: process.env.CORS_WILDCARD !== '0',
|
|
||||||
corsURL: process.env.CORS_URL,
|
|
||||||
|
|
||||||
cookiePath: process.env.COOKIE_PATH,
|
|
||||||
|
|
||||||
rateLimitWindow: (process.env.RATELIMIT_WINDOW && parseInt(process.env.RATELIMIT_WINDOW)) || 60,
|
|
||||||
rateLimitMax: (process.env.RATELIMIT_MAX && parseInt(process.env.RATELIMIT_MAX)) || 20,
|
|
||||||
|
|
||||||
tunnelRateLimitWindow: (process.env.TUNNEL_RATELIMIT_WINDOW && parseInt(process.env.TUNNEL_RATELIMIT_WINDOW)) || 60,
|
|
||||||
tunnelRateLimitMax: (process.env.TUNNEL_RATELIMIT_MAX && parseInt(process.env.TUNNEL_RATELIMIT_MAX)) || 40,
|
|
||||||
|
|
||||||
sessionRateLimitWindow: (process.env.SESSION_RATELIMIT_WINDOW && parseInt(process.env.SESSION_RATELIMIT_WINDOW)) || 60,
|
|
||||||
sessionRateLimit: (process.env.SESSION_RATELIMIT && parseInt(process.env.SESSION_RATELIMIT)) || 10,
|
|
||||||
|
|
||||||
durationLimit: (process.env.DURATION_LIMIT && parseInt(process.env.DURATION_LIMIT)) || 10800,
|
|
||||||
streamLifespan: (process.env.TUNNEL_LIFESPAN && parseInt(process.env.TUNNEL_LIFESPAN)) || 90,
|
|
||||||
|
|
||||||
processingPriority: process.platform !== 'win32'
|
|
||||||
&& process.env.PROCESSING_PRIORITY
|
|
||||||
&& parseInt(process.env.PROCESSING_PRIORITY),
|
|
||||||
|
|
||||||
externalProxy: process.env.API_EXTERNAL_PROXY,
|
|
||||||
|
|
||||||
turnstileSitekey: process.env.TURNSTILE_SITEKEY,
|
|
||||||
turnstileSecret: process.env.TURNSTILE_SECRET,
|
|
||||||
jwtSecret: process.env.JWT_SECRET,
|
|
||||||
jwtLifetime: process.env.JWT_EXPIRY || 120,
|
|
||||||
|
|
||||||
sessionEnabled: process.env.TURNSTILE_SITEKEY
|
|
||||||
&& process.env.TURNSTILE_SECRET
|
|
||||||
&& process.env.JWT_SECRET,
|
|
||||||
|
|
||||||
apiKeyURL: process.env.API_KEY_URL && new URL(process.env.API_KEY_URL),
|
|
||||||
authRequired: process.env.API_AUTH_REQUIRED === '1',
|
|
||||||
redisURL: process.env.API_REDIS_URL,
|
|
||||||
instanceCount: (process.env.API_INSTANCE_COUNT && parseInt(process.env.API_INSTANCE_COUNT)) || 1,
|
|
||||||
keyReloadInterval: 900,
|
|
||||||
|
|
||||||
enabledServices,
|
|
||||||
|
|
||||||
customInnertubeClient: process.env.CUSTOM_INNERTUBE_CLIENT,
|
|
||||||
ytSessionServer: process.env.YOUTUBE_SESSION_SERVER,
|
|
||||||
ytSessionReloadInterval: 300,
|
|
||||||
ytSessionInnertubeClient: process.env.YOUTUBE_SESSION_INNERTUBE_CLIENT,
|
|
||||||
ytAllowBetterAudio: process.env.YOUTUBE_ALLOW_BETTER_AUDIO !== "0",
|
|
||||||
|
|
||||||
// "never" | "session" | "always"
|
|
||||||
forceLocalProcessing: process.env.FORCE_LOCAL_PROCESSING ?? "never",
|
|
||||||
}
|
|
||||||
|
|
||||||
const genericUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36";
|
const genericUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36";
|
||||||
const cobaltUserAgent = `cobalt/${version} (+https://github.com/imputnet/cobalt)`;
|
const cobaltUserAgent = `cobalt/${version} (+https://github.com/imputnet/cobalt)`;
|
||||||
@ -78,31 +11,7 @@ const cobaltUserAgent = `cobalt/${version} (+https://github.com/imputnet/cobalt)
|
|||||||
export const setTunnelPort = (port) => env.tunnelPort = port;
|
export const setTunnelPort = (port) => env.tunnelPort = port;
|
||||||
export const isCluster = env.instanceCount > 1;
|
export const isCluster = env.instanceCount > 1;
|
||||||
|
|
||||||
if (env.sessionEnabled && env.jwtSecret.length < 16) {
|
await validateEnvs(env);
|
||||||
throw new Error("JWT_SECRET env is too short (must be at least 16 characters long)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.instanceCount > 1 && !env.redisURL) {
|
|
||||||
throw new Error("API_REDIS_URL is required when API_INSTANCE_COUNT is >= 2");
|
|
||||||
} else if (env.instanceCount > 1 && !await supportsReusePort()) {
|
|
||||||
console.error('API_INSTANCE_COUNT is not supported in your environment. to use this env, your node.js');
|
|
||||||
console.error('version must be >= 23.1.0, and you must be running a recent enough version of linux');
|
|
||||||
console.error('(or other OS that supports it). for more info, see `reusePort` option on');
|
|
||||||
console.error('https://nodejs.org/api/net.html#serverlistenoptions-callback');
|
|
||||||
throw new Error('SO_REUSEPORT is not supported');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.customInnertubeClient && !Constants.SUPPORTED_CLIENTS.includes(env.customInnertubeClient)) {
|
|
||||||
console.error("CUSTOM_INNERTUBE_CLIENT is invalid. Provided client is not supported.");
|
|
||||||
console.error(`Supported clients are: ${Constants.SUPPORTED_CLIENTS.join(', ')}\n`);
|
|
||||||
throw new Error("Invalid CUSTOM_INNERTUBE_CLIENT");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.forceLocalProcessing && !forceLocalProcessingOptions.includes(env.forceLocalProcessing)) {
|
|
||||||
console.error("FORCE_LOCAL_PROCESSING is invalid.");
|
|
||||||
console.error(`Supported options are are: ${forceLocalProcessingOptions.join(', ')}\n`);
|
|
||||||
throw new Error("Invalid FORCE_LOCAL_PROCESSING");
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
env,
|
env,
|
||||||
|
101
api/src/core/env.js
Normal file
101
api/src/core/env.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
import { Constants } from "youtubei.js";
|
||||||
|
import { supportsReusePort } from "../misc/cluster.js";
|
||||||
|
import { services } from "../processing/service-config.js";
|
||||||
|
|
||||||
|
const forceLocalProcessingOptions = ["never", "session", "always"];
|
||||||
|
|
||||||
|
export const loadEnvs = (env = process.env) => {
|
||||||
|
const disabledServices = env.DISABLED_SERVICES?.split(',') || [];
|
||||||
|
const enabledServices = new Set(Object.keys(services).filter(e => {
|
||||||
|
if (!disabledServices.includes(e)) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
apiURL: env.API_URL || '',
|
||||||
|
apiPort: env.API_PORT || 9000,
|
||||||
|
tunnelPort: env.API_PORT || 9000,
|
||||||
|
|
||||||
|
listenAddress: env.API_LISTEN_ADDRESS,
|
||||||
|
freebindCIDR: process.platform === 'linux' && env.FREEBIND_CIDR,
|
||||||
|
|
||||||
|
corsWildcard: env.CORS_WILDCARD !== '0',
|
||||||
|
corsURL: env.CORS_URL,
|
||||||
|
|
||||||
|
cookiePath: env.COOKIE_PATH,
|
||||||
|
|
||||||
|
rateLimitWindow: (env.RATELIMIT_WINDOW && parseInt(env.RATELIMIT_WINDOW)) || 60,
|
||||||
|
rateLimitMax: (env.RATELIMIT_MAX && parseInt(env.RATELIMIT_MAX)) || 20,
|
||||||
|
|
||||||
|
tunnelRateLimitWindow: (env.TUNNEL_RATELIMIT_WINDOW && parseInt(env.TUNNEL_RATELIMIT_WINDOW)) || 60,
|
||||||
|
tunnelRateLimitMax: (env.TUNNEL_RATELIMIT_MAX && parseInt(env.TUNNEL_RATELIMIT_MAX)) || 40,
|
||||||
|
|
||||||
|
sessionRateLimitWindow: (env.SESSION_RATELIMIT_WINDOW && parseInt(env.SESSION_RATELIMIT_WINDOW)) || 60,
|
||||||
|
sessionRateLimit: (env.SESSION_RATELIMIT && parseInt(env.SESSION_RATELIMIT)) || 10,
|
||||||
|
|
||||||
|
durationLimit: (env.DURATION_LIMIT && parseInt(env.DURATION_LIMIT)) || 10800,
|
||||||
|
streamLifespan: (env.TUNNEL_LIFESPAN && parseInt(env.TUNNEL_LIFESPAN)) || 90,
|
||||||
|
|
||||||
|
processingPriority: process.platform !== 'win32'
|
||||||
|
&& env.PROCESSING_PRIORITY
|
||||||
|
&& parseInt(env.PROCESSING_PRIORITY),
|
||||||
|
|
||||||
|
externalProxy: env.API_EXTERNAL_PROXY,
|
||||||
|
|
||||||
|
turnstileSitekey: env.TURNSTILE_SITEKEY,
|
||||||
|
turnstileSecret: env.TURNSTILE_SECRET,
|
||||||
|
jwtSecret: env.JWT_SECRET,
|
||||||
|
jwtLifetime: env.JWT_EXPIRY || 120,
|
||||||
|
|
||||||
|
sessionEnabled: env.TURNSTILE_SITEKEY
|
||||||
|
&& env.TURNSTILE_SECRET
|
||||||
|
&& env.JWT_SECRET,
|
||||||
|
|
||||||
|
apiKeyURL: env.API_KEY_URL && new URL(env.API_KEY_URL),
|
||||||
|
authRequired: env.API_AUTH_REQUIRED === '1',
|
||||||
|
redisURL: env.API_REDIS_URL,
|
||||||
|
instanceCount: (env.API_INSTANCE_COUNT && parseInt(env.API_INSTANCE_COUNT)) || 1,
|
||||||
|
keyReloadInterval: 900,
|
||||||
|
|
||||||
|
enabledServices,
|
||||||
|
|
||||||
|
customInnertubeClient: env.CUSTOM_INNERTUBE_CLIENT,
|
||||||
|
ytSessionServer: env.YOUTUBE_SESSION_SERVER,
|
||||||
|
ytSessionReloadInterval: 300,
|
||||||
|
ytSessionInnertubeClient: env.YOUTUBE_SESSION_INNERTUBE_CLIENT,
|
||||||
|
ytAllowBetterAudio: env.YOUTUBE_ALLOW_BETTER_AUDIO !== "0",
|
||||||
|
|
||||||
|
// "never" | "session" | "always"
|
||||||
|
forceLocalProcessing: env.FORCE_LOCAL_PROCESSING ?? "never",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateEnvs = async (env) => {
|
||||||
|
if (env.sessionEnabled && env.jwtSecret.length < 16) {
|
||||||
|
throw new Error("JWT_SECRET env is too short (must be at least 16 characters long)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.instanceCount > 1 && !env.redisURL) {
|
||||||
|
throw new Error("API_REDIS_URL is required when API_INSTANCE_COUNT is >= 2");
|
||||||
|
} else if (env.instanceCount > 1 && !await supportsReusePort()) {
|
||||||
|
console.error('API_INSTANCE_COUNT is not supported in your environment. to use this env, your node.js');
|
||||||
|
console.error('version must be >= 23.1.0, and you must be running a recent enough version of linux');
|
||||||
|
console.error('(or other OS that supports it). for more info, see `reusePort` option on');
|
||||||
|
console.error('https://nodejs.org/api/net.html#serverlistenoptions-callback');
|
||||||
|
throw new Error('SO_REUSEPORT is not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.customInnertubeClient && !Constants.SUPPORTED_CLIENTS.includes(env.customInnertubeClient)) {
|
||||||
|
console.error("CUSTOM_INNERTUBE_CLIENT is invalid. Provided client is not supported.");
|
||||||
|
console.error(`Supported clients are: ${Constants.SUPPORTED_CLIENTS.join(', ')}\n`);
|
||||||
|
throw new Error("Invalid CUSTOM_INNERTUBE_CLIENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.forceLocalProcessing && !forceLocalProcessingOptions.includes(env.forceLocalProcessing)) {
|
||||||
|
console.error("FORCE_LOCAL_PROCESSING is invalid.");
|
||||||
|
console.error(`Supported options are are: ${forceLocalProcessingOptions.join(', ')}\n`);
|
||||||
|
throw new Error("Invalid FORCE_LOCAL_PROCESSING");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user