Files
Final-Year-Project/Backend/utils/minio.ts

148 lines
4.1 KiB
TypeScript

import { readFileSync } from 'node:fs';
import { Agent as HttpsAgent } from 'node:https';
import { Client } from 'minio';
type MinioTarget = {
endPoint: string;
port: number;
useSSL: boolean;
origin: string;
};
const parseBoolean = (value: string | undefined, fallback: boolean): boolean => {
if (value == null || value.trim() === '') {
return fallback;
}
return value.toLowerCase() === 'true';
};
const resolveMinioTarget = ({
origin,
endpoint,
port,
useSSL,
}: {
origin?: string;
endpoint?: string;
port?: string | number;
useSSL: boolean;
}): MinioTarget => {
const rawOrigin = origin?.trim();
if (rawOrigin) {
const url = new URL(rawOrigin);
const targetUseSSL = url.protocol === 'https:';
const targetPort = Number(url.port || (targetUseSSL ? 443 : 80));
return {
endPoint: url.hostname,
port: targetPort,
useSSL: targetUseSSL,
origin: url.origin,
};
}
const rawEndpoint = endpoint?.trim() || 'localhost';
if (rawEndpoint.startsWith('http://') || rawEndpoint.startsWith('https://')) {
const url = new URL(rawEndpoint);
const targetUseSSL = url.protocol === 'https:';
const targetPort = Number(url.port || (targetUseSSL ? 443 : 80));
return {
endPoint: url.hostname,
port: targetPort,
useSSL: targetUseSSL,
origin: url.origin,
};
}
const targetPort = Number(port ?? (useSSL ? 443 : 80));
const includePort = !(useSSL && targetPort === 443) && !(!useSSL && targetPort === 80);
return {
endPoint: rawEndpoint,
port: targetPort,
useSSL,
origin: `${useSSL ? 'https' : 'http'}://${rawEndpoint}${includePort ? `:${targetPort}` : ''}`,
};
};
const accessKey = process.env.MINIO_ACCESS_KEY;
const secretKey = process.env.MINIO_SECRET_KEY;
const insecureSkipTlsVerify = parseBoolean(process.env.MINIO_INSECURE_SKIP_TLS_VERIFY, false);
const tlsRejectUnauthorized = parseBoolean(process.env.MINIO_TLS_REJECT_UNAUTHORIZED, true);
const minioCaCertPath = process.env.MINIO_CA_CERT_PATH?.trim();
const internalUseSSL = parseBoolean(process.env.MINIO_USE_SSL, false);
const internalTarget = resolveMinioTarget({
endpoint: process.env.MINIO_ENDPOINT ?? 'localhost',
port: process.env.MINIO_PORT ?? 9000,
useSSL: internalUseSSL,
});
const publicTarget = resolveMinioTarget({
origin: process.env.MINIO_PUBLIC_ORIGIN,
endpoint: process.env.MINIO_PUBLIC_ENDPOINT ?? internalTarget.endPoint,
port: process.env.MINIO_PUBLIC_PORT ?? internalTarget.port,
useSSL: parseBoolean(process.env.MINIO_PUBLIC_USE_SSL, internalTarget.useSSL),
});
if (!accessKey || !secretKey) {
throw new Error('MINIO_ACCESS_KEY and MINIO_SECRET_KEY must be set');
}
export const minioBucket = process.env.MINIO_BUCKET ?? 'videos';
export const minioPresignedExpirySeconds = Number(process.env.MINIO_PRESIGNED_EXPIRY_SECONDS ?? 60 * 10);
export const minioPublicOrigin = publicTarget.origin;
const customCa = minioCaCertPath ? readFileSync(minioCaCertPath) : undefined;
const transportAgent = internalTarget.useSSL
? new HttpsAgent({
keepAlive: true,
ca: customCa,
rejectUnauthorized: insecureSkipTlsVerify ? false : tlsRejectUnauthorized,
})
: undefined;
export const minioClient = new Client({
endPoint: internalTarget.endPoint,
port: internalTarget.port,
useSSL: internalTarget.useSSL,
accessKey,
secretKey,
region: process.env.MINIO_REGION ?? 'us-east-1',
transportAgent,
});
export const minioPresignClient = new Client({
endPoint: publicTarget.endPoint,
port: publicTarget.port,
useSSL: publicTarget.useSSL,
accessKey,
secretKey,
region: process.env.MINIO_REGION ?? 'us-east-1',
});
let ensureBucketPromise: Promise<void> | null = null;
export const ensureMinioBucket = async (): Promise<void> => {
if (ensureBucketPromise) {
return ensureBucketPromise;
}
ensureBucketPromise = (async () => {
const exists = await minioClient.bucketExists(minioBucket);
if (!exists) {
await minioClient.makeBucket(minioBucket, process.env.MINIO_REGION ?? 'us-east-1');
}
})();
try {
await ensureBucketPromise;
console.log("Minio Up")
} catch (error) {
ensureBucketPromise = null;
throw error;
}
};