diff options
| author | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-03-25 15:55:45 +0900 |
| commit | 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 (patch) | |
| tree | 8a5587f10ca55b162d7e3254cb088b323a34c41b /lib/downloadFile.ts | |
initial commit
Diffstat (limited to 'lib/downloadFile.ts')
| -rw-r--r-- | lib/downloadFile.ts | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/lib/downloadFile.ts b/lib/downloadFile.ts new file mode 100644 index 00000000..e2777976 --- /dev/null +++ b/lib/downloadFile.ts @@ -0,0 +1,81 @@ +'use server' + +import fs from 'fs/promises' +import path from 'path' +import { NextResponse } from 'next/server' + +/** + * 첨부 파일 다운로드를 위한 서버 액션 + * + * @param filePath 파일의 상대 경로 + * @returns 파일 내용(Base64 인코딩) 및 메타데이터를 포함한 객체 + */ +export async function downloadFileAction(filePath: string) { + try { + // 보안: 파일 경로가 uploads 디렉토리 내에 있는지 확인 + if (!filePath.startsWith('/uploads/') && !filePath.startsWith('uploads/')) { + return { + ok: false, + error: 'Invalid file path. Only files in the uploads directory can be downloaded.' + }; + } + + // 실제 서버 파일 시스템에서의 전체 경로 계산 + // 참고: process.cwd()는 현재 실행 중인 프로세스의 작업 디렉토리를 반환합니다. + // 환경에 따라 public 폴더나 다른 위치를 기준으로 할 수도 있습니다. + const normalizedPath = filePath.startsWith('/') ? filePath.slice(1) : filePath; + const fullPath = path.join(process.cwd(), 'public', normalizedPath); + + // 파일 존재 여부 확인 + try { + await fs.access(fullPath); + } catch { + return { ok: false, error: 'File not found' }; + } + + // 파일 읽기 + const fileBuffer = await fs.readFile(fullPath); + + // 파일 통계 정보 가져오기 + const stats = await fs.stat(fullPath); + + // MIME 타입 추측 + const extension = path.extname(fullPath).toLowerCase(); + let mimeType = 'application/octet-stream'; // 기본값 + + // 일반적인 파일 타입에 대한 MIME 타입 매핑 + const mimeTypes = { + '.pdf': 'application/pdf', + '.doc': 'application/msword', + '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + '.xls': 'application/vnd.ms-excel', + '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.txt': 'text/plain', + }; + + if (extension in mimeTypes) { + mimeType = mimeTypes[extension]; + } + + // Base64로 인코딩하여 반환 + return { + ok: true, + data: { + content: fileBuffer.toString('base64'), + fileName: path.basename(fullPath), + size: stats.size, + mimeType, + }, + }; + } catch (error) { + console.error('Download error:', error); + return { + ok: false, + error: error instanceof Error ? error.message : 'An unknown error occurred' + }; + } +}
\ No newline at end of file |
