diff --git a/src/Controller/OgRepository/Image/BackupImageAction.php b/src/Controller/OgRepository/Image/BackupImageAction.php index aaf3d1f..3a2c2ac 100644 --- a/src/Controller/OgRepository/Image/BackupImageAction.php +++ b/src/Controller/OgRepository/Image/BackupImageAction.php @@ -34,10 +34,26 @@ class BackupImageAction extends AbstractOgRepositoryController $image = $imageImageRepository->getImage(); $repository = $imageImageRepository->getRepository(); + $this->validateImageName($image); + $this->logger->info('Create backup image', ['image' => $image->getName()]); + + $content = $this->createBackupRequest($input, $imageImageRepository, $repository); + $this->handleBackupResponse($content); + + $this->processBackupSuccess($input, $image, $repository, $imageImageRepository, $content); + + return new JsonResponse(data: $content, status: Response::HTTP_OK); + } + + private function validateImageName(Image $image): void + { if (!$image->getName()) { throw new BadRequestHttpException('Name is required'); } + } + private function createBackupRequest(BackupImageInput $input, ImageImageRepository $imageImageRepository, ImageRepository $repository): array + { $params = [ 'json' => [ 'ID_img' => $imageImageRepository->getImageFullsum(), @@ -48,16 +64,85 @@ class BackupImageAction extends AbstractOgRepositoryController ] ]; - $this->logger->info('Create backup image', ['image' => $image->getName()]); + return $this->createRequest('PUT', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params); + } - $repository = $imageImageRepository->getRepository(); - - $content = $this->createRequest('PUT', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params); - - if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { - throw new BadRequestHttpException('Error backing up image: ' . $content['error'] . ' - ' . $content['details']); + private function handleBackupResponse(array $content): void + { + if (!isset($content['error'])) { + return; } + $errorMessage = $this->extractErrorMessage($content); + $errorCode = $content['code'] ?? Response::HTTP_BAD_REQUEST; + + $this->throwAppropriateException($errorCode, $errorMessage); + } + + private function extractErrorMessage(array $content): string + { + $errorMessage = $content['error']; + $errorDetails = $content['details'] ?? null; + + if (!$errorDetails) { + return $errorMessage; + } + + $extractedMessage = $this->extractMessageFromDetails($errorDetails); + + return $extractedMessage ?: $errorMessage; + } + + private function extractMessageFromDetails($errorDetails): ?string + { + if (is_array($errorDetails)) { + return $errorDetails['details'] ?? $errorDetails['message'] ?? $errorDetails['error'] ?? null; + } + + if (is_string($errorDetails)) { + $parsed = $this->parseJsonString($errorDetails); + if ($parsed !== null) { + return $parsed['details'] ?? $parsed['message'] ?? $parsed['error'] ?? null; + } + + return !empty($errorDetails) ? $errorDetails : null; + } + + return null; + } + + private function parseJsonString(string $jsonString): ?array + { + $cleanJson = trim($jsonString, " \t\n\r\0\x0B"); + $decoded = json_decode($cleanJson, true); + + return (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) ? $decoded : null; + } + + private function throwAppropriateException(int $errorCode, string $errorMessage): void + { + if ($errorCode === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new BadRequestHttpException('Error backing up image: ' . $errorMessage); + } + + if ($errorCode >= 400 && $errorCode < 500) { + throw new BadRequestHttpException($errorMessage); + } + + if ($errorCode >= 500) { + throw new BadRequestHttpException('Error backing up image: ' . $errorMessage); + } + + throw new BadRequestHttpException($errorMessage); + } + + private function processBackupSuccess( + BackupImageInput $input, + Image $image, + ImageRepository $repository, + ImageImageRepository $imageImageRepository, + array $content + ): void { $inputData = [ 'imageName' => $image->getName(), 'repositoryUuid' => $repository->getUuid(), @@ -67,13 +152,16 @@ class BackupImageAction extends AbstractOgRepositoryController 'remote_path' => $input->remotePath ]; - $this->createService->__invoke($image->getClient(), CommandTypes::BACKUP_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData); + $this->createService->__invoke( + $image->getClient(), + CommandTypes::BACKUP_IMAGE, + TraceStatus::IN_PROGRESS, + $content['job_id'], + $inputData + ); $imageImageRepository->setStatus(ImageStatus::BACKUP); $this->entityManager->persist($imageImageRepository); $this->entityManager->flush(); - - - return new JsonResponse(data: $content, status: Response::HTTP_OK); } } \ No newline at end of file diff --git a/src/Controller/OgRepository/Image/ImportAction.php b/src/Controller/OgRepository/Image/ImportAction.php index 31c501c..667c4fa 100644 --- a/src/Controller/OgRepository/Image/ImportAction.php +++ b/src/Controller/OgRepository/Image/ImportAction.php @@ -19,6 +19,7 @@ use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Component\HttpKernel\Exception\HttpException; #[AsController] class ImportAction extends AbstractOgRepositoryController @@ -30,20 +31,52 @@ class ImportAction extends AbstractOgRepositoryController * @throws ClientExceptionInterface */ public function __invoke(ImportImageRepositoryInput $input, ImageRepository $repository): JsonResponse + { + $this->validateRepositoryStatus($repository); + + $image = $input->name; + $imageEntity = $this->getOrCreateImageEntity($image); + $this->validateImageNotExistsInRepository($imageEntity, $repository); + + $this->logger->info('Creating aux files', ['image' => $image]); + + $content = $this->createTorrentSumRequest($repository, $image); + $this->handleTorrentSumResponse($content); + + $imageImageRepositoryEntity = $this->createImageImageRepositoryEntity($imageEntity, $repository, $image); + $this->entityManager->persist($imageImageRepositoryEntity); + $this->entityManager->flush(); + + $this->createService->__invoke( + null, + CommandTypes::CREATE_IMAGE_AUX_FILE, + TraceStatus::IN_PROGRESS, + $content['job_id'], + [ + 'imageName' => $image, + 'imageImageRepositoryUuid' => $imageImageRepositoryEntity->getUuid(), + ] + ); + + return new JsonResponse(data: [], status: Response::HTTP_OK); + } + + private function validateRepositoryStatus(ImageRepository $repository): void { $content = $this->createRequest('GET', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/status'); if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { throw new BadRequestHttpException('An error occurred while fetching the status: ' . $content['details']); } + } - $image = $input->name; + private function getOrCreateImageEntity(string $imageName): Image + { + $imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $imageName]); - $imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $image]); - - if (!$imageEntity){ + if (!$imageEntity) { $imageEntity = new Image(); - $imageEntity->setName($image); + $imageEntity->setName($imageName); $imageEntity->setType('monolithic'); $imageEntity->setRemotePc(false); $imageEntity->setIsGlobal(false); @@ -51,65 +84,97 @@ class ImportAction extends AbstractOgRepositoryController $this->entityManager->persist($imageEntity); } - $imageImageRepositoryEntity = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['image' => $imageEntity, 'repository' => $repository]); + return $imageEntity; + } - if ($imageImageRepositoryEntity){ + private function validateImageNotExistsInRepository(Image $imageEntity, ImageRepository $repository): void + { + $imageImageRepositoryEntity = $this->entityManager->getRepository(ImageImageRepository::class) + ->findOneBy(['image' => $imageEntity, 'repository' => $repository]); + + if ($imageImageRepositoryEntity) { throw new BadRequestHttpException('This image already exists in this repository'); } + } - $imageImageRepositoryEntity = new ImageImageRepository(); - $imageImageRepositoryEntity->setName($imageEntity->getName()); - $imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING); - $imageImageRepositoryEntity->setImage($imageEntity); - $imageImageRepositoryEntity->setRepository($repository); - $imageImageRepositoryEntity->setVersion($this->extractVersionFromImageName($image)); - - $this->entityManager->persist($imageImageRepositoryEntity); - $this->entityManager->flush(); - - $this->logger->info('Creating aux files', ['image' => $image]); - + private function createTorrentSumRequest(ImageRepository $repository, string $image): array + { $params = [ 'json' => [ 'image' => $image.'.img' ] ]; - $content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params); - - if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { - throw new BadRequestHttpException('Error importing image' . ' - ' . $content['error'] . ' - ' . $content['details']); - } - - $inputData = [ - 'imageName' => $image, - 'imageImageRepositoryUuid' => $imageImageRepositoryEntity->getUuid(), - ]; - - $this->createService->__invoke(null, CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData); - - return new JsonResponse(data: [], status: Response::HTTP_OK); + return $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params); } + private function handleTorrentSumResponse(array $content): void + { + if (!isset($content['error'])) { + return; + } + + $errorMessage = $this->extractErrorMessage($content); + $errorCode = $content['code'] ?? Response::HTTP_BAD_REQUEST; + + $this->throwAppropriateException($errorCode, $errorMessage); + } + + private function extractErrorMessage(array $content): string + { + $errorMessage = $content['error']; + $errorDetails = $content['details'] ?? null; + + if (!$errorDetails) { + return $errorMessage; + } + + if (is_array($errorDetails)) { + return $errorDetails['message'] ?? $errorDetails['error'] ?? $errorMessage; + } + + if (is_string($errorDetails) && !empty($errorDetails)) { + return $errorDetails; + } + + return $errorMessage; + } + + private function throwAppropriateException(int $errorCode, string $errorMessage): void + { + if ($errorCode >= 400 && $errorCode < 500) { + throw new BadRequestHttpException($errorMessage); + } + + if ($errorCode >= 500) { + throw new HttpException($errorCode, $errorMessage); + } + + throw new BadRequestHttpException($errorMessage); + } + + private function createImageImageRepositoryEntity(Image $imageEntity, ImageRepository $repository, string $imageName): ImageImageRepository + { + $imageImageRepositoryEntity = new ImageImageRepository(); + $imageImageRepositoryEntity->setName($imageEntity->getName()); + $imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING); + $imageImageRepositoryEntity->setImage($imageEntity); + $imageImageRepositoryEntity->setRepository($repository); + $imageImageRepositoryEntity->setVersion($this->extractVersionFromImageName($imageName)); + + return $imageImageRepositoryEntity; + } private function extractVersionFromImageName(string $imageName): int { - // Buscar patrones como "_v2", "_v3", etc. - if (preg_match('/_v(\d+)$/', $imageName, $matches)) { - return (int) $matches[1]; + $patterns = ['/_v(\d+)$/', '/-v(\d+)$/', '/v(\d+)$/']; + + foreach ($patterns as $pattern) { + if (preg_match($pattern, $imageName, $matches)) { + return (int) $matches[1]; + } } - // Buscar patrones como "-v2", "-v3", etc. - if (preg_match('/-v(\d+)$/', $imageName, $matches)) { - return (int) $matches[1]; - } - - // Buscar patrones como "v2", "v3" al final del nombre - if (preg_match('/v(\d+)$/', $imageName, $matches)) { - return (int) $matches[1]; - } - - // Si no se encuentra ningún patrón de versión, devolver 1 por defecto return 1; } } \ No newline at end of file