Skip to content

Commit 116debc

Browse files
committed
fix : server s3 logic -> client s3 logic
1 parent d59e0ba commit 116debc

7 files changed

Lines changed: 163 additions & 44 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"zustand": "^5.0.7"
3838
},
3939
"devDependencies": {
40+
"@aws-sdk/s3-request-presigner": "^3.873.0",
4041
"@eslint/eslintrc": "^3",
4142
"@tailwindcss/postcss": "^4",
4243
"@types/next-pwa": "^5.6.9",

pnpm-lock.yaml

Lines changed: 102 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/(pages)/(main)/make-video/_components/video-image-upload.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { useState, useEffect } from 'react';
44
import { useVideoCreationStore } from '@/stores/video-creation-store';
5-
import { useUploadService } from '@/hooks/use-upload-service';
65
import { VideoUploadCard } from './video-upload-card';
76
import { ImageUploadCard } from './image-upload-card';
87
import { FieldContainer } from '@/components/store-info';
@@ -11,6 +10,7 @@ import MakeVideoStartIcon from '@/public/svg/make-video/make-video-start.svg';
1110
import { GradientProgressBar } from '@/components/gradient-progress-bar';
1211
import { useRouter } from 'next/navigation';
1312
import { createVideoGeneration } from '@/lib/api/video/video';
13+
import { useUploadService } from '@/hooks/use-upload-service';
1414

1515
export function VideoImageUpload() {
1616
const router = useRouter();
@@ -79,8 +79,6 @@ export function VideoImageUpload() {
7979
toast.error(error.message);
8080
setIsProcessing(false);
8181
},
82-
validateBeforeUpload: true,
83-
uploadMode: 'sequential',
8482
});
8583

8684
const handleVideoFileSelect = (files: File[]) => {

src/app/api/logout/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ export async function POST(request: NextRequest) {
55
try {
66
const cookieStore = await cookies();
77

8-
// accessToken � �
8+
// accessToken
99
cookieStore.delete('accessToken');
10-
localStorage.removeItem('accessToken');
1110

1211
return NextResponse.json({
1312
success: true,

src/hooks/use-upload-service.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,8 @@ import { useState, useCallback } from 'react';
44
import { useMutation } from '@tanstack/react-query';
55
import { UploadService } from '@/services/upload/UploadService';
66
import { FileValidationService } from '@/services/upload/FileValidationService';
7-
import type {
8-
UploadResult,
9-
ValidationResult,
10-
} from '@/services/upload/types';
11-
import {
12-
DEFAULT_UPLOAD_CONFIG,
13-
UploadError,
14-
} from '@/services/upload/types';
7+
import type { UploadResult, ValidationResult } from '@/services/upload/types';
8+
import { DEFAULT_UPLOAD_CONFIG, UploadError } from '@/services/upload/types';
159
import { toast } from 'sonner';
1610

1711
interface UseUploadServiceOptions {

src/lib/utils/server-s3-client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { S3Client } from '@aws-sdk/client-s3';
33

44
// 서버 전용 S3 클라이언트 (환경변수 보호)
55
export const serverS3Client = new S3Client({
6-
region: process.env.AWS_REGION!,
6+
region: process.env.NEXT_PUBLIC_AWS_REGION!,
77
credentials: {
8-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
9-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
8+
accessKeyId: process.env.NEXT_PUBLIC_AWS_ACCESS_KEY_ID!,
9+
secretAccessKey: process.env.NEXT_PUBLIC_AWS_SECRET_ACCESS_KEY!,
1010
},
1111
});
1212

13-
export const BUCKET_NAME = process.env.S3_BUCKET_NAME!;
13+
export const BUCKET_NAME = process.env.NEXT_PUBLIC_S3_BUCKET_NAME!;

src/services/upload/UploadService.ts

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import type {
2-
IUploadService,
3-
UploadResult,
4-
UploadOptions,
5-
} from './types';
6-
import {
7-
DEFAULT_UPLOAD_CONFIG,
8-
UploadError,
9-
} from './types';
1+
import { PutObjectCommand } from '@aws-sdk/client-s3';
2+
import type { IUploadService, UploadResult, UploadOptions } from './types';
3+
import { DEFAULT_UPLOAD_CONFIG, UploadError } from './types';
4+
import { BUCKET_NAME, serverS3Client } from '@/lib/utils/server-s3-client';
105

116
export class UploadService implements IUploadService {
127
private static instance: UploadService;
@@ -30,36 +25,66 @@ export class UploadService implements IUploadService {
3025
formData.append('file', file);
3126

3227
try {
33-
const response = await fetch('/api/upload', {
34-
method: 'POST',
35-
body: formData,
28+
// const response = await fetch('/api/upload', {
29+
// method: 'POST',
30+
// body: formData,
31+
// });
32+
const file = formData.get('file') as File;
33+
const timestamp = Date.now();
34+
const randomString = Math.random().toString(36).substring(2, 15);
35+
const fileExtension = file.name.split('.').pop()?.toLowerCase();
36+
const fileType = file.type.startsWith('image/') ? 'images' : 'videos';
37+
const key = `uploads/${fileType}/${timestamp}-${randomString}.${fileExtension}`;
38+
const buffer = Buffer.from(await file.arrayBuffer());
39+
40+
// S3에 업로드
41+
const command = new PutObjectCommand({
42+
Bucket: BUCKET_NAME,
43+
Key: key,
44+
Body: buffer,
45+
ContentType: file.type,
46+
Metadata: {
47+
originalName: Buffer.from(file.name, 'utf-8').toString('base64'),
48+
uploadedAt: new Date().toISOString(),
49+
},
3650
});
51+
await serverS3Client.send(command);
3752

38-
if (!response.ok) {
39-
const errorData = await response.json() as { error?: string };
40-
throw new UploadError(
41-
errorData.error ?? '업로드에 실패했습니다.',
42-
'UPLOAD_FAILED',
43-
file.name,
44-
);
45-
}
53+
// public URL 생성
54+
const publicUrl = `https://${BUCKET_NAME}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`;
4655

47-
const result = await response.json() as {
48-
url: string;
49-
fileName: string;
50-
fileSize: number;
51-
fileType: string;
52-
metadata?: Record<string, unknown>;
56+
const result = {
57+
success: true,
58+
url: publicUrl,
59+
fileName: file.name,
60+
fileSize: file.size,
61+
fileType: file.type,
5362
};
5463

64+
// if (!response.ok) {
65+
// const errorData = await response.json() as { error?: string };
66+
// throw new UploadError(
67+
// errorData.error ?? '업로드에 실패했습니다.',
68+
// 'UPLOAD_FAILED',
69+
// file.name,
70+
// );
71+
// }
72+
73+
// const result = await response.json() as {
74+
// url: string;
75+
// fileName: string;
76+
// fileSize: number;
77+
// fileType: string;
78+
// metadata?: Record<string, unknown>;
79+
// };
80+
5581
return {
5682
success: true,
5783
url: result.url,
5884
fileName: result.fileName,
5985
fileSize: result.fileSize,
6086
fileType: result.fileType,
6187
uploadTime: Date.now(),
62-
metadata: result.metadata ?? {},
6388
};
6489
} catch (error) {
6590
if (error instanceof UploadError) {

0 commit comments

Comments
 (0)