mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-14 12:11:19 +03:00
Allowed to delay GeoLite2 db download on docker images
This commit is contained in:
parent
ef01754ad5
commit
6f17f70137
8 changed files with 95 additions and 23 deletions
|
@ -50,7 +50,7 @@
|
|||
"shlinkio/shlink-event-dispatcher": "dev-main#48c0137 as 2.6",
|
||||
"shlinkio/shlink-importer": "^4.0",
|
||||
"shlinkio/shlink-installer": "dev-develop#a01bca9 as 8.2",
|
||||
"shlinkio/shlink-ip-geolocation": "^3.0",
|
||||
"shlinkio/shlink-ip-geolocation": "^3.1",
|
||||
"spiral/roadrunner": "^2.11",
|
||||
"spiral/roadrunner-jobs": "^2.3",
|
||||
"symfony/console": "^6.1",
|
||||
|
|
|
@ -18,14 +18,14 @@ php bin/doctrine orm:generate-proxies -n ${flags}
|
|||
echo "Clearing entities cache..."
|
||||
php bin/doctrine orm:clear-cache:metadata -n ${flags}
|
||||
|
||||
# Try to download GeoLite2 db file only if the license key env var was defined
|
||||
if [ ! -z "${GEOLITE_LICENSE_KEY}" ]; then
|
||||
# Try to download GeoLite2 db file only if the license key env var was defined and skipping was not explicitly set
|
||||
if [ ! -z "${GEOLITE_LICENSE_KEY}" ] && [ "${SKIP_INITIAL_GEOLITE_DOWNLOAD}" != "true" ]; then
|
||||
echo "Downloading GeoLite2 db file..."
|
||||
php bin/cli visit:download-db -n ${flags}
|
||||
fi
|
||||
|
||||
# Periodically run visit:locate every hour, if ENABLE_PERIODIC_VISIT_LOCATE=true was provided
|
||||
if [ $ENABLE_PERIODIC_VISIT_LOCATE ]; then
|
||||
if [ "${ENABLE_PERIODIC_VISIT_LOCATE}" = "true" ]; then
|
||||
echo "Configuring periodic visit location..."
|
||||
echo "0 * * * * php /etc/shlink/bin/cli visit:locate -q" > /etc/crontabs/root
|
||||
/usr/sbin/crond &
|
||||
|
|
|
@ -19,6 +19,7 @@ use Shlinkio\Shlink\Core\Tag\TagService;
|
|||
use Shlinkio\Shlink\Core\Visit;
|
||||
use Shlinkio\Shlink\Installer\Factory\ProcessHelperFactory;
|
||||
use Shlinkio\Shlink\IpGeolocation\GeoLite2\DbUpdater;
|
||||
use Shlinkio\Shlink\IpGeolocation\GeoLite2\GeoLite2Options;
|
||||
use Shlinkio\Shlink\IpGeolocation\Resolver\IpLocationResolverInterface;
|
||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||
use Symfony\Component\Console as SymfonyCli;
|
||||
|
@ -75,6 +76,7 @@ return [
|
|||
Reader::class,
|
||||
LOCAL_LOCK_FACTORY,
|
||||
TrackingOptions::class,
|
||||
GeoLite2Options::class,
|
||||
],
|
||||
Util\ProcessRunner::class => [SymfonyCli\Helper\ProcessHelper::class],
|
||||
ApiKey\RoleResolver::class => [DomainService::class, 'config.url_shortener.domain.hostname'],
|
||||
|
|
|
@ -34,8 +34,8 @@ class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocat
|
|||
private SymfonyStyle $io;
|
||||
|
||||
public function __construct(
|
||||
private VisitLocatorInterface $visitLocator,
|
||||
private IpLocationResolverInterface $ipLocationResolver,
|
||||
private readonly VisitLocatorInterface $visitLocator,
|
||||
private readonly IpLocationResolverInterface $ipLocationResolver,
|
||||
LockFactory $locker,
|
||||
) {
|
||||
parent::__construct($locker);
|
||||
|
|
|
@ -9,7 +9,9 @@ use GeoIp2\Database\Reader;
|
|||
use MaxMind\Db\Reader\Metadata;
|
||||
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
||||
use Shlinkio\Shlink\Core\Options\TrackingOptions;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\RuntimeException;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\DbUpdateException;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\MissingLicenseException;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\WrongIpException;
|
||||
use Shlinkio\Shlink\IpGeolocation\GeoLite2\DbUpdaterInterface;
|
||||
use Symfony\Component\Lock\LockFactory;
|
||||
|
||||
|
@ -20,10 +22,10 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
|
|||
private const LOCK_NAME = 'geolocation-db-update';
|
||||
|
||||
public function __construct(
|
||||
private DbUpdaterInterface $dbUpdater,
|
||||
private Reader $geoLiteDbReader,
|
||||
private LockFactory $locker,
|
||||
private TrackingOptions $trackingOptions,
|
||||
private readonly DbUpdaterInterface $dbUpdater,
|
||||
private readonly Reader $geoLiteDbReader,
|
||||
private readonly LockFactory $locker,
|
||||
private readonly TrackingOptions $trackingOptions,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -52,14 +54,12 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
|
|||
private function downloadIfNeeded(?callable $beforeDownload, ?callable $handleProgress): GeolocationResult
|
||||
{
|
||||
if (! $this->dbUpdater->databaseFileExists()) {
|
||||
$this->downloadNewDb(false, $beforeDownload, $handleProgress);
|
||||
return GeolocationResult::DB_CREATED;
|
||||
return $this->downloadNewDb(false, $beforeDownload, $handleProgress);
|
||||
}
|
||||
|
||||
$meta = $this->geoLiteDbReader->metadata();
|
||||
if ($this->buildIsTooOld($meta)) {
|
||||
$this->downloadNewDb(true, $beforeDownload, $handleProgress);
|
||||
return GeolocationResult::DB_UPDATED;
|
||||
return $this->downloadNewDb(true, $beforeDownload, $handleProgress);
|
||||
}
|
||||
|
||||
return GeolocationResult::DB_IS_UP_TO_DATE;
|
||||
|
@ -95,15 +95,22 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
|
|||
/**
|
||||
* @throws GeolocationDbUpdateFailedException
|
||||
*/
|
||||
private function downloadNewDb(bool $olderDbExists, ?callable $beforeDownload, ?callable $handleProgress): void
|
||||
{
|
||||
private function downloadNewDb(
|
||||
bool $olderDbExists,
|
||||
?callable $beforeDownload,
|
||||
?callable $handleProgress,
|
||||
): GeolocationResult {
|
||||
if ($beforeDownload !== null) {
|
||||
$beforeDownload($olderDbExists);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->dbUpdater->downloadFreshCopy($this->wrapHandleProgressCallback($handleProgress, $olderDbExists));
|
||||
} catch (RuntimeException $e) {
|
||||
return $olderDbExists ? GeolocationResult::DB_UPDATED : GeolocationResult::DB_CREATED;
|
||||
} catch (MissingLicenseException) {
|
||||
// If there's no license key, just ignore the error
|
||||
return GeolocationResult::CHECK_SKIPPED;
|
||||
} catch (DbUpdateException | WrongIpException $e) {
|
||||
throw $olderDbExists
|
||||
? GeolocationDbUpdateFailedException::withOlderDb($e)
|
||||
: GeolocationDbUpdateFailedException::withoutOlderDb($e);
|
||||
|
@ -116,6 +123,6 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
|
|||
return null;
|
||||
}
|
||||
|
||||
return fn (int $total, int $downloaded) => $handleProgress($total, $downloaded, $olderDbExists);
|
||||
return static fn (int $total, int $downloaded) => $handleProgress($total, $downloaded, $olderDbExists);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
|||
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdater;
|
||||
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
|
||||
use Shlinkio\Shlink\Core\Options\TrackingOptions;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\RuntimeException;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\DbUpdateException;
|
||||
use Shlinkio\Shlink\IpGeolocation\GeoLite2\DbUpdaterInterface;
|
||||
use Symfony\Component\Lock;
|
||||
use Throwable;
|
||||
|
@ -48,7 +48,7 @@ class GeolocationDbUpdaterTest extends TestCase
|
|||
public function exceptionIsThrownWhenOlderDbDoesNotExistAndDownloadFails(): void
|
||||
{
|
||||
$mustBeUpdated = fn () => self::assertTrue(true);
|
||||
$prev = new RuntimeException('');
|
||||
$prev = new DbUpdateException('');
|
||||
|
||||
$fileExists = $this->dbUpdater->databaseFileExists()->willReturn(false);
|
||||
$getMeta = $this->geoLiteDbReader->metadata();
|
||||
|
@ -81,7 +81,7 @@ class GeolocationDbUpdaterTest extends TestCase
|
|||
$getMeta = $this->geoLiteDbReader->metadata()->willReturn($this->buildMetaWithBuildEpoch(
|
||||
Chronos::now()->subDays($days)->getTimestamp(),
|
||||
));
|
||||
$prev = new RuntimeException('');
|
||||
$prev = new DbUpdateException('');
|
||||
$download = $this->dbUpdater->downloadFreshCopy(null)->willThrow($prev);
|
||||
|
||||
try {
|
||||
|
|
|
@ -10,6 +10,7 @@ use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdater;
|
|||
use Shlinkio\Shlink\Common\Cache\RedisPublishingHelper;
|
||||
use Shlinkio\Shlink\Common\Mercure\MercureHubPublishingHelper;
|
||||
use Shlinkio\Shlink\Common\RabbitMq\RabbitMqPublishingHelper;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitLocator;
|
||||
use Shlinkio\Shlink\IpGeolocation\GeoLite2\DbUpdater;
|
||||
use Shlinkio\Shlink\IpGeolocation\Resolver\IpLocationResolverInterface;
|
||||
|
||||
|
@ -21,7 +22,7 @@ return [
|
|||
EventDispatcher\LocateVisit::class,
|
||||
],
|
||||
EventDispatcher\Event\GeoLiteDbCreated::class => [
|
||||
// EventDispatcher\LocateUnloctedVisits::class,
|
||||
EventDispatcher\LocateUnlocatedVisits::class,
|
||||
],
|
||||
],
|
||||
'async' => [
|
||||
|
@ -43,6 +44,7 @@ return [
|
|||
'dependencies' => [
|
||||
'factories' => [
|
||||
EventDispatcher\LocateVisit::class => ConfigAbstractFactory::class,
|
||||
EventDispatcher\LocateUnlocatedVisits::class => ConfigAbstractFactory::class,
|
||||
EventDispatcher\NotifyVisitToWebHooks::class => ConfigAbstractFactory::class,
|
||||
EventDispatcher\Mercure\NotifyVisitToMercure::class => ConfigAbstractFactory::class,
|
||||
EventDispatcher\Mercure\NotifyNewShortUrlToMercure::class => ConfigAbstractFactory::class,
|
||||
|
@ -72,6 +74,9 @@ return [
|
|||
EventDispatcher\RedisPubSub\NotifyNewShortUrlToRedis::class => [
|
||||
EventDispatcher\CloseDbConnectionEventListenerDelegator::class,
|
||||
],
|
||||
EventDispatcher\LocateUnlocatedVisits::class => [
|
||||
EventDispatcher\CloseDbConnectionEventListenerDelegator::class,
|
||||
],
|
||||
EventDispatcher\NotifyVisitToWebHooks::class => [
|
||||
EventDispatcher\CloseDbConnectionEventListenerDelegator::class,
|
||||
],
|
||||
|
@ -86,6 +91,7 @@ return [
|
|||
DbUpdater::class,
|
||||
EventDispatcherInterface::class,
|
||||
],
|
||||
EventDispatcher\LocateUnlocatedVisits::class => [VisitLocator::class, IpLocationResolverInterface::class],
|
||||
EventDispatcher\NotifyVisitToWebHooks::class => [
|
||||
'httpClient',
|
||||
'em',
|
||||
|
|
57
module/Core/src/EventDispatcher/LocateUnlocatedVisits.php
Normal file
57
module/Core/src/EventDispatcher/LocateUnlocatedVisits.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\EventDispatcher;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\IpAddress;
|
||||
use Shlinkio\Shlink\Core\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Entity\VisitLocation;
|
||||
use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated;
|
||||
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitGeolocationHelperInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitLocatorInterface;
|
||||
use Shlinkio\Shlink\IpGeolocation\Exception\WrongIpException;
|
||||
use Shlinkio\Shlink\IpGeolocation\Model\Location;
|
||||
use Shlinkio\Shlink\IpGeolocation\Resolver\IpLocationResolverInterface;
|
||||
|
||||
class LocateUnlocatedVisits implements VisitGeolocationHelperInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly VisitLocatorInterface $locator,
|
||||
private readonly IpLocationResolverInterface $ipLocationResolver,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(GeoLiteDbCreated $event): void
|
||||
{
|
||||
$this->locator->locateUnlocatedVisits($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IpCannotBeLocatedException
|
||||
*/
|
||||
public function geolocateVisit(Visit $visit): Location
|
||||
{
|
||||
// TODO This method duplicates code from LocateVisitsCommand. Move to a common place.
|
||||
if (! $visit->hasRemoteAddr()) {
|
||||
throw IpCannotBeLocatedException::forEmptyAddress();
|
||||
}
|
||||
|
||||
$ipAddr = $visit->getRemoteAddr() ?? '';
|
||||
if ($ipAddr === IpAddress::LOCALHOST) {
|
||||
throw IpCannotBeLocatedException::forLocalhost();
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->ipLocationResolver->resolveIpLocation($ipAddr);
|
||||
} catch (WrongIpException $e) {
|
||||
throw IpCannotBeLocatedException::forError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function onVisitLocated(VisitLocation $visitLocation, Visit $visit): void
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue