brunner56's picture
implement app
0bfe2e3
import { BaseProxy, ProxyStream } from './base';
import { createLogger, maskSensitiveInfo, Env } from '../utils';
const logger = createLogger('stremthru');
export class StremThruProxy extends BaseProxy {
protected generateProxyUrl(endpoint: string): URL {
const proxyUrl = new URL(this.config.url.replace(/\/$/, ''));
proxyUrl.pathname = `${proxyUrl.pathname === '/' ? '' : proxyUrl.pathname}${endpoint}`;
return proxyUrl;
}
protected getPublicIpEndpoint(): string {
return '/v0/health/__debug__';
}
protected getPublicIpFromResponse(data: any): string | null {
return typeof data.data?.ip?.exposed === 'object'
? data.data.ip.exposed['*'] || data.data.ip.machine
: data.data?.ip?.machine || null;
}
protected getHeaders(): Record<string, string> {
const headers: Record<string, string> = {
'Content-Type': 'application/x-www-form-urlencoded',
};
if (Env.ENCRYPT_STREMTHRU_URLS) {
headers['X-StremThru-Authorization'] = `Basic ${this.config.credentials}`;
}
return headers;
}
protected async generateStreamUrls(
streams: ProxyStream[]
): Promise<string[] | null> {
const proxyUrl = this.generateProxyUrl('/v0/proxy');
if (!Env.ENCRYPT_STREMTHRU_URLS) {
proxyUrl.searchParams.set('token', this.config.credentials);
}
const data = new URLSearchParams();
streams.forEach((stream, i) => {
data.append('url', stream.url);
let req_headers = '';
if (stream.headers?.request) {
for (const [key, value] of Object.entries(stream.headers.request)) {
req_headers += `${key}: ${value}\n`;
}
}
data.append(`req_headers[${i}]`, req_headers);
if (stream.filename) {
data.append(`filename[${i}]`, stream.filename);
}
});
if (Env.LOG_SENSITIVE_INFO) {
logger.debug(`POST ${proxyUrl.toString()}`);
} else {
logger.debug(
`POST ${proxyUrl.protocol}://${maskSensitiveInfo(proxyUrl.hostname)}${proxyUrl.port ? `:${proxyUrl.port}` : ''}/v0/proxy`
);
}
const response = await fetch(proxyUrl.toString(), {
method: 'POST',
headers: this.getHeaders(),
body: data,
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
throw new Error(`${response.status}: ${response.statusText}`);
}
let responseData: any;
try {
responseData = await response.json();
} catch (error) {
const text = await response.text();
logger.debug(`Response body: ${text}`);
throw new Error('Failed to parse JSON response from StremThru');
}
if (responseData.error) {
throw new Error(responseData.error);
}
if (responseData.data?.items) {
return responseData.data.items;
} else {
throw new Error('No URLs were returned from StremThru');
}
}
}