minecraft-web/backend/lib/s3.js

136 lines
2.8 KiB
JavaScript
Raw Normal View History

import {
S3Client,
PutObjectCommand,
GetObjectCommand,
HeadObjectCommand,
DeleteObjectCommand,
ListObjectsV2Command,
} from "@aws-sdk/client-s3";
2025-12-16 08:40:32 +09:00
// S3 설정 (RustFS) - 환경변수에서 로드
const s3Config = {
endpoint: process.env.S3_ENDPOINT,
accessKey: process.env.S3_ACCESS_KEY,
secretKey: process.env.S3_SECRET_KEY,
bucket: "minecraft",
publicUrl: "https://s3.caadiq.co.kr",
};
// S3 클라이언트 생성
const s3Client = new S3Client({
endpoint: s3Config.endpoint,
region: "us-east-1",
credentials: {
accessKeyId: s3Config.accessKey,
secretAccessKey: s3Config.secretKey,
},
forcePathStyle: true, // RustFS/MinIO용
});
2025-12-16 08:40:32 +09:00
/**
* S3(RustFS) 파일 업로드
*/
async function uploadToS3(
bucket,
key,
data,
contentType = "application/octet-stream"
) {
const command = new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: data,
ContentType: contentType,
2025-12-16 08:40:32 +09:00
});
await s3Client.send(command);
// 공개 URL 반환 (key는 인코딩)
const encodedKey = key
.split("/")
.map((s) => encodeURIComponent(s))
.join("/");
return `${s3Config.publicUrl}/${bucket}/${encodedKey}`;
2025-12-16 08:40:32 +09:00
}
/**
* S3(RustFS)에서 파일 다운로드
*/
async function downloadFromS3(bucket, key) {
const command = new GetObjectCommand({
Bucket: bucket,
Key: key,
});
const response = await s3Client.send(command);
// ReadableStream을 Buffer로 변환
const chunks = [];
for await (const chunk of response.Body) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
}
/**
* S3(RustFS) 파일이 존재하는지 확인
*/
async function checkS3Exists(bucket, key) {
try {
const command = new HeadObjectCommand({
Bucket: bucket,
Key: key,
});
await s3Client.send(command);
return true;
} catch (err) {
if (err.name === "NotFound" || err.$metadata?.httpStatusCode === 404) {
return false;
}
throw err;
}
}
/**
* S3(RustFS)에서 파일 삭제
*/
async function deleteFromS3(bucket, key) {
const command = new DeleteObjectCommand({
Bucket: bucket,
Key: key,
});
await s3Client.send(command);
}
/**
* S3(RustFS)에서 prefix로 시작하는 모든 파일 삭제
*/
async function deleteByPrefix(bucket, prefix) {
const listCommand = new ListObjectsV2Command({
Bucket: bucket,
Prefix: prefix,
});
const listResult = await s3Client.send(listCommand);
const objects = listResult.Contents || [];
let deletedCount = 0;
for (const obj of objects) {
try {
await deleteFromS3(bucket, obj.Key);
deletedCount++;
} catch (err) {
console.error(`[S3] 파일 삭제 실패: ${obj.Key} - ${err.message}`);
}
}
return deletedCount;
}
export {
s3Config,
uploadToS3,
downloadFromS3,
checkS3Exists,
deleteFromS3,
deleteByPrefix,
};