Passed
Pull Request — master (#258)
by Alejandro
03:13
created

DbUpdater   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Test Coverage

Coverage 97.22%

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 85
ccs 35
cts 36
cp 0.9722
rs 10
c 0
b 0
f 0
wmc 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A extractDbFile() 0 13 2
A downloadDbFile() 0 11 2
A deleteTempFiles() 0 5 2
A copyNewDbFile() 0 6 2
A downloadFreshCopy() 0 9 1
A __construct() 0 5 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\Common\IpGeolocation\GeoLite2;
5
6
use Fig\Http\Message\RequestMethodInterface as RequestMethod;
7
use GuzzleHttp\ClientInterface;
8
use GuzzleHttp\Exception\GuzzleException;
9
use GuzzleHttp\RequestOptions;
10
use PharData;
11
use Shlinkio\Shlink\Common\Exception\RuntimeException;
12
use Symfony\Component\Filesystem\Exception as FilesystemException;
13
use Symfony\Component\Filesystem\Filesystem;
14
use Throwable;
15
use function sprintf;
16
17
class DbUpdater implements DbUpdaterInterface
18
{
19
    private const DB_COMPRESSED_FILE = 'GeoLite2-City.tar.gz';
20
    private const DB_DECOMPRESSED_FILE = 'GeoLite2-City.mmdb';
21
22
    /**
23
     * @var ClientInterface
24
     */
25
    private $httpClient;
26
    /**
27
     * @var Filesystem
28
     */
29
    private $filesystem;
30
    /**
31
     * @var GeoLite2Options
32
     */
33
    private $options;
34
35 5
    public function __construct(ClientInterface $httpClient, Filesystem $filesystem, GeoLite2Options $options)
36
    {
37 5
        $this->httpClient = $httpClient;
38 5
        $this->filesystem = $filesystem;
39 5
        $this->options = $options;
40
    }
41
42
    /**
43
     * @throws RuntimeException
44
     */
45 5
    public function downloadFreshCopy(): void
46
    {
47 5
        $tempDir = $this->options->getTempDir();
48 5
        $compressedFile = sprintf('%s/%s', $tempDir, self::DB_COMPRESSED_FILE);
49
50 5
        $this->downloadDbFile($compressedFile);
51 4
        $tempFullPath = $this->extractDbFile($compressedFile, $tempDir);
52 3
        $this->copyNewDbFile($tempFullPath);
53 1
        $this->deleteTempFiles([$compressedFile, $tempFullPath]);
54
    }
55
56 5
    private function downloadDbFile(string $dest): void
57
    {
58
        try {
59 5
            $this->httpClient->request(RequestMethod::METHOD_GET, $this->options->getDownloadFrom(), [
60 5
                RequestOptions::SINK => $dest,
61
            ]);
62 1
        } catch (Throwable | GuzzleException $e) {
63 1
            throw new RuntimeException(
64 1
                'An error occurred while trying to download a fresh copy of the GeoLite2 database',
65 1
                0,
66 1
                $e
67
            );
68
        }
69
    }
70
71 4
    private function extractDbFile(string $compressedFile, string $tempDir): string
72
    {
73
        try {
74 4
            $phar = new PharData($compressedFile);
75 3
            $internalPathToDb = sprintf('%s/%s', $phar->getBasename(), self::DB_DECOMPRESSED_FILE);
76 3
            $phar->extractTo($tempDir, $internalPathToDb, true);
77
78 3
            return sprintf('%s/%s', $tempDir, $internalPathToDb);
79 1
        } catch (Throwable $e) {
80 1
            throw new RuntimeException(
81 1
                sprintf('An error occurred while trying to extract the GeoLite2 database from %s', $compressedFile),
82 1
                0,
83 1
                $e
84
            );
85
        }
86
    }
87
88 3
    private function copyNewDbFile(string $from): void
89
    {
90
        try {
91 3
            $this->filesystem->copy($from, $this->options->getDbLocation(), true);
92 2
        } catch (FilesystemException\FileNotFoundException | FilesystemException\IOException $e) {
93 2
            throw new RuntimeException('An error occurred while trying to copy GeoLite2 db file to destination', 0, $e);
94
        }
95
    }
96
97 1
    private function deleteTempFiles(array $files): void
98
    {
99
        try {
100 1
            $this->filesystem->remove($files);
101
        } catch (FilesystemException\IOException $e) {
102
            // Ignore any error produced when trying to delete temp files
103
        }
104
    }
105
}
106