Skip to content

Commit

Permalink
chore: enhance error handling and refactor URL processing logic
Browse files Browse the repository at this point in the history
  • Loading branch information
datlechin committed Nov 10, 2024
1 parent 0ab5edc commit 0a053c0
Showing 1 changed file with 88 additions and 47 deletions.
135 changes: 88 additions & 47 deletions src/Api/Controllers/BatchLinkPreviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,78 +16,119 @@ public function __construct(protected LinkPreviewService $service) {}

public function handle(Request $request): Response
{
$urls = $request->getParsedBody()['urls'] ?? [];
$urlsToFetch = [];
try {
$urls = $request->getParsedBody()['urls'] ?? [];
$result = $this->processUrls($urls);

return new JsonResponse($result);
} catch (Throwable $e) {
return new JsonResponse([
'error' => $e->getMessage(),
]);
}
}

protected function processUrls(array $urls): array
{
$result = [];
$urlsToFetch = [];

foreach ($urls as $url) {
if (!$this->service->isValidUrl($url)) {
$result[$url] = $this->service->getErrorResponse('datlechin-link-preview.forum.site_cannot_be_reached');
continue;
$processResult = $this->preProcessUrl($url);
if (isset($processResult['data'])) {
$result[$url] = $processResult['data'];
} else if (isset($processResult['fetch'])) {
$urlsToFetch[$url] = $processResult['fetch'];
} else {
$result[$url] = $processResult['error'];
}
}

$normalizedUrl = $this->service->normalizeUrl($url);
if (empty($urlsToFetch)) {
return $result;
}

if (!$this->service->isUrlAllowed($normalizedUrl)) {
$result[$url] = $this->service->getErrorResponse('datlechin-link-preview.forum.site_cannot_be_reached');
continue;
}
$fetchResults = $this->fetchUrls($urlsToFetch);

$cachedData = $this->service->getCachedData($normalizedUrl);
if ($cachedData) {
$result[$url] = $cachedData;
continue;
}
foreach ($urlsToFetch as $originalUrl => $normalizedUrl) {
$result[$originalUrl] = $fetchResults[$originalUrl] ?? [
'error' => 'Failed to fetch preview'
];
}

return $result;
}

$urlsToFetch[$url] = $normalizedUrl;
protected function preProcessUrl(string $url): array
{
if (!$this->service->isValidUrl($url)) {
return [
'error' => $this->service->getErrorResponse('datlechin-link-preview.forum.site_cannot_be_reached')
];
}

if (empty($urlsToFetch)) {
return new JsonResponse($result);
$normalizedUrl = $this->service->normalizeUrl($url);

if (!$this->service->isUrlAllowed($normalizedUrl)) {
return [
'error' => $this->service->getErrorResponse('datlechin-link-preview.forum.site_cannot_be_reached')
];
}

$cachedData = $this->service->getCachedData($normalizedUrl);
if ($cachedData) {
return ['data' => $cachedData];
}

return ['fetch' => $normalizedUrl];
}

protected function fetchUrls(array $urlsToFetch): array
{
$promises = [];
$results = [];

foreach ($urlsToFetch as $originalUrl) {
try {
$promises[$originalUrl] = $this->service->getClient()->getAsync($originalUrl);
} catch (Throwable $e) {
$results[$originalUrl] = [
'error' => 'Failed to create request: ' . $e->getMessage()
];
}
}

$promises = $this->preparePromises($urlsToFetch);
if (empty($promises)) {
return $results;
}

$responses = Utils::settle($promises)->wait();

foreach ($responses as $originalUrl => $response) {
foreach ($promises as $originalUrl => $promise) {
try {
if (!isset($responses[$originalUrl])) {
$result[$originalUrl] = [
'error' => 'No response received',
$response = $responses[$originalUrl] ?? null;

if (!$response || $response['state'] !== 'fulfilled') {
$results[$originalUrl] = [
'error' => $response['reason'] instanceof \Exception ?
$response['reason']->getMessage() :
'Failed to fetch preview'
];
continue;
}

if ($response['state'] === 'fulfilled') {
$html = $response['value']->getBody()->getContents();
$data = $this->service->parseHtml($html, $originalUrl);
$html = $response['value']->getBody()->getContents();
$data = $this->service->parseHtml($html, $originalUrl);

$this->service->cacheData($urlsToFetch[$originalUrl], $data);
$result[$originalUrl] = $data;
} else {
$result[$originalUrl] = [
'error' => $response['reason']->getMessage(),
];
}
$this->service->cacheData($urlsToFetch[$originalUrl], $data);
$results[$originalUrl] = $data;
} catch (Throwable $e) {
$result[$originalUrl] = [
'error' => $e->getMessage(),
$results[$originalUrl] = [
'error' => $e->getMessage()
];
}
}

return new JsonResponse($result);
}

protected function preparePromises(array $urlsToFetch): array
{
$promises = [];

foreach ($urlsToFetch as $originalUrl) {
$promises[$originalUrl] = $this->service->getClient()->getAsync($originalUrl);
}

return $promises;
return $results;
}
}

0 comments on commit 0a053c0

Please sign in to comment.