- Ajoute jobId dans ChapterScrapingStarted et ChapterScrapingFailed - Publie job.created (PENDING) depuis ScrapeChapterStateProcessor - Publie job.status_changed (in_progress/completed/failed) depuis ScrapingEventSubscriber - Gère job.created et job.status_changed dans activityStore : ajout instantané et suppression différée (1.5s)
148 lines
5.1 KiB
PHP
148 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace App\Domain\Scraping\Infrastructure\EventSubscriber;
|
|
|
|
use App\Domain\Shared\Domain\Event\ChapterScraped;
|
|
use App\Domain\Scraping\Domain\Event\ChapterScrapingFailed;
|
|
use App\Domain\Scraping\Domain\Event\ChapterScrapingStarted;
|
|
use App\Domain\Scraping\Domain\Event\PageScrapingProgressed;
|
|
use App\Domain\Scraping\Domain\Contract\Repository\ChapterRepositoryInterface;
|
|
use App\Domain\Shared\Domain\Contract\JobRepositoryInterface;
|
|
use App\Domain\Shared\Domain\Contract\NotificationInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\Mercure\HubInterface;
|
|
use Symfony\Component\Mercure\Update;
|
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
|
|
|
class ScrapingEventSubscriber implements EventSubscriberInterface
|
|
{
|
|
public function __construct(
|
|
private readonly HubInterface $hub,
|
|
private readonly ChapterRepositoryInterface $chapterRepository,
|
|
private readonly JobRepositoryInterface $jobRepository,
|
|
private readonly NotificationInterface $notification,
|
|
private readonly LoggerInterface $logger
|
|
) {
|
|
}
|
|
|
|
public static function getSubscribedEvents(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
#[AsMessageHandler]
|
|
public function onPageScrapingProgressed(PageScrapingProgressed $event): void
|
|
{
|
|
$progress = (int) round($event->getProgress()->getPercentage());
|
|
|
|
$update = new Update(
|
|
'jobs/activity',
|
|
json_encode([
|
|
'type' => 'job.progress_updated',
|
|
'jobId' => $event->getJobId(),
|
|
'progress' => $progress,
|
|
])
|
|
);
|
|
$this->hub->publish($update);
|
|
}
|
|
|
|
#[AsMessageHandler]
|
|
public function onChapterScrapingStarted(ChapterScrapingStarted $event): void
|
|
{
|
|
$this->hub->publish(new Update(
|
|
'jobs/activity',
|
|
json_encode(['type' => 'job.status_changed', 'jobId' => $event->getJobId(), 'status' => 'in_progress'])
|
|
));
|
|
|
|
$this->notification->sendInfo(
|
|
sprintf('Scraping du chapitre %s de "%s" démarré', $event->getChapterNumber(), $event->getMangaTitle())
|
|
);
|
|
}
|
|
|
|
#[AsMessageHandler]
|
|
public function onChapterScraped(ChapterScraped $event): void
|
|
{
|
|
$jobId = $event->getJobId();
|
|
$this->logger->info('ChapterScraped reçu pour le job: ' . $jobId);
|
|
|
|
$job = $this->jobRepository->get($jobId);
|
|
|
|
if (!$job) {
|
|
$this->logger->warning('Job non trouvé pour l\'ID: ' . $jobId);
|
|
return;
|
|
}
|
|
|
|
$chapterId = $job->context['chapterId'] ?? null;
|
|
$this->logger->info('ChapterId extrait du job: ' . $chapterId);
|
|
|
|
$chapter = $this->chapterRepository->getById($chapterId);
|
|
|
|
if (!$chapter) {
|
|
$this->logger->warning('Chapitre non trouvé pour l\'ID: ' . $chapterId);
|
|
return;
|
|
}
|
|
|
|
$this->logger->info('Chapitre trouvé - ID: ' . $chapter->id . ', MangaId: ' . $chapter->mangaId . ', Number: ' . $chapter->chapterNumber);
|
|
|
|
$data = [
|
|
'type' => 'chapter.scraped',
|
|
'chapterId' => $chapter->id,
|
|
'mangaId' => $chapter->mangaId,
|
|
'chapterNumber' => $chapter->chapterNumber,
|
|
'isAvailable' => true,
|
|
'timestamp' => (new \DateTimeImmutable())->format('c')
|
|
];
|
|
|
|
$topics = [
|
|
'manga/chapter/' . $chapter->id,
|
|
'manga/' . $chapter->mangaId . '/chapters',
|
|
'scraping/status'
|
|
];
|
|
|
|
$update = new Update($topics, json_encode($data));
|
|
$this->hub->publish($update);
|
|
|
|
$this->hub->publish(new Update(
|
|
'jobs/activity',
|
|
json_encode(['type' => 'job.status_changed', 'jobId' => $jobId, 'status' => 'completed'])
|
|
));
|
|
|
|
$mangaTitle = $job->context['mangaTitle'] ?? 'manga inconnu';
|
|
$this->notification->sendSuccess(
|
|
sprintf('Chapitre %s de "%s" scrappé avec succès', $chapter->chapterNumber, $mangaTitle)
|
|
);
|
|
}
|
|
|
|
#[AsMessageHandler]
|
|
public function onChapterScrapingFailed(ChapterScrapingFailed $event): void
|
|
{
|
|
$this->hub->publish(new Update(
|
|
'jobs/activity',
|
|
json_encode(['type' => 'job.status_changed', 'jobId' => $event->getJobId(), 'status' => 'failed'])
|
|
));
|
|
|
|
$this->logger->info('ChapterScrapingFailed reçu pour mangaId: ' . $event->getMangaId() . ', chapter: ' . $event->getChapterNumber());
|
|
|
|
$data = [
|
|
'type' => 'chapter.scraping.failed',
|
|
'mangaId' => $event->getMangaId(),
|
|
'chapterNumber' => $event->getChapterNumber(),
|
|
'reason' => $event->getReason(),
|
|
'timestamp' => (new \DateTimeImmutable())->format('c')
|
|
];
|
|
|
|
$topics = [
|
|
'manga/' . $event->getMangaId() . '/chapters',
|
|
'scraping/status'
|
|
];
|
|
|
|
$update = new Update($topics, json_encode($data));
|
|
$this->hub->publish($update);
|
|
|
|
$this->notification->sendError(
|
|
sprintf('Échec du scraping du chapitre %s : %s', $event->getChapterNumber(), $event->getReason())
|
|
);
|
|
}
|
|
}
|