MarketplaceService::loadRemote()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 7
c 1
b 0
f 1
dl 0
loc 13
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Gameap\Services\Modules;
4
5
use Gameap\Exceptions\GameapException;
6
use Gameap\Exceptions\InvalidArgumentValueException;
7
use Gameap\Exceptions\NotFoundException;
8
use Gameap\Exceptions\Services\ResponseException;
9
use GuzzleHttp\Client;
10
use GuzzleHttp\Exception\GuzzleException;
11
use Illuminate\Support\Facades\Config;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
15
class MarketplaceService
16
{
17
    public const CONFIG_REPOSITORIES_NAME = 'app.modules_repositories';
18
19
    /** @var Client */
20
    private $client;
21
22
    public function __construct(Client $client)
23
    {
24
        $this->client = $client;
25
    }
26
27
    public function getList(): iterable
28
    {
29
        $repositories = Config::get(self::CONFIG_REPOSITORIES_NAME);
30
31
        $modules = [];
32
        foreach ($repositories as $repository) {
33
            $modules[] = $this->loadRemote($repository . '/index.json');
34
        }
35
36
        return array_merge(...$modules);
37
    }
38
39
    public function findModule(string $moduleID): ?array
40
    {
41
        $repositories = Config::get(self::CONFIG_REPOSITORIES_NAME);
42
43
        foreach ($repositories as $repository) {
44
            $modules = $this->loadRemote($repository . '/index.json');
45
46
            if (array_key_exists($moduleID, $modules)) {
47
                return $this->getModule($repository, $moduleID);
48
            }
49
        }
50
51
        return null;
52
    }
53
54
    public function getModule(string $repository, string $moduleID): array
55
    {
56
        return $this->loadRemote($repository . '/modules/' . $moduleID . '.json');
57
    }
58
59
    public function downloadModule(string $moduleID, string $version): string
60
    {
61
        $module = $this->findModule($moduleID);
62
63
        if ($module === null) {
64
            throw new NotFoundException('Module not found');
65
        }
66
67
        if (!array_key_exists($version, $module['versions'])) {
68
            throw new InvalidArgumentValueException('Invalid module version');
69
        }
70
71
        $mirrors = $module['versions'][$version]['mirrors'];
72
73
        $filePath = tempnam(sys_get_temp_dir(), $moduleID);
74
        foreach ($mirrors as $mirror) {
75
            $result = $this->client->request(Request::METHOD_GET, $mirror, ['sink' => $filePath]);
76
77
            if ($result->getStatusCode() === Response::HTTP_OK) {
78
                return $filePath;
79
            }
80
        }
81
82
        throw new GameapException('Unable to download module');
83
    }
84
85
    /**
86
     * @param string $uri
87
     * @return array
88
     * @throws ResponseException
89
     * @throws GuzzleException
90
     * @throws \JsonException
91
     */
92
    private function loadRemote(string $uri): array
93
    {
94
        $response = $this->client->request(
95
            Request::METHOD_GET,
96
            $uri,
97
            ['headers' => ['Accept: application/json']]
98
        );
99
100
        if ($response->getStatusCode() !== Response::HTTP_OK) {
101
            throw new ResponseException('Unexpected HTTP status code: ' . $response->getStatusCode());
102
        }
103
104
        return json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
105
    }
106
}
107