AbstractGate::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * Abstract gate
4
 * User: moyo
5
 * Date: 24/08/2017
6
 * Time: 4:56 PM
7
 */
8
9
namespace Carno\Consul\APIs;
10
11
use Carno\Consul\Results\Failed;
12
use Carno\Consul\Results\Success;
13
use Carno\Consul\Types\Agent;
14
use Carno\DNS\DNS;
15
use Carno\DNS\Result;
16
use Carno\HTTP\Client;
17
use Carno\HTTP\Contracts\Client as HTTP;
18
use Carno\HTTP\Options;
19
use Carno\HTTP\Standard\Request;
20
use Carno\HTTP\Standard\Response;
21
use Carno\HTTP\Standard\Streams\Body;
22
use Carno\HTTP\Standard\Uri;
23
use Carno\Promise\Promise;
24
use Carno\Promise\Promised;
25
26
abstract class AbstractGate
27
{
28
    // default to http
29
    private const SCHEME = 'http';
30
31
    // version 1
32
    private const VERSION = 'v1';
33
34
    /**
35
     * @var string
36
     */
37
    protected $method = 'GET';
38
39
    /**
40
     * @var string
41
     */
42
    protected $uri = '/';
43
44
    /**
45
     * @var array
46
     */
47
    protected $query = [];
48
49
    /**
50
     * @var int
51
     */
52
    protected $timeout = 5000;
53
54
    /**
55
     * provided agent
56
     * @var Agent
57
     */
58
    private $agent = null;
59
60
    /**
61
     * assigned agent
62
     * @var Agent
63
     */
64
    private $assigned = null;
65
66
    /**
67
     * @var Client[]
68
     */
69
    private $http = [];
70
71
    /**
72
     * @var string
73
     */
74
    private $payloadType = 'application/json';
75
76
    /**
77
     * @var string
78
     */
79
    private $payloadData = '{}';
80
81
    /**
82
     * AbstractAPI constructor.
83
     * @param Agent $agent
84
     */
85
    final public function __construct(Agent $agent)
86
    {
87
        $this->agent = $agent;
88
    }
89
90
    /**
91
     * @return Agent
92
     */
93
    final protected function agent() : Agent
94
    {
95
        return $this->agent;
96
    }
97
98
    /**
99
     * @return Agent
100
     */
101
    final protected function assigned() : Agent
102
    {
103
        return $this->assigned ?? $this->agent;
104
    }
105
106
    /**
107
     * @return Promised
108
     */
109
    final private function assigning() : Promised
110
    {
111
        if ($this->assigned) {
112
            return Promise::resolved($this->assigned);
113
        }
114
115
        DNS::resolve($this->agent->host())->then(function (Result $result) {
116
            return $this->assigned = new Agent($result->random(), $this->agent->port());
117
        })->sync($resolving = Promise::deferred());
118
119
        return $resolving;
120
    }
121
122
    /**
123
     * @param Agent $agent
124
     * @return HTTP
125
     */
126
    final private function http(Agent $agent) : HTTP
127
    {
128
        return
129
            $this->http[$agent->host()] ??
130
            $this->http[$agent->host()] = new Client((new Options)->setTimeouts($this->timeout), $agent)
131
        ;
132
    }
133
134
    /**
135
     * @param string $key
136
     * @param string $replaced
137
     */
138
    final protected function setVars(string $key, string $replaced) : void
139
    {
140
        $this->uri = str_replace(sprintf(':%s', $key), $replaced, $this->uri);
141
    }
142
143
    /**
144
     * @param string $key
145
     * @param $val
146
     */
147
    final protected function setQuery(string $key, $val) : void
148
    {
149
        is_scalar($val) && $this->query[$key] = $val;
150
    }
151
152
    /**
153
     * @param array $data
154
     */
155
    final protected function setPayload(array $data) : void
156
    {
157
        $this->payloadData = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
158
    }
159
160
    /**
161
     * @return string
162
     */
163
    final protected function getPayload() : string
164
    {
165
        return $this->payloadData;
166
    }
167
168
    /**
169
     * @param string $raw
170
     * @return array
171
     */
172
    final protected function decodeResponse(string $raw) : array
173
    {
174
        return json_decode($raw, true);
175
    }
176
177
    /**
178
     * @param Promised $canceller
179
     * @return Promised|Response
180
     */
181
    final protected function perform(Promised $canceller = null) : Promised
182
    {
183
        $this->assigning()->sync($resolved = Promise::deferred());
184
185
        return $resolved->then(function (Agent $agent) use ($canceller) {
186
            $request = new Request(
187
                $this->method,
188
                new Uri(
189
                    self::SCHEME,
190
                    $agent->host(),
191
                    $agent->port(),
192
                    sprintf("/%s", self::VERSION) . $this->uri,
193
                    $this->query
194
                ),
195
                [
196
                    'Content-Type' => $this->payloadType,
197
                ],
198
                new Body($this->getPayload())
199
            );
200
201
            return $this->http($agent)->perform($request, $canceller);
202
        });
203
    }
204
205
    /**
206
     * @return Promised|Success|Failed
207
     */
208
    final protected function simpleHCodeResult()
209
    {
210
        return $this->perform()->then(static function (Response $response) {
211
            return
212
                $response->getStatusCode() === 200
213
                    ? new Success
214
                    : new Failed((string)$response->getBody())
215
                ;
216
        });
217
    }
218
219
    /**
220
     * @return mixed
221
     */
222
    abstract public function result();
223
}
224