Ajout de la gestion des routes pour le système de capture, mise à jour des chemins de fichiers et amélioration de la logique de gestion des mesures et vidéos.

This commit is contained in:
2025-04-03 14:42:51 +02:00
parent cedd9949bd
commit 265d1c5f18
8 changed files with 52 additions and 400 deletions

2
api.js
View File

@@ -5,7 +5,6 @@ const projectRoutes = require('./routes/projectRoutes');
const measurementRoutes = require('./routes/measurementRoutes');
const videoRoutes = require('./routes/videoRoutes');
const imageRoutes = require('./routes/imageRoutes');
const cameraRoutes = require('./routes/cameraRoutes');
const uploadRoutes = require('./routes/uploadRoutes');
const FileWatcher = require('./src/data/filewatcher');
const database_manager = require('./src/database/database_manager');
@@ -22,6 +21,5 @@ router.use('/', measurementRoutes);
router.use('/', videoRoutes);
router.use('/', imageRoutes);
router.use('/', uploadRoutes);
router.use('/', cameraRoutes);
module.exports = router;

View File

@@ -1,359 +0,0 @@
const express = require('express');
const router = express.Router();
const db = require('../db');
const serverError = require('../utils/serverError');
const { start } = require('repl');
//const minInterval = 3; // Minutes
//const maxInterval = 60; // Minutes
var defaultCaptureInterval = 5; // minutes
var defaultMaintenance = 0;
var defaultActive = 0; // 0 = pas de capture, 1 = capture en cours
async function initCamera() {
const query = 'SELECT * FROM public.camera WHERE id = $1';
const values = [1];
db.query(query, values, (err, result) => {
if (err) {
console.error('Erreur lors de la vérification de l\'entrée caméra:', err);
return;
}
if (result.rows.length === 0) {
const insertQuery = `
INSERT INTO public.camera (id, interval, maintenance, active)
VALUES ($1, $2, $3, $4)
`;
const insertValues = [1, defaultCaptureInterval, defaultMaintenance, defaultActive];
db.query(insertQuery, insertValues, (err) => {
if (err) {
console.error('Erreur lors de l\'initialisation de la caméra:', err);
} else {
console.log('Caméra initialisée avec les valeurs par défaut.');
}
});
} else {
console.log('L\'entrée caméra avec l\'ID 1 existe déjà. Aucune initialisation nécessaire.');
}
});
}
async function getCamera() {
// retourner l'état de la caméra
const query = 'SELECT * FROM public.camera WHERE id = $1';
const values = [1];
try {
const result = await db.query(query, values);
if (result.rows.length === 0) {
console.log('Aucune entrée caméra trouvée.');
return null;
} else {
const camera = result.rows[0];
console.log('État de la caméra récupéré avec succès:', camera);
return {
captureInterval: camera.interval,
captureProjectID: camera.active,
captureStatus: camera.active,
maintenance: camera.maintenance
};
}
} catch (err) {
console.error('Erreur lors de la récupération de l\'état de la caméra:', err);
throw err;
}
}
async function printCameraStatus() {
let camera = await getCamera();
console.log('Statut de la caméra:');
console.log('Intervalle de capture:', camera.captureInterval, 'minutes');
console.log('Maintenance:', camera.maintenance === 1 ? 'En cours' : 'Aucune');
console.log('Statut de la capture:', camera.active === 1 ? 'En cours' : 'Arrêté');
console.log('-----------------------------------');
}
async function isCameraOccupied() {
try {
const query = 'SELECT id FROM public.projects WHERE status = $1 LIMIT 1';
const values = [1];
return new Promise((resolve, reject) => {
db.query(query, values, (err, result) => {
if (err) {
console.error('Erreur lors de la vérification de l\'occupation de la caméra:', err);
reject(err);
} else {
const isOccupied = result.rows.length > 0 ? result.rows[0].id : null;
resolve(isOccupied);
}
});
});
} catch (err) {
console.error('Erreur inattendue lors de la vérification de l\'occupation de la caméra:', err);
}
}
async function getCurrentProject() {
try {
const query = 'SELECT * FROM public.projects WHERE status = $1 LIMIT 1';
const values = [1];
return new Promise((resolve, reject) => {
db.query(query, values, (err, result) => {
if (err) {
console.error('Erreur lors de la récupération du projet en cours:', err);
reject(err);
} else if (result.rows.length === 0) {
console.log('Aucun projet en cours trouvé.');
resolve(null);
} else {
const currentProject = result.rows[0];
console.log('Projet en cours récupéré avec succès:', currentProject);
resolve(currentProject);
}
});
});
} catch (err) {
console.error('Erreur inattendue lors de la récupération du projet en cours:', err);
}
}
async function resetProjectStatus() {
const query = 'UPDATE public.projects SET status = $1 WHERE status = $2';
const values = [2, 1];
db.query(query, values, (err) => {
if (err) {
console.error('Erreur lors de la réinitialisation du statut des projets:', err);
} else {
console.log('Statut des projets réinitialisé avec succès.');
}
});
}
async function activateCamera() {
const query = 'UPDATE public.camera SET active = $1 WHERE id = $2';
const values = [1, 1];
db.query(query, values, (err) => {
if (err) {
console.error('Erreur lors de l\'activation de la caméra:', err);
} else {
console.log('Caméra activée avec succès.');
}
});
}
async function deactivateCamera() {
const query = 'UPDATE public.camera SET active = $1 WHERE id = $2';
const values = [0, 1];
db.query(query, values, (err) => {
if (err) {
console.error('Erreur lors de la désactivation de la caméra:', err);
} else {
console.log('Caméra désactivée avec succès.');
}
});
}
async function changeProjectStatus(projectId, status) {
try {
const query = 'UPDATE public.projects SET status = $1 WHERE id = $2';
const values = [status, projectId];
await db.query(query, values);
console.log(`Statut du projet ID ${projectId} modifié avec succès à ${status}.`);
} catch (err) {
console.error('Une erreur inattendue s\'est produite lors de la modification du statut du projet:', err);
}
}
async function startup() {
await initCamera();
await printCameraStatus();
}
startup()
.catch(err => {
console.error('Erreur lors de l\'initialisation de la caméra:', err);
});
/**
* @swagger
* /camera/status:
* get:
* summary: Get the current status of the camera
* tags:
* - Camera
* responses:
* 200:
* description: Successfully retrieved the camera status
* content:
* application/json:
* schema:
* type: object
* properties:
* captureInterval:
* type: integer
* description: Capture interval in minutes
* captureProjectID:
* type: integer
* description: ID of the project currently being captured
* captureStatus:
* type: integer
* description: Capture status (0 = stopped, 1 = ongoing)
* maintenance:
* type: integer
* description: Maintenance status (0 = none, 1 = ongoing)
* 500:
* description: Internal server error
*/
router.get('/camera/status', async (req, res) => {
try {
const cameraStatus = await getCamera();
res.status(200).json(cameraStatus);
} catch (err) {
serverError.sendError('Erreur lors de la récupération de l\'état de la caméra:', res, err, 500);
}
});
async function setCameraSettings(interval, maintenance) {
try {
const query = `
UPDATE public.camera
SET interval = $1, maintenance = $2
WHERE id = $3
`;
const values = [interval, maintenance, 1];
db.query(query, values, (err) => {
if (err) {
console.error('Erreur lors de la mise à jour des paramètres de la caméra:', err);
} else {
console.log('Paramètres de la caméra mis à jour avec succès.');
//captureInterval = interval;
//maintenance = maintenance;
}
});
} catch (err) {
console.error('Une erreur inattendue s\'est produite lors de la mise à jour des paramètres de la caméra:', err);
}
}
async function startProcedure(projectId, interval, maintenance) {
if (isNaN(projectId) || isNaN(interval) || isNaN(maintenance)) {
return { error: 'Invalid parameters' };
}
const cameraOccupied = await isCameraOccupied();
if (cameraOccupied) {
return { error: 'Camera is occupied by another project' };
} else {
await activateCamera();
await setCameraSettings(interval, maintenance);
await changeProjectStatus(projectId, 1); // changer le statut du projet en cours à 1 (en cours)
console.log('Procédure de capture démarrée avec succès.');
return { message: 'Capture procedure started successfully' };
}
}
async function stopProcedure() {
var project = await getCurrentProject();
console.log(project);
if (project) {
await resetProjectStatus(); // réinitialiser le statut du projet en cours
await deactivateCamera(); // désactiver la caméra
await changeProjectStatus(project.id, 2); // changer le statut du projet en cours à 2 (terminé)
console.log('Procédure de capture arrêtée avec succès.');
return { message: 'Capture procedure stopped successfully' };
} else {
return { error: 'No project is currently being captured' };
}
}
/**
* @swagger
* /procedure/start/:
* post:
* summary: Start the capture procedure
* tags:
* - Procedure
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* projectId:
* type: integer
* description: ID of the project to start capturing
* interval:
* type: integer
* description: Capture interval in minutes
* maintenance:
* type: integer
* description: Maintenance status (0 = none, 1 = ongoing)
* responses:
* 200:
* description: Successfully started the capture procedure
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* description: Success message
* error:
* type: string
* description: Error message, if any
* 500:
* description: Internal server error
* /procedure/stop/:
* post:
* summary: Stop the capture procedure
* tags:
* - Procedure
* responses:
* 200:
* description: Successfully stopped the capture procedure
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* description: Success message
* error:
* type: string
* description: Error message, if any
* 500:
* description: Internal server error
*/
router.post('/procedure/start/', async (req, res) => {
const { projectId, interval, maintenance } = req.body;
try {
const result = await startProcedure(projectId, interval, maintenance);
res.status(200).json(result);
} catch (err) {
serverError.sendError('Erreur lors du démarrage de la procédure de capture:', res, err, 500);
}
});
router.post('/procedure/stop/', async (req, res) => {
try {
const result = await stopProcedure();
res.status(200).json(result);
} catch (err) {
serverError.sendError('Erreur lors de l\'arrêt de la procédure de capture:', res, err, 500);
}
});
module.exports = router;

8
routes/capture_system.js Normal file
View File

@@ -0,0 +1,8 @@
const express = require('express');
const router = express.Router();
const sharp = require('sharp');
const fs = require('fs');
const dbTester = require('../test/tester');
const db = require('../db');
const serverError = require('../utils/serverError');

View File

@@ -34,9 +34,9 @@ router.post('/uploadmeasurement', upload.single('image'), async (req, res) => {
if (!imagePath) {
return res.status(500).json({ error: 'Failed to upload image' });
}
const measurement = await database_manager.measurement.add_measurement(projectId, timestamp, imagePath, temperature, humidity, nextOrderId);
const measurement = await database_manager.measurement.create_measurement(projectId, timestamp, imagePath, temperature, humidity, nextOrderId);
if (!measurement) {
return res.status(500).json({ error: 'Failed to add measurement' });
return res.status(500).json({ error: 'Failed to create measurement' });
}
res.json({ message: 'Measurement uploaded successfully', path: imagePath, id: measurement.id });
} catch (error) {

View File

@@ -38,7 +38,7 @@ async function checkAndRemoveInvalidEntries() {
// Run the check periodically
console.log('[INFO] Activation du FileWatcher pour surveiller les fichiers invalides...')
setInterval(checkAndRemoveInvalidEntries, 10000); // Every 10 seconds
setInterval(checkAndRemoveInvalidEntries, 1000); // Every 10 seconds
// Initial run
checkAndRemoveInvalidEntries();

View File

@@ -1,5 +1,6 @@
const fs = require('fs').promises;
const path = require('path');
const { Buffer } = require('buffer');
const PROJECTS_DIR = path.join('.');
const database_manager = require('../database/database_manager.js');
@@ -62,7 +63,8 @@ async function scanAllImages(dir = 'storage') {
}
async function saveFile(filePath, content) {
let Buffer=Buffer.from(content, 'base64');
const dir = path.dirname(filePath);
await fs.mkdir(dir, { recursive: true });
if (Buffer.isBuffer(content)) {
await fs.writeFile(filePath, content);
} else {
@@ -101,7 +103,7 @@ async function handleFileOperation(operation, ...args) {
const project = {
createProjectDirectory: async function (projectId) {
const projectPath = `${projectId}`;
const projectPath = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
await handleFileOperation(createFolder, projectPath);
await handleFileOperation(createFolder, `${projectPath}/images`);
await handleFileOperation(createFolder, `${projectPath}/videos`);
@@ -109,7 +111,7 @@ const project = {
},
deleteProjectDirectory: async function (projectId) {
const projectPath = `${projectId}`;
const projectPath = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
await handleFileOperation(deleteFolder, projectPath);
console.log("[FILE] deleteProjectDirectory : " + projectPath);
}
@@ -117,15 +119,15 @@ const project = {
const measurement = {
get_measurement_image: async function (projectId, orderId) {
const projectPath = `${projectId}`;
const imagePath = `${projectPath}/images/${orderId}.jpg`;
const projectPath = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
const imagePath = path.join(projectPath, 'images', `${orderId}.jpg`);
console.log("[FILE] get_measurement_image : " + imagePath);
return await handleFileOperation(getFile, imagePath);
},
upload_measurement_image: async function (image, projectId, orderId) {
const projectPath = `${projectId}`;
const imagePath = `${projectPath}/images/${orderId}.jpg`;
const projectPath = path.join(PROJECTS_DIR, 'storage', `${projectId}`);
const imagePath = path.join(projectPath, 'images', `${orderId}.jpg`);
console.log("[FILE] upload_measurement_image : " + imagePath);
await handleFileOperation(saveFile, imagePath, image.buffer);
return imagePath;
@@ -158,8 +160,8 @@ const measurement = {
const video = {
get_video: async function (projectId, orderId) {
const projectPath = `${projectId}`;
const videoPath = `${projectPath}/videos/${orderId}.mp4`;
const projectPath = path.join(PROJECTS_DIR, `${projectId}`);
const videoPath = `/storage/${projectPath}/videos/${orderId}.mp4`;
console.log("[FILE] get_video : " + videoPath);
return await handleFileOperation(getFile, videoPath);
},

View File

@@ -259,8 +259,8 @@ const video = {
const camera = {
get_camera: handleDatabaseOperation(async () => {
const query = `SELECT * FROM camera;`;
return (await db.query(query)).rows;
const query = `SELECT * FROM camera WHERE id = 1;`;
return (await db.query(query)).rows[0];
}),
edit_camera: handleDatabaseOperation(async (id, updates) => {
@@ -276,6 +276,12 @@ const camera = {
})
};
// zone de test
async function test_zone(){
}
test_zone();
// Export des modules
module.exports = {
project,

View File

@@ -1,30 +1,27 @@
Routes :
Workflow Caméra
- /projects = liste des projets
- /projects/:id = détail d'un projet
- /projects/:id/edit = édition d'un projet
- /projects/:id/delete = suppression d'un projet
- /projects/new = création d'un projet
- /projects/:id/measurements = liste des mesures d'un projet
- /projects/:id/measurements/:id = détail d'une mesure
- /projects/:id/measurements/:id/edit = édition d'une mesure
- /projects/:id/measurements/:id/delete = suppression d'une mesure
- /projects/:id/videos = liste des vidéos d'un projet
- /projects/:id/videos/:id = détail d'une vidéo
Côté Caméra
/camera/status // récupérer le statut de la caméra (GET)
- /measurements = liste des mesures
- /measurements/:id = détail d'une mesure
- /measurements/:id/edit = édition d'une mesure
- /measurements/:id/delete = suppression d'une mesure
- /measurements/new = création d'une mesure
si stop :
/camera/stop // arrêter la caméra (POST)
- /cameras = liste des caméras
- /cameras/:id = détail d'une caméra
- /cameras/:id/edit = édition d'une caméra
- /cameras/:id/delete = suppression d'une caméra
- /cameras/new = création d'une caméra
si upload :
/camera/upload // uploader la vidéo (POST)
- /data/image/:id = image depuis le pool de stockage
- /data/video/:id = vidéo depuis le pool de stockage
-
Côté Backend
/procedure/start // démarrer une procédure (POST)
/procedure/status // récupérer le statut de la caméra/procédure courante (GET)
/procedure/stop // arrêter la procédure courante (POST) (doit attendre la confirmation de /camera/stop)
/procedure/delete // supprimer la procédure courante (POST) (doit attendre la confirmation de /camera/delete)
Modèle de données :
table camera (paramètres de la caméra et procédure courante)
id (int, PK) - Toujours 1
interval(int) - Intervalle de la caméra (en minutes), peut être null
image
maintenance(int) - 1 ou 0, 1 = maintenance, 0 = pas de maintenance (si maintenance, la caméra ne doit pas se redémarrer)
status(int) - 1 ou 0, 1 = caméra en cours d'utilisation, 0 = caméra arrêtée (si la caméra est arrêtée, la procédure doit être arrêtée)