chore: working on backup api for new storage system.

This commit is contained in:
charlesgauthereau
2026-01-15 21:27:36 +01:00
parent dd1f791b3e
commit 670f6a1974
16 changed files with 437 additions and 102 deletions
+6 -5
View File
@@ -5,6 +5,7 @@ import type {
} from '../types';
import {uploadLocal, getLocal, deleteLocal} from './local';
import {deleteS3, getS3, uploadS3} from "@/features/storages/providers/s3";
type ProviderHandler = {
upload: (config: any, input: StorageInput & { action: 'upload' }) => Promise<StorageResult>;
@@ -18,11 +19,11 @@ const handlers: Record<StorageProviderKind, ProviderHandler> = {
get: getLocal,
delete: deleteLocal,
},
// s3: {
// upload: uploadS3,
// get: getS3,
// delete: deleteS3,
// },
s3: {
upload: uploadS3,
get: getS3,
delete: deleteS3,
},
// gcs: null as any,
// azure: null as any,
};
+3 -1
View File
@@ -14,7 +14,9 @@ export async function uploadLocal(
const base = config.baseDir || BASE_DIR;
const fullPath = path.join(process.cwd(), base, input.data.path);
await mkdir(fullPath, {recursive: true});
const dir = path.dirname(fullPath);
await mkdir(dir, { recursive: true });
await writeFile(fullPath, input.data.file);
return {
+92
View File
@@ -0,0 +1,92 @@
import * as Minio from "minio";
import {StorageDeleteInput, StorageGetInput, StorageResult, StorageUploadInput} from "../types";
type S3Config = {
endPointUrl: string;
accessKey: string;
secretKey: string;
bucketName: string;
port?: number;
useSSL?: boolean;
};
async function getS3Client(config: S3Config) {
return new Minio.Client({
endPoint: config.endPointUrl,
accessKey: config.accessKey,
secretKey: config.secretKey,
port: config.port ?? 443,
useSSL: config.useSSL ?? true,
});
}
const BASE_DIR = "backups/";
async function ensureBucket(config: S3Config) {
const client = await getS3Client(config);
const exists = await client.bucketExists(config.bucketName);
if (!exists) await client.makeBucket(config.bucketName);
}
export async function uploadS3(config: S3Config, input: { data: StorageUploadInput }): Promise<StorageResult> {
const client = await getS3Client(config);
await ensureBucket(config);
const key = `${BASE_DIR}${input.data.path}`;
try {
await client.statObject(config.bucketName, key);
return {success: false, provider: "s3", error: "File already exists"};
} catch {
// continue if not found
}
await client.putObject(config.bucketName, key, input.data.file as Buffer);
return {
success: true,
provider: "s3",
};
}
export async function getS3(config: S3Config, input: { data: StorageGetInput }): Promise<StorageResult> {
const client = await getS3Client(config);
// const key = input.data.path;
const key = `${BASE_DIR}${input.data.path}`;
try {
await client.statObject(config.bucketName, key);
} catch {
return {success: false, provider: "s3", error: "File not found"};
}
const presignedUrl = await client.presignedGetObject(config.bucketName, key, 60);
const fileStream = await client.getObject(config.bucketName, key);
const chunks: Buffer[] = [];
for await (const chunk of fileStream) chunks.push(chunk as Buffer);
const buffer = Buffer.concat(chunks);
return {
success: true,
provider: "s3",
file: buffer,
url: presignedUrl,
};
}
export async function deleteS3(config: S3Config, input: { data: StorageDeleteInput }): Promise<StorageResult> {
const client = await getS3Client(config);
// const key = input.data.path;
const key = `${BASE_DIR}${input.data.path}`;
try {
await client.removeObject(config.bucketName, key);
return {success: true, provider: "s3"};
} catch (err: any) {
return {success: false, provider: "s3", error: err.message};
}
}