demo-visite-virtuelle / server.cjs
Natha1627
Initial commit
3b6bb5e
const { execFile } = require('child_process');
const http = require('http');
const fs = require('fs');
const path = require('path');
const formidable = require('formidable'); // Ajout de formidable pour analyser les requêtes multipart/form-data
// Importer dotenv pour gérer les variables d'environnement
require('dotenv').config();
const { Storage } = require('@google-cloud/storage');
// Si la variable GOOGLE_APPLICATION_CREDENTIALS n'est pas définie, on la définit ici.
if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.join(__dirname, 'service-key.json');
}
// Instancier le client Google Cloud Storage
const storage = new Storage();
const bucketName = "test3-2d896.appspot.com";
// Chemin vers le dossier contenant les fichiers statiques
const staticDir = path.join(__dirname, 'public');
// Fonction pour servir les fichiers statiques
function serveStaticFile(req, res) {
let filePath = path.join(staticDir, req.url === '/' ? 'index.html' : req.url);
// Normalisez le chemin pour éviter des caractères relatifs comme "../"
filePath = path.normalize(filePath);
// Vérifiez que le fichier demandé reste dans le dossier `public`
if (!filePath.startsWith(staticDir)) {
res.writeHead(403, { 'Content-Type': 'text/plain' });
res.end('Accès refusé');
return;
}
// Vérifiez si le fichier existe
fs.stat(filePath, (err, stats) => {
if (err || !stats.isFile()) {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Fichier non trouvé');
return;
}
// Détecte le type MIME basé sur l'extension
const ext = path.extname(filePath).toLowerCase();
const mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.svg': 'image/svg+xml',
'.wasm': 'application/wasm',
};
const contentType = mimeTypes[ext] || 'application/octet-stream';
// Lit et sert le fichier
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Erreur du serveur');
return;
}
res.writeHead(200, { 'Content-Type': contentType });
res.end(data);
});
});
}
const server = http.createServer((req, res) => {
// Ajouter les en-têtes CORS nécessaires pour toutes les requêtes
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// Gérer les requêtes OPTIONS (préflight request)
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
// Servir les fichiers statiques pour les requêtes GET
if (req.method === 'GET') {
serveStaticFile(req, res);
return;
}
// Endpoint : Création des données JSON pour une visite
if (req.method === 'POST' && req.url === '/create-visite-data') {
const bucketName = "test3-2d896.appspot.com";
const form = new formidable.IncomingForm();
form.parse(req, async (err, fields) => {
if (err) {
console.error('Erreur lors de l\'analyse de la requête :', err);
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Erreur lors de l\'analyse de la requête.');
return;
}
try {
console.log('Métadonnées brutes reçues :', fields.metadata); // Log des données brutes
const metadata = JSON.parse(fields.metadata || '{}'); // Parse en JSON
console.log('Métadonnées analysées :', metadata);
} catch (parseError) {
console.error('Erreur lors du parsing JSON :', parseError);
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Erreur dans le format du JSON envoyé.');
}
});
return;
}
if (req.method === 'POST' && req.url === '/upload-to-gcs') {
let body = '';
req.on('data', chunk => {
body += chunk.toString(); // Convertir les chunks en chaîne
});
req.on('end', () => {
try {
// Analysez le corps de la requête en JSON
const { folderPath, jsonData } = JSON.parse(body);
// Loguer le chemin du dossier et les données pour voir ce qui est reçu
console.log('Chemin du dossier:', folderPath);
console.log('Données JSON:', JSON.stringify(jsonData, null, 2));
// Chemin vers le script local_script.js
const scriptPath = path.resolve(__dirname, 'local_script.js'); // Utilisez path.resolve pour obtenir un chemin absolu
console.log(`Chemin absolu du script : ${scriptPath}`);
// Exécuter le script Node.js avec les paramètres appropriés
const args = [folderPath, JSON.stringify(jsonData)];
console.log(`Commande exécutée : node ${scriptPath} ${args.join(' ')}`); // Affichez la commande exécutée pour vérification
// Augmentez maxBuffer si nécessaire pour éviter les problèmes liés à la taille des logs
execFile('node', [scriptPath, ...args], { maxBuffer: 1024 * 1024 * 50 }, (error, stdout, stderr) => {
if (error) {
console.error(`Erreur lors de l'exécution de local_script.js :`, error);
console.error(`stderr:`, stderr);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Erreur lors du téléversement.');
return; // Sortir pour éviter un double envoi
} else {
console.log(`Téléversement réussi : ${stdout}`);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Fichier téléversé avec succès vers Google Cloud Storage.');
}
});
} catch (parseError) {
console.error('Erreur lors de la lecture du corps de la requête:', parseError);
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Erreur de format du corps de la requête.');
}
});
return; // Sortir après avoir traité cette route
}
if (req.method === 'POST' && req.url === '/create-visit') {
const form = new formidable.IncomingForm();
form.multiples = true;
form.uploadDir = './uploads';
if (!fs.existsSync(form.uploadDir)) {
fs.mkdirSync(form.uploadDir, { recursive: true });
}
const bucketName = "test3-2d896.appspot.com";
form.parse(req, async (err, fields, files) => {
if (err) {
console.error('Erreur lors de l\'analyse de la requête :', err);
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Erreur lors de l\'analyse de la requête.');
return;
}
try {
const metadata = JSON.parse(fields.metadata || '{}');
const { jsonData } = metadata;
console.log('Données JSON reçues :', jsonData);
const folderName = jsonData.folderName;
if (!folderName) {
throw new Error("Nom de dossier (folderName) manquant ou incorrect.");
}
console.log('Nom du dossier pour les fichiers téléversés :', folderName);
const uploadedFiles = Array.isArray(files.files) ? files.files : [files.files];
const uploadedUrls = [];
for (const file of uploadedFiles) {
const destinationPath = `${folderName}/${file.originalFilename}`;
console.log(`Téléversement du fichier : ${destinationPath}`);
await storage.bucket(bucketName).upload(file.filepath, {
destination: destinationPath,
metadata: {
contentType: file.mimetype,
},
});
uploadedUrls.push(`https://storage.googleapis.com/${bucketName}/${destinationPath}`);
}
jsonData.mediaUrls = uploadedUrls;
const jsonFilePath = `${folderName}/visit_data.json`;
const jsonBuffer = Buffer.from(JSON.stringify(jsonData, null, 2));
console.log(`Téléversement du fichier JSON : ${jsonFilePath}`);
await storage.bucket(bucketName).file(jsonFilePath).save(jsonBuffer, {
contentType: 'application/json',
});
console.log('Fichiers et données téléversés avec succès.');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
success: true,
message: 'Données de la visite téléversées avec succès.',
jsonFilePath,
}));
} catch (error) {
console.error('Erreur lors du traitement des données :', error);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Erreur lors du traitement des données.');
}
});
return;
}
// Route pour générer une URL signée
if (req.method === 'POST' && req.url === '/generate-signed-url') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', async () => {
try {
// Extraire le `dirUrl` du corps de la requête
const { dirUrl } = JSON.parse(body);
if (!dirUrl) {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('dirUrl est manquant');
return;
}
// Nettoyer les segments relatifs du chemin avant de générer l'URL signée
const cleanedDirUrl = dirUrl.replace(/\/?\.\.\//g, '');
const bucketName = 'test3-2d896.appspot.com';
const filePath = `users/visite_3D/${cleanedDirUrl}`; // Utiliser le chemin nettoyé sans encodage
const options = {
version: 'v4',
action: 'read',
expires: Date.now() + 15 * 60 * 1000, // URL valable pour 15 minutes
};
// Générer une URL signée (GCS s'occupe de l'encodage)
const [url] = await storage.bucket(bucketName).file(filePath).getSignedUrl(options);
console.log(`URL signée générée : ${url}`);
// Répondre avec l'URL signée
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ url }));
} catch (error) {
console.error('Erreur lors de la génération de l\'URL signée:', error);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Erreur lors de la génération de l\'URL signée.');
}
});
return;
}
// Nouvelle route pour obtenir le GCS token
if (req.method === 'GET' && req.url === '/get-gcs-token') {
try {
// Générez ou récupérez le token GCS ici
const gcsToken = '9be5e912-95e8-4e13-841e-8be3bf99505d'; // Remplacez cela par la méthode de génération dynamique si nécessaire
// Répondre avec le token
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ token: gcsToken }));
} catch (error) {
console.error('Erreur lors de la récupération du jeton GCS:', error);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Erreur lors de la récupération du jeton GCS.');
}
return;
}
// Si aucune des routes n'est trouvée, envoyer une réponse 404
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Route non trouvée');
});
server.listen(7860, () => {
console.log('Serveur en écoute sur le port 7860');
});