Skip to content
This repository was archived by the owner on May 4, 2024. It is now read-only.

Commit c156ac1

Browse files
authored
Merge pull request #6 from lookyman/async
Rewritten for asynchronous requests and promises
2 parents 80c6461 + 44d545d commit c156ac1

File tree

8 files changed

+163
-100
lines changed

8 files changed

+163
-100
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@ use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
2424
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
2525

2626
$api = new Api(
27-
new Client(), // Client must implement Http\Client\HttpClient
27+
new Client(), // Client must implement Http\Client\HttpAsyncClient
2828
new RequestFactory(), // RequestFactory must implement Interop\Http\Factory\RequestFactoryInterface
2929
'https://chronicle.uri',
3030
new SigningPublicKey(Base64UrlSafe::decode('chronicle public key')) // optional, omit if you don't care about validating API responses
3131
);
32-
$api->lastHash();
32+
var_dump($api->lastHash()->wait());
3333

3434
// you must authenticate first before you can publish a message
3535
$api->authenticate(
3636
new SigningSecretKey(Base64UrlSafe::decode('your secret key')),
3737
'your client id'
3838
);
39-
$api->publish('hello world');
39+
var_dump($api->publish('hello world')->wait());
4040
```
4141

4242
For implementations of client and request factory, you can use for example [Guzzle 6 HTTP Adapter](https://github.com/php-http/guzzle6-adapter) and [HTTP Factory for Guzzle](https://github.com/http-interop/http-factory-guzzle) respectively.
43+
44+
All endpoints return `Http\Promise\Promise`, so you can either just `->wait()` for the response, or handle it asynchronously with `->then()`. Responses are just plain arrays, look up the structure in the Chronicle's documentation.

src/AbstractApi.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected function verifyAndReturnResponse(ResponseInterface $response): array
3939
if ($this->chroniclePublicKey !== \null) {
4040
$headers = $response->getHeader(Sapient::HEADER_SIGNATURE_NAME);
4141
if (\count($headers) === 0) {
42-
throw new HeaderMissingException(\sprintf('No signed response header (%s) found.', Sapient::HEADER_SIGNATURE_NAME));
42+
throw new HeaderMissingException(\sprintf('No signed response header (%s) found', Sapient::HEADER_SIGNATURE_NAME));
4343
}
4444
foreach ($headers as $header) {
4545
if (\ParagonIE_Sodium_Compat::crypto_sign_verify_detached(
@@ -52,10 +52,10 @@ protected function verifyAndReturnResponse(ResponseInterface $response): array
5252
}
5353
}
5454
}
55-
if ($verified) {
56-
return \json_decode($body, \true);
55+
if (!$verified) {
56+
throw new InvalidMessageException('No valid signature given for this HTTP response');
5757
}
58-
throw new InvalidMessageException('No valid signature given for this HTTP response');
58+
return \json_decode($body, \true);
5959
}
6060

6161
}

src/Api.php

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
namespace Lookyman\Chronicle;
66

7-
use Http\Client\HttpClient;
7+
use Http\Client\HttpAsyncClient;
8+
use Http\Promise\Promise;
89
use Interop\Http\Factory\RequestFactoryInterface;
910
use ParagonIE\ConstantTime\Base64UrlSafe;
1011
use ParagonIE\Sapient\Adapter\Generic\Stream;
@@ -13,14 +14,15 @@
1314
use ParagonIE\Sapient\Sapient;
1415
use Psr\Http\Message\MessageInterface;
1516
use Psr\Http\Message\RequestInterface;
17+
use Psr\Http\Message\ResponseInterface;
1618

1719
final class Api extends AbstractApi implements ApiInterface
1820
{
1921

2022
const CHRONICLE_CLIENT_KEY_ID = 'Chronicle-Client-Key-ID';
2123

2224
/**
23-
* @var HttpClient
25+
* @var HttpAsyncClient
2426
*/
2527
private $client;
2628

@@ -45,7 +47,7 @@ final class Api extends AbstractApi implements ApiInterface
4547
private $chronicleClientId;
4648

4749
public function __construct(
48-
HttpClient $client,
50+
HttpAsyncClient $client,
4951
RequestFactoryInterface $requestFactory,
5052
string $chronicleUri,
5153
SigningPublicKey $chroniclePublicKey = \null
@@ -62,64 +64,74 @@ public function authenticate(SigningSecretKey $signingSecretKey, string $chronic
6264
$this->chronicleClientId = $chronicleClientId;
6365
}
6466

65-
public function lastHash(): array
67+
public function lastHash(): Promise
6668
{
67-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
69+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
6870
'GET',
6971
\sprintf(
7072
'%s/chronicle/lasthash',
7173
$this->chronicleUri
7274
)
73-
)));
75+
))->then(function (ResponseInterface $response) {
76+
return $this->verifyAndReturnResponse($response);
77+
});
7478
}
7579

76-
public function lookup(string $hash): array
80+
public function lookup(string $hash): Promise
7781
{
78-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
82+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
7983
'GET',
8084
\sprintf(
8185
'%s/chronicle/lookup/%s',
8286
$this->chronicleUri,
8387
\urlencode($hash)
8488
)
85-
)));
89+
))->then(function (ResponseInterface $response) {
90+
return $this->verifyAndReturnResponse($response);
91+
});
8692
}
8793

88-
public function since(string $hash): array
94+
public function since(string $hash): Promise
8995
{
90-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
96+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
9197
'GET',
9298
\sprintf(
9399
'%s/chronicle/since/%s',
94100
$this->chronicleUri,
95101
\urlencode($hash)
96102
)
97-
)));
103+
))->then(function (ResponseInterface $response) {
104+
return $this->verifyAndReturnResponse($response);
105+
});
98106
}
99107

100-
public function export(): array
108+
public function export(): Promise
101109
{
102-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
110+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
103111
'GET',
104112
\sprintf(
105113
'%s/chronicle/export',
106114
$this->chronicleUri
107115
)
108-
)));
116+
))->then(function (ResponseInterface $response) {
117+
return $this->verifyAndReturnResponse($response);
118+
});
109119
}
110120

111-
public function index(): array
121+
public function index(): Promise
112122
{
113-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
123+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
114124
'GET',
115125
\sprintf(
116126
'%s/chronicle',
117127
$this->chronicleUri
118128
)
119-
)));
129+
))->then(function (ResponseInterface $response) {
130+
return $this->verifyAndReturnResponse($response);
131+
});
120132
}
121133

122-
public function register(SigningPublicKey $publicKey, string $comment = \null): array
134+
public function register(SigningPublicKey $publicKey, string $comment = \null): Promise
123135
{
124136
$message = \json_encode([
125137
'publickey' => $publicKey->getString(),
@@ -133,10 +145,12 @@ public function register(SigningPublicKey $publicKey, string $comment = \null):
133145
'Content-Type',
134146
'application/json'
135147
));
136-
return $this->verifyAndReturnResponse($this->client->sendRequest($request));
148+
return $this->client->sendAsyncRequest($request)->then(function (ResponseInterface $response) {
149+
return $this->verifyAndReturnResponse($response);
150+
});
137151
}
138152

139-
public function revoke(string $clientId, SigningPublicKey $publicKey): array
153+
public function revoke(string $clientId, SigningPublicKey $publicKey): Promise
140154
{
141155
$message = \json_encode([
142156
'clientid' => $clientId,
@@ -150,17 +164,21 @@ public function revoke(string $clientId, SigningPublicKey $publicKey): array
150164
'Content-Type',
151165
'application/json'
152166
));
153-
return $this->verifyAndReturnResponse($this->client->sendRequest($request));
167+
return $this->client->sendAsyncRequest($request)->then(function (ResponseInterface $response) {
168+
return $this->verifyAndReturnResponse($response);
169+
});
154170
}
155171

156-
public function publish(string $message): array
172+
public function publish(string $message): Promise
157173
{
158174
/** @var RequestInterface $request */
159175
$request = $this->authenticateAndSignMessage($this->requestFactory->createRequest(
160176
'POST',
161177
\sprintf('%s/chronicle/publish', $this->chronicleUri)
162178
)->withBody(Stream::fromString($message)));
163-
return $this->verifyAndReturnResponse($this->client->sendRequest($request));
179+
return $this->client->sendAsyncRequest($request)->then(function (ResponseInterface $response) {
180+
return $this->verifyAndReturnResponse($response);
181+
});
164182
}
165183

166184
public function replica(string $source): CommonEndpointInterface
@@ -174,15 +192,17 @@ public function replica(string $source): CommonEndpointInterface
174192
);
175193
}
176194

177-
public function replicas(): array
195+
public function replicas(): Promise
178196
{
179-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
197+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
180198
'GET',
181199
\sprintf(
182200
'%s/chronicle/replica',
183201
$this->chronicleUri
184202
)
185-
)));
203+
))->then(function (ResponseInterface $response) {
204+
return $this->verifyAndReturnResponse($response);
205+
});
186206
}
187207

188208
private function authenticateAndSignMessage(MessageInterface $request): MessageInterface

src/ApiInterface.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,22 @@
44

55
namespace Lookyman\Chronicle;
66

7+
use Http\Promise\Promise;
78
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
89

910
interface ApiInterface extends CommonEndpointInterface
1011
{
1112

12-
public function index(): array;
13+
public function index(): Promise;
1314

14-
public function register(SigningPublicKey $publicKey, string $comment = null): array;
15+
public function register(SigningPublicKey $publicKey, string $comment = null): Promise;
1516

16-
public function revoke(string $clientId, SigningPublicKey $publicKey): array;
17+
public function revoke(string $clientId, SigningPublicKey $publicKey): Promise;
1718

18-
public function publish(string $message): array;
19+
public function publish(string $message): Promise;
1920

2021
public function replica(string $source): CommonEndpointInterface;
2122

22-
public function replicas(): array;
23+
public function replicas(): Promise;
2324

2425
}

src/CommonEndpointInterface.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
namespace Lookyman\Chronicle;
66

7+
use Http\Promise\Promise;
8+
79
interface CommonEndpointInterface
810
{
911

10-
public function lastHash(): array;
12+
public function lastHash(): Promise;
1113

12-
public function lookup(string $hash): array;
14+
public function lookup(string $hash): Promise;
1315

14-
public function since(string $hash): array;
16+
public function since(string $hash): Promise;
1517

16-
public function export(): array;
18+
public function export(): Promise;
1719

1820
}

src/Replica.php

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44

55
namespace Lookyman\Chronicle;
66

7-
use Http\Client\HttpClient;
7+
use Http\Client\HttpAsyncClient;
8+
use Http\Promise\Promise;
89
use Interop\Http\Factory\RequestFactoryInterface;
910
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
11+
use Psr\Http\Message\ResponseInterface;
1012

1113
final class Replica extends AbstractApi implements CommonEndpointInterface
1214
{
1315

1416
/**
15-
* @var HttpClient
17+
* @var HttpAsyncClient
1618
*/
1719
private $client;
1820

@@ -32,7 +34,7 @@ final class Replica extends AbstractApi implements CommonEndpointInterface
3234
private $source;
3335

3436
public function __construct(
35-
HttpClient $client,
37+
HttpAsyncClient $client,
3638
RequestFactoryInterface $requestFactory,
3739
string $chronicleUri,
3840
string $source,
@@ -45,54 +47,62 @@ public function __construct(
4547
$this->source = $source;
4648
}
4749

48-
public function lastHash(): array
50+
public function lastHash(): Promise
4951
{
50-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
52+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
5153
'GET',
5254
\sprintf(
5355
'%s/chronicle/replica/%s/lasthash',
5456
$this->chronicleUri,
5557
\urlencode($this->source)
5658
)
57-
)));
59+
))->then(function (ResponseInterface $response) {
60+
return $this->verifyAndReturnResponse($response);
61+
});
5862
}
5963

60-
public function lookup(string $hash): array
64+
public function lookup(string $hash): Promise
6165
{
62-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
66+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
6367
'GET',
6468
\sprintf(
6569
'%s/chronicle/replica/%s/lookup/%s',
6670
$this->chronicleUri,
6771
\urlencode($this->source),
6872
\urlencode($hash)
6973
)
70-
)));
74+
))->then(function (ResponseInterface $response) {
75+
return $this->verifyAndReturnResponse($response);
76+
});
7177
}
7278

73-
public function since(string $hash): array
79+
public function since(string $hash): Promise
7480
{
75-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
81+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
7682
'GET',
7783
\sprintf(
7884
'%s/chronicle/replica/%s/since/%s',
7985
$this->chronicleUri,
8086
\urlencode($this->source),
8187
\urlencode($hash)
8288
)
83-
)));
89+
))->then(function (ResponseInterface $response) {
90+
return $this->verifyAndReturnResponse($response);
91+
});
8492
}
8593

86-
public function export(): array
94+
public function export(): Promise
8795
{
88-
return $this->verifyAndReturnResponse($this->client->sendRequest($this->requestFactory->createRequest(
96+
return $this->client->sendAsyncRequest($this->requestFactory->createRequest(
8997
'GET',
9098
\sprintf(
9199
'%s/chronicle/replica/%s/export',
92100
$this->chronicleUri,
93101
\urlencode($this->source)
94102
)
95-
)));
103+
))->then(function (ResponseInterface $response) {
104+
return $this->verifyAndReturnResponse($response);
105+
});
96106
}
97107

98108
}

0 commit comments

Comments
 (0)