Failed Conditions
Pull Request — master (#12)
by thomas
03:33
created

HttpClient::acquire()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Trezor\Bridge\Http;
6
7
use BitWasp\Trezor\Bridge\Codec\CallMessage;
8
use BitWasp\Trezor\Bridge\Message\Device;
9
use BitWasp\Trezor\Device\Message;
10
use BitWasp\Trezor\Device\MessageBase;
11
use BitWasp\TrezorProto\MessageType;
12
use GuzzleHttp\Client as GuzzleClient;
13
use GuzzleHttp\Psr7\Response;
14
use Psr\Http\Message\ResponseInterface;
15
16
class HttpClient
17
{
18
    /**
19
     * @var GuzzleClient
20
     */
21
    private $client;
22
23
    /**
24
     * Base headers to use when the request is
25
     * simple JSON
26
     *
27
     * @var array
28
     */
29
    private $jsonHeaders = [
30
        'Accept' => 'application/json',
31
    ];
32
33
    /**
34
     * Encoder for serializing the call payload & response
35
     *
36
     * @var CallMessage\HexCodec
37
     */
38
    private $callCodec;
39
40 53
    public function __construct(GuzzleClient $client, CallMessage\HexCodec $codec = null)
41
    {
42 53
        $this->client = $client;
43 53
        $this->callCodec = $codec ?: new CallMessage\HexCodec();
44 53
    }
45
46 53
    public static function forUri(string $uri, array $options = []): self
47
    {
48 53
        return new self(new GuzzleClient(
49 53
            array_merge(
50 53
                $options,
51
                [
52 53
                'base_uri' => $uri,
53
                'headers' => [
54
                    'Origin' => 'http://localhost:5000',
55
                ]
56
                ]
57
            )
58
        ));
59
    }
60
61 8
    public function bridgeVersion(): ResponseInterface
62
    {
63 8
        return $this->client->post('/', [
64 8
            'headers' => $this->jsonHeaders,
65
        ]);
66
    }
67
68 3
    public function listDevices(): ResponseInterface
69
    {
70 3
        return $this->client->post('/enumerate', [
71 3
            'headers' => $this->jsonHeaders,
72
        ]);
73
    }
74
75 2
    public function listen(Device ...$devices): ResponseInterface
76
    {
77 2
        return $this->client->post('/listen', [
78 2
            'headers' => $this->jsonHeaders,
79 2
            'json' => array_map(function (Device $device): \stdClass {
80 2
                return $device->getObject();
81 2
            }, $devices),
82
        ]);
83
    }
84
85 5
    public function acquire(Device $device): ResponseInterface
86
    {
87 5
        if ($device->getSession()) {
88 1
            $prevSession = $device->getSession();
89
        } else {
90 4
            $prevSession = "null";
91
        }
92
93 5
        return $this->client->post("/acquire/{$device->getPath()}/{$prevSession}", [
94 5
            'headers' => $this->jsonHeaders,
95
        ]);
96
    }
97
98 4
    public function release(string $sessionId): ResponseInterface
99
    {
100 4
        return $this->client->post("/release/{$sessionId}", [
101 4
            'headers' => $this->jsonHeaders,
102
        ]);
103
    }
104
105
    public function post(string $sessionId, MessageBase $message)
106
    {
107
        $responsePromise = $this->postAsync($sessionId, $message);
108
        return $responsePromise->wait(true);
109
    }
110
111 2
    public function call(string $sessionId, MessageBase $message): Message
112
    {
113 2
        $responsePromise = $this->callAsync($sessionId, $message);
114 2
        return $responsePromise->wait(true);
115
    }
116
117
    public function postAsync(string $sessionId, MessageBase $message)
118
    {
119
        static $prefixLen;
120
        if (null === $prefixLen) {
121
            $prefixLen = strlen("MessageType_");
122
        }
123
124
        return $this->client->postAsync("/post/{$sessionId}", [
125
            'body' => $this->callCodec->encode($message->getType(), $message->getProto()),
126
        ]);
127
    }
128
129 30
    public function callAsync(string $sessionId, MessageBase $message)
130
    {
131 30
        static $prefixLen;
132 30
        if (null === $prefixLen) {
133 1
            $prefixLen = strlen("MessageType_");
134
        }
135
136 30
        return $this->client->postAsync("/call/{$sessionId}", [
137 30
            'body' => $this->callCodec->encode($message->getType(), $message->getProto()),
138
        ])
139 30
            ->then(function (Response $response) use ($prefixLen): Message {
140 30
                list ($type, $result) = $this->callCodec->parsePayload($response->getBody());
141
142 30
                $messageType = MessageType::valueOf($type);
143 30
                $protoType = substr($messageType->name(), $prefixLen);
144 30
                $reader = ["\\BitWasp\\TrezorProto\\{$protoType}", 'fromStream'];
145 30
                assert(class_exists($reader[0]));
146
147 30
                $protobuf = call_user_func($reader, $result);
148 30
                return new Message($messageType, $protobuf);
149 30
            });
150
    }
151
}
152