Completed
Pull Request — master (#12)
by thomas
29:47 queued 14:48
created

HttpClient::postAsync()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
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 53
    private $callCodec;
39
40 53
    public function __construct(GuzzleClient $client, CallMessage\HexCodec $codec = null)
41 53
    {
42 53
        $this->client = $client;
43
        $this->callCodec = $codec ?: new CallMessage\HexCodec();
44 53
    }
45
46 53
    public static function forUri(string $uri, array $options = []): self
47 53
    {
48 53
        return new self(new GuzzleClient(
49
            array_merge(
50 53
                $options,
51
                [
52
                'base_uri' => $uri,
53
                'headers' => [
54
                    'Origin' => 'http://localhost:5000',
55
                ]
56
                ]
57
            )
58
        ));
59 8
    }
60
61 8
    public function bridgeVersion(): ResponseInterface
62 8
    {
63
        return $this->client->post('/', [
64
            'headers' => $this->jsonHeaders,
65
        ]);
66 3
    }
67
68 3
    public function listDevices(): ResponseInterface
69 3
    {
70
        return $this->client->post('/enumerate', [
71
            'headers' => $this->jsonHeaders,
72
        ]);
73 2
    }
74
75 2
    public function listen(Device ...$devices): ResponseInterface
76 2
    {
77 2
        return $this->client->post('/listen', [
78 2
            'headers' => $this->jsonHeaders,
79 2
            'json' => array_map(function (Device $device): \stdClass {
80
                return $device->getObject();
81
            }, $devices),
82
        ]);
83 5
    }
84
85 5
    public function acquire(Device $device): ResponseInterface
86 1
    {
87
        if ($device->getSession()) {
88 4
            $prevSession = $device->getSession();
89
        } else {
90
            $prevSession = "null";
91 5
        }
92 5
93
        return $this->client->post("/acquire/{$device->getPath()}/{$prevSession}", [
94
            'headers' => $this->jsonHeaders,
95
        ]);
96 4
    }
97
98 4
    public function release(string $sessionId): ResponseInterface
99 4
    {
100
        return $this->client->post("/release/{$sessionId}", [
101
            'headers' => $this->jsonHeaders,
102
        ]);
103 30
    }
104
105 30
    public function post(string $sessionId, MessageBase $message)
106 30
    {
107 1
        $responsePromise = $this->postAsync($sessionId, $message);
108
        return $responsePromise->wait(true);
109
    }
110 30
111 30
    public function call(string $sessionId, MessageBase $message): Message
112
    {
113
        $responsePromise = $this->callAsync($sessionId, $message);
114 30
        return $responsePromise->wait(true);
115
    }
116 30
117 30
    public function postAsync(string $sessionId, MessageBase $message)
118 30
    {
119 30
        static $prefixLen;
120
        if (null === $prefixLen) {
121 30
            $prefixLen = strlen("MessageType_");
122 30
        }
123
124
        return $this->client->postAsync("/post/{$sessionId}", [
125
            'body' => $this->callCodec->encode($message->getType(), $message->getProto()),
126
        ]);
127
    }
128
129
    public function callAsync(string $sessionId, MessageBase $message)
130
    {
131
        static $prefixLen;
132
        if (null === $prefixLen) {
133
            $prefixLen = strlen("MessageType_");
134
        }
135
136
        return $this->client->postAsync("/call/{$sessionId}", [
137
            'body' => $this->callCodec->encode($message->getType(), $message->getProto()),
138
        ])
139
            ->then(function (Response $response) use ($prefixLen): Message {
140
                list ($type, $result) = $this->callCodec->parsePayload($response->getBody());
141
142
                $messageType = MessageType::valueOf($type);
143
                $protoType = substr($messageType->name(), $prefixLen);
144
                $reader = ["\\BitWasp\\TrezorProto\\{$protoType}", 'fromStream'];
145
                assert(class_exists($reader[0]));
146
147
                $protobuf = call_user_func($reader, $result);
148
                return new Message($messageType, $protobuf);
149
            });
150
    }
151
}
152