mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-21 14:08:10 +02:00
feat: Initialize the core Express server with security, session management, and service integrations, and add a Docker volume for audio file persistence.
This commit is contained in:
1 parent
04373d2881
commit
94429e86df
3 files changed
+24
-21
No files matched your search
@@ -49,6 +49,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- encryption_key:/app/.encryption-key-data
|
- encryption_key:/app/.encryption-key-data
|
||||||
|
- audio_uploads:/app/uploads/audio
|
||||||
command: npm run start
|
command: npm run start
|
||||||
|
|
||||||
# Service FFmpeg dédié
|
# Service FFmpeg dédié
|
||||||
@@ -70,6 +71,8 @@ volumes:
|
|||||||
driver: local
|
driver: local
|
||||||
encryption_key:
|
encryption_key:
|
||||||
driver: local
|
driver: local
|
||||||
|
audio_uploads:
|
||||||
|
driver: local
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
# Réseau interne pour la communication DB <-> App
|
# Réseau interne pour la communication DB <-> App
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ const authLimiter = rateLimit({
|
|||||||
app.use('/api/', globalLimiter);
|
app.use('/api/', globalLimiter);
|
||||||
app.use('/api/auth/login', authLimiter);
|
app.use('/api/auth/login', authLimiter);
|
||||||
|
|
||||||
|
// Serve locally stored audio files
|
||||||
|
const AUDIO_UPLOAD_DIR = process.env.AUDIO_UPLOAD_DIR || '/app/uploads/audio';
|
||||||
|
app.use('/uploads/audio', express.static(AUDIO_UPLOAD_DIR));
|
||||||
|
|
||||||
declare module 'http' {
|
declare module 'http' {
|
||||||
interface IncomingMessage {
|
interface IncomingMessage {
|
||||||
rawBody: unknown
|
rawBody: unknown
|
||||||
|
|||||||
+17
-21
@@ -56,9 +56,16 @@ const upload = multer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup audio upload with different filters
|
// Setup audio upload with different filters
|
||||||
|
// Files saved directly to the persistent local folder
|
||||||
|
const AUDIO_UPLOAD_DIR = process.env.AUDIO_UPLOAD_DIR || '/app/uploads/audio';
|
||||||
|
|
||||||
|
// Ensure the directory exists at startup
|
||||||
|
import { mkdirSync } from 'fs';
|
||||||
|
try { mkdirSync(AUDIO_UPLOAD_DIR, { recursive: true }); } catch { /* already exists */ }
|
||||||
|
|
||||||
const audioUpload = multer({
|
const audioUpload = multer({
|
||||||
storage: multer.diskStorage({
|
storage: multer.diskStorage({
|
||||||
destination: os.tmpdir(),
|
destination: AUDIO_UPLOAD_DIR,
|
||||||
filename: (req, file, cb) => {
|
filename: (req, file, cb) => {
|
||||||
const safeName = file.originalname.replace(/[^a-zA-Z0-9.]/g, '_');
|
const safeName = file.originalname.replace(/[^a-zA-Z0-9.]/g, '_');
|
||||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
||||||
@@ -67,7 +74,7 @@ const audioUpload = multer({
|
|||||||
}),
|
}),
|
||||||
limits: {
|
limits: {
|
||||||
fileSize: 50 * 1024 * 1024, // 50MB max for audio
|
fileSize: 50 * 1024 * 1024, // 50MB max for audio
|
||||||
files: 5
|
files: 20
|
||||||
},
|
},
|
||||||
fileFilter: (req, file, cb) => {
|
fileFilter: (req, file, cb) => {
|
||||||
if (ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype) || file.originalname.match(/\.(mp3|wav|ogg)$/i)) {
|
if (ALLOWED_AUDIO_MIME_TYPES.includes(file.mimetype) || file.originalname.match(/\.(mp3|wav|ogg)$/i)) {
|
||||||
@@ -977,7 +984,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Audio Tracks Management (Admin Only) - Multi-file upload
|
// Audio Tracks Management (Admin Only) - Multi-file upload (stored locally)
|
||||||
app.post("/api/audio-tracks", requireAdmin, audioUpload.array("files", 20), async (req, res) => {
|
app.post("/api/audio-tracks", requireAdmin, audioUpload.array("files", 20), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const files = req.files as Express.Multer.File[];
|
const files = req.files as Express.Multer.File[];
|
||||||
@@ -990,41 +997,30 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
try {
|
try {
|
||||||
console.log(`🎵 Processing audio upload: ${file.originalname} (${(file.size / 1024 / 1024).toFixed(2)} MB)`);
|
console.log(`🎵 Audio saved locally: ${file.originalname} (${(file.size / 1024 / 1024).toFixed(2)} MB)`);
|
||||||
|
|
||||||
// Upload to Cloudinary; audio is categorized as "video" in Cloudinary
|
// Build a public URL served by Express at /uploads/audio/<filename>
|
||||||
const uploadResult = await cloudinaryService.uploadMedia(
|
const publicUrl = `/uploads/audio/${file.filename}`;
|
||||||
file.path,
|
|
||||||
file.originalname,
|
|
||||||
user.id,
|
|
||||||
"video"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clean up temp file immediately after upload
|
|
||||||
await fs.promises.unlink(file.path).catch(err => console.error("Failed to cleanup temp audio file:", err));
|
|
||||||
|
|
||||||
const title = file.originalname.replace(/\.[^/.]+$/, "");
|
|
||||||
|
|
||||||
const track = await storage.createAudioTrack({
|
const track = await storage.createAudioTrack({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
title: title,
|
title: file.originalname.replace(/\.[^/.]+$/, ""),
|
||||||
fileName: file.originalname,
|
fileName: file.originalname,
|
||||||
url: uploadResult.originalUrl,
|
url: publicUrl,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
results.push({ success: true, track });
|
results.push({ success: true, track });
|
||||||
} catch (fileError) {
|
} catch (fileError) {
|
||||||
// Clean up on per-file error
|
// Remove the file if DB insert fails
|
||||||
await fs.promises.unlink(file.path).catch(() => { });
|
await fs.promises.unlink(file.path).catch(() => { });
|
||||||
results.push({ success: false, fileName: file.originalname, error: fileError instanceof Error ? fileError.message : "Upload failed" });
|
results.push({ success: false, fileName: file.originalname, error: fileError instanceof Error ? fileError.message : "Save failed" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ results });
|
res.json({ results });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error uploading audio tracks:", error);
|
console.error("Error uploading audio tracks:", error);
|
||||||
// Cleanup all remaining temp files
|
|
||||||
if (req.files) {
|
if (req.files) {
|
||||||
for (const file of req.files as Express.Multer.File[]) {
|
for (const file of req.files as Express.Multer.File[]) {
|
||||||
await fs.promises.unlink(file.path).catch(() => { });
|
await fs.promises.unlink(file.path).catch(() => { });
|
||||||
|
|||||||
Reference in new issue
Block a user