Created service to update geolite2 database file

This commit is contained in:
Alejandro Celaya
2018-11-11 21:08:23 +01:00
parent 06db082e3f
commit 3d7cf6992e
8 changed files with 302 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Common\IpGeolocation\GeoLite2;
use Fig\Http\Message\RequestMethodInterface as RequestMethod;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\RequestOptions;
use PharData;
use Shlinkio\Shlink\Common\Exception\RuntimeException;
use Symfony\Component\Filesystem\Exception as FilesystemException;
use Symfony\Component\Filesystem\Filesystem;
use Throwable;
use function sprintf;
class DbUpdater implements DbUpdaterInterface
{
private const DB_COMPRESSED_FILE = 'GeoLite2-City.tar.gz';
private const DB_DECOMPRESSED_FILE = 'GeoLite2-City.mmdb';
/**
* @var ClientInterface
*/
private $httpClient;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var GeoLite2Options
*/
private $options;
public function __construct(ClientInterface $httpClient, Filesystem $filesystem, GeoLite2Options $options)
{
$this->httpClient = $httpClient;
$this->filesystem = $filesystem;
$this->options = $options;
}
/**
* @throws RuntimeException
*/
public function downloadFreshCopy(): void
{
$tempDir = $this->options->getTempDir();
$compressedFile = sprintf('%s/%s', $tempDir, self::DB_COMPRESSED_FILE);
$this->downloadDbFile($compressedFile);
$tempFullPath = $this->extractDbFile($compressedFile, $tempDir);
$this->copyNewDbFile($tempFullPath);
$this->deleteTempFiles([$compressedFile, $tempFullPath]);
}
private function downloadDbFile(string $dest): void
{
try {
$this->httpClient->request(RequestMethod::METHOD_GET, $this->options->getDownloadFrom(), [
RequestOptions::SINK => $dest,
]);
} catch (Throwable | GuzzleException $e) {
throw new RuntimeException(
'An error occurred while trying to download a fresh copy of the GeoLite2 database',
0,
$e
);
}
}
private function extractDbFile(string $compressedFile, string $tempDir): string
{
try {
$phar = new PharData($compressedFile);
$internalPathToDb = sprintf('%s/%s', $phar->getBasename(), self::DB_DECOMPRESSED_FILE);
$phar->extractTo($tempDir, $internalPathToDb, true);
return sprintf('%s/%s', $tempDir, $internalPathToDb);
} catch (Throwable $e) {
throw new RuntimeException(
sprintf('An error occurred while trying to extract the GeoLite2 database from %s', $compressedFile),
0,
$e
);
}
}
private function copyNewDbFile(string $from): void
{
try {
$this->filesystem->copy($from, $this->options->getDbLocation(), true);
} catch (FilesystemException\FileNotFoundException | FilesystemException\IOException $e) {
throw new RuntimeException('An error occurred while trying to copy GeoLite2 db file to destination', 0, $e);
}
}
private function deleteTempFiles(array $files): void
{
try {
$this->filesystem->remove($files);
} catch (FilesystemException\IOException $e) {
// Ignore any error produced when trying to delete temp files
}
}
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Common\IpGeolocation\GeoLite2;
use Shlinkio\Shlink\Common\Exception\RuntimeException;
interface DbUpdaterInterface
{
/**
* @throws RuntimeException
*/
public function downloadFreshCopy(): void;
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Common\IpGeolocation\GeoLite2;
use Zend\Stdlib\AbstractOptions;
class GeoLite2Options extends AbstractOptions
{
private $dbLocation = '';
private $tempDir = '';
private $downloadFrom = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz';
public function getDbLocation(): string
{
return $this->dbLocation;
}
protected function setDbLocation(string $dbLocation): self
{
$this->dbLocation = $dbLocation;
return $this;
}
public function getTempDir(): string
{
return $this->tempDir;
}
protected function setTempDir(string $tempDir): self
{
$this->tempDir = $tempDir;
return $this;
}
public function getDownloadFrom(): string
{
return $this->downloadFrom;
}
protected function setDownloadFrom(string $downloadFrom): self
{
$this->downloadFrom = $downloadFrom;
return $this;
}
}