mirror of
https://github.com/wukko/cobalt.git
synced 2025-04-29 14:04:25 +02:00
133 lines
3.7 KiB
JavaScript
133 lines
3.7 KiB
JavaScript
import mime from "mime";
|
|
import ipaddr from "ipaddr.js";
|
|
|
|
import { apiSchema } from "./schema.js";
|
|
import { createProxyTunnels, createStream } from "../stream/manage.js";
|
|
|
|
export function createResponse(responseType, responseData) {
|
|
const internalError = (code) => {
|
|
return {
|
|
status: 500,
|
|
body: {
|
|
status: "error",
|
|
error: {
|
|
code: code || "error.api.fetch.critical",
|
|
},
|
|
critical: true
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
let status = 200,
|
|
response = {};
|
|
|
|
if (responseType === "error") {
|
|
status = 400;
|
|
}
|
|
|
|
switch (responseType) {
|
|
case "error":
|
|
response = {
|
|
error: {
|
|
code: responseData?.code,
|
|
context: responseData?.context,
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "redirect":
|
|
response = {
|
|
url: responseData?.url,
|
|
filename: responseData?.filename
|
|
}
|
|
break;
|
|
|
|
case "tunnel":
|
|
response = {
|
|
url: createStream(responseData),
|
|
filename: responseData?.filename
|
|
}
|
|
break;
|
|
|
|
case "local-processing":
|
|
response = {
|
|
type: responseData?.type,
|
|
service: responseData?.service,
|
|
tunnel: createProxyTunnels(responseData),
|
|
|
|
output: {
|
|
type: mime.getType(responseData?.filename) || undefined,
|
|
filename: responseData?.filename,
|
|
metadata: responseData?.fileMetadata || undefined,
|
|
},
|
|
|
|
audio: {
|
|
copy: responseData?.audioCopy,
|
|
format: responseData?.audioFormat,
|
|
bitrate: responseData?.audioBitrate,
|
|
},
|
|
|
|
isHLS: responseData?.isHLS,
|
|
}
|
|
|
|
if (!response.audio.format) {
|
|
if (response.type === "audio") {
|
|
// audio response without a format is invalid
|
|
return internalError();
|
|
}
|
|
delete response.audio;
|
|
}
|
|
|
|
if (!response.output.type || !response.output.filename) {
|
|
// response without a type or filename is invalid
|
|
return internalError();
|
|
}
|
|
break;
|
|
|
|
case "picker":
|
|
response = {
|
|
picker: responseData?.picker,
|
|
audio: responseData?.url,
|
|
audioFilename: responseData?.filename
|
|
}
|
|
break;
|
|
|
|
case "critical":
|
|
return internalError(responseData?.code);
|
|
|
|
default:
|
|
throw "unreachable"
|
|
}
|
|
|
|
return {
|
|
status,
|
|
body: {
|
|
status: responseType,
|
|
...response
|
|
}
|
|
}
|
|
} catch {
|
|
return internalError()
|
|
}
|
|
}
|
|
|
|
export function normalizeRequest(request) {
|
|
return apiSchema.safeParseAsync(request).catch(() => (
|
|
{ success: false }
|
|
));
|
|
}
|
|
|
|
export function getIP(req, prefix = 56) {
|
|
const strippedIP = req.ip.replace(/^::ffff:/, '');
|
|
const ip = ipaddr.parse(strippedIP);
|
|
if (ip.kind() === 'ipv4') {
|
|
return strippedIP;
|
|
}
|
|
|
|
const v6Bytes = ip.toByteArray();
|
|
v6Bytes.fill(0, prefix / 8);
|
|
|
|
return ipaddr.fromByteArray(v6Bytes).toString();
|
|
}
|