Regalamiunsorriso/faceai/apps/backend/src/race-storage.js
MaddoScientisto bb60201ad4
All checks were successful
Publish FaceAI Container / publish (push) Successful in 3m22s
Enhance FaceAI integration with live checks and metadata handling
- Added optional live FaceAI checks in README.md
- Implemented relative storage segment parsing in race-storage.js
- Updated server.js to include relative directory in race storage
- Refactored legacyAssets.js to resolve asset base URL dynamically
- Expanded live race tests to validate FaceAI app launch and metadata
- Introduced portrait image handling for live upload flow
- Updated faceai_handoff.php to process race storage relative directory
2026-04-19 10:38:32 +02:00

151 lines
No EOL
4 KiB
JavaScript

import fs from 'node:fs/promises';
import path from 'node:path';
const ITALIAN_MONTH_NAMES = [
'GENNAIO',
'FEBBRAIO',
'MARZO',
'APRILE',
'MAGGIO',
'GIUGNO',
'LUGLIO',
'AGOSTO',
'SETTEMBRE',
'OTTOBRE',
'NOVEMBRE',
'DICEMBRE'
];
function sanitizePathSegment(value) {
const normalized = String(value || '').trim();
if (!normalized) {
return '';
}
if (normalized === '.' || normalized === '..' || normalized.includes('..') || /[\\/]/.test(normalized)) {
throw new Error('Invalid race storage path segment');
}
return normalized;
}
function parseRelativeStorageSegments(value) {
const normalized = String(value || '').trim().replace(/\\/g, '/');
if (!normalized) {
return [];
}
return normalized
.split('/')
.map((segment) => segment.trim())
.filter(Boolean)
.map((segment) => sanitizePathSegment(segment));
}
export function normalizeRaceFolderName(value) {
return String(value || '')
.trim()
.replace(/[<>:"/\\|?*]/g, ' ')
.replace(/\s+/g, ' ')
.toUpperCase();
}
export function buildMonthFolder(year, monthIndex) {
const safeYear = sanitizePathSegment(year);
const normalizedMonthIndex = Number(monthIndex);
if (!safeYear || Number.isNaN(normalizedMonthIndex) || normalizedMonthIndex < 1 || normalizedMonthIndex > 12) {
return '';
}
return `${String(normalizedMonthIndex).padStart(2, '0')}.${ITALIAN_MONTH_NAMES[normalizedMonthIndex - 1]}`;
}
export function buildRaceStorage(storageInput = {}) {
const relativeSegments = parseRelativeStorageSegments(storageInput.relativeDir);
const relativeYear = relativeSegments[0] || '';
const relativeMonthFolder = relativeSegments.length >= 3 ? relativeSegments[1] : '';
const relativeRaceFolder = relativeSegments.length >= 3
? relativeSegments[2]
: (relativeSegments.length >= 2 ? relativeSegments[1] : '');
const year = sanitizePathSegment(storageInput.year || relativeYear);
const monthFolder = sanitizePathSegment(storageInput.monthFolder || relativeMonthFolder);
const raceFolder = sanitizePathSegment(normalizeRaceFolderName(storageInput.raceFolder || relativeRaceFolder));
if (!year || !monthFolder || !raceFolder) {
return null;
}
return {
year,
monthFolder,
raceFolder,
relativeDir: path.posix.join(year, monthFolder, raceFolder)
};
}
export async function resolveRacePklAvailability({ pklRoot, race }) {
if (!pklRoot) {
return {
available: false,
reasonCode: 'PKL_ROOT_NOT_CONFIGURED',
message: 'The PKL root is not configured for this FaceAI environment.',
storage: null
};
}
const storage = buildRaceStorage(race?.storage || race);
if (!storage) {
return {
available: false,
reasonCode: 'MISSING_RACE_STORAGE',
message: 'The legacy handoff did not provide the folder metadata required to resolve FaceAI data for this race.',
storage: null
};
}
const raceDir = path.join(pklRoot, storage.year, storage.monthFolder, storage.raceFolder);
let entries;
try {
entries = await fs.readdir(raceDir, { withFileTypes: true });
} catch (error) {
if (error?.code === 'ENOENT') {
return {
available: false,
reasonCode: 'RACE_DIRECTORY_NOT_FOUND',
message: `No FaceAI dataset directory exists for ${storage.relativeDir}.`,
storage,
raceDir
};
}
throw error;
}
const pklEntry = entries
.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.pkl'))
.sort((left, right) => left.name.localeCompare(right.name, 'en'))[0];
if (!pklEntry) {
return {
available: false,
reasonCode: 'PKL_FILE_NOT_FOUND',
message: `The race directory ${storage.relativeDir} exists, but it does not contain any .pkl file.`,
storage,
raceDir
};
}
return {
available: true,
reasonCode: null,
message: `Using ${storage.relativeDir}/${pklEntry.name}`,
storage,
raceDir,
pklPath: path.join(raceDir, pklEntry.name),
pklFileName: pklEntry.name
};
}