Skip to content

Commit 7f0e8b2

Browse files
authored
Merge pull request #32 from laudis-technologies/debug
- added auto routing to http - increased testing - better error handling
2 parents 0db17d9 + f92eb5d commit 7f0e8b2

File tree

11 files changed

+240
-45
lines changed

11 files changed

+240
-45
lines changed

docker-compose.yml

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,28 @@ services:
2929
neo4j-42:
3030
networks:
3131
- neo4j
32-
image: neo4j:4.2
32+
image: neo4j:4.2-enterprise
3333
healthcheck:
34-
test: neo4j status
34+
test: [ "CMD", "neo4j status" ]
35+
interval: 30s
36+
timeout: 10s
37+
retries: 5
3538
expose:
3639
- 7474
3740
- 7687
41+
ports:
42+
- "7474:7474"
43+
- "7687:7687"
3844
environment:
45+
- NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
3946
- NEO4J_AUTH=neo4j/test
4047
core1:
4148
image: neo4j:4.2-enterprise
4249
healthcheck:
43-
test: neo4j status
50+
test: [ "CMD", "neo4j status" ]
51+
interval: 30s
52+
timeout: 10s
53+
retries: 5
4454
networks:
4555
- neo4j
4656
expose:
@@ -49,6 +59,9 @@ services:
4959
- 5000
5060
- 6000
5161
- 7000
62+
ports:
63+
- "7475:7474"
64+
- "7688:7687"
5265
environment:
5366
- NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
5467
- NEO4J_AUTH=neo4j/test
@@ -62,7 +75,10 @@ services:
6275
core2:
6376
image: neo4j:4.2-enterprise
6477
healthcheck:
65-
test: neo4j status
78+
test: [ "CMD", "neo4j status" ]
79+
interval: 30s
80+
timeout: 10s
81+
retries: 5
6682
networks:
6783
- neo4j
6884
expose:
@@ -84,7 +100,10 @@ services:
84100
core3:
85101
image: neo4j:4.2-enterprise
86102
healthcheck:
87-
test: neo4j status
103+
test: [ "CMD", "neo4j status" ]
104+
interval: 30s
105+
timeout: 10s
106+
retries: 5
88107
networks:
89108
- neo4j
90109
expose:
@@ -106,7 +125,10 @@ services:
106125
readreplica1:
107126
image: neo4j:4.2-enterprise
108127
healthcheck:
109-
test: neo4j status
128+
test: [ "CMD", "neo4j status" ]
129+
interval: 30s
130+
timeout: 10s
131+
retries: 5
110132
networks:
111133
- neo4j
112134
expose:

src/Contracts/Injections.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Laudis Neo4j package.
7+
*
8+
* (c) Laudis technologies <http://laudis.tech>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Laudis\Neo4j\Contracts;
15+
16+
interface Injections
17+
{
18+
/**
19+
* @param string|callable():string $database
20+
*
21+
* @return static
22+
*/
23+
public function withDatabase($database): self;
24+
25+
/**
26+
* @param callable():bool|bool $routing
27+
*
28+
* @return static
29+
*/
30+
public function withAutoRouting($routing): self;
31+
32+
public function database(): string;
33+
34+
public function hasAutoRouting(): bool;
35+
}

src/Network/Bolt/AutoRoutedSession.php renamed to src/Network/AutoRoutedSession.php

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,20 @@
1111
* file that was distributed with this source code.
1212
*/
1313

14-
namespace Laudis\Neo4j\Network\Bolt;
14+
namespace Laudis\Neo4j\Network;
1515

1616
use Ds\Map;
1717
use Ds\Vector;
1818
use Exception;
1919
use Laudis\Neo4j\ClientBuilder;
2020
use Laudis\Neo4j\Contracts\ClientInterface;
21+
use Laudis\Neo4j\Contracts\Injections;
2122
use Laudis\Neo4j\Contracts\SessionInterface;
2223
use Laudis\Neo4j\Contracts\TransactionInterface;
2324
use Laudis\Neo4j\Databags\Statement;
2425
use Laudis\Neo4j\Enum\RoutingRoles;
26+
use Laudis\Neo4j\Network\Bolt\BoltInjections;
27+
use Laudis\Neo4j\Network\Http\HttpInjections;
2528
use function parse_url;
2629
use function preg_match;
2730
use function random_int;
@@ -32,12 +35,16 @@ final class AutoRoutedSession implements SessionInterface
3235
private SessionInterface $referenceSession;
3336
private ?ClientInterface $client = null;
3437
private ?RoutingTable $table = null;
35-
private BoltInjections $injections;
38+
/** @var BoltInjections|HttpInjections */
39+
private Injections $injections;
3640
private int $maxLeader = 0;
3741
private int $maxFollower = 0;
3842
private array $parsedUrl;
3943

40-
public function __construct(SessionInterface $referenceSession, BoltInjections $injections, array $parsedUrl)
44+
/**
45+
* @param BoltInjections|HttpInjections $injections
46+
*/
47+
public function __construct(SessionInterface $referenceSession, Injections $injections, array $parsedUrl)
4148
{
4249
$this->referenceSession = $referenceSession;
4350
$this->injections = $injections;
@@ -81,20 +88,20 @@ private function setupClient(): ClientInterface
8188
$values = $response->get('servers');
8289
/** @var int $ttl */
8390
$ttl = $response->get('ttl');
91+
if ($this->injections instanceof HttpInjections) {
92+
$values = $this->translateTableToHttp($values);
93+
}
8494
$this->table = new RoutingTable($values, time() + $ttl);
8595

8696
$builder = ClientBuilder::create();
8797
$leaders = $this->table->getWithRole(RoutingRoles::LEADER());
8898
$followers = $this->table->getWithRole(RoutingRoles::FOLLOWER());
8999
$injections = $this->injections->withAutoRouting(false);
90100

91-
foreach ($leaders as $i => $leader) {
92-
$builder = $builder->addBoltConnection('leader-'.$i, $this->rebuildUrl($leader), $injections);
93-
$this->maxLeader = $i;
94-
}
95-
foreach ($followers as $i => $follower) {
96-
$builder = $builder->addBoltConnection('follower-'.$i, $this->rebuildUrl($follower), $injections);
97-
$this->maxFollower = $i;
101+
if ($injections instanceof BoltInjections) {
102+
$builder = $this->buildBoltConnections($leaders, $builder, $injections, $followers);
103+
} else {
104+
$builder = $this->buildHttpConnections($leaders, $builder, $injections, $followers);
98105
}
99106

100107
$this->client = $builder->build();
@@ -183,9 +190,9 @@ public function commitTransaction(TransactionInterface $transaction, iterable $s
183190
return $transaction->commit($statements);
184191
}
185192

186-
private function rebuildUrl(string $url): string
193+
private function rebuildUrl(array $parsedUrl): string
187194
{
188-
$parts = array_merge($this->parsedUrl, parse_url($url));
195+
$parts = array_merge($this->parsedUrl, $parsedUrl);
189196

190197
return (isset($parts['scheme']) ? "{$parts['scheme']}:" : '').
191198
((isset($parts['user']) || isset($parts['host'])) ? '//' : '').
@@ -198,4 +205,69 @@ private function rebuildUrl(string $url): string
198205
(isset($parts['query']) ? "?{$parts['query']}" : '').
199206
(isset($parts['fragment']) ? "#{$parts['fragment']}" : '');
200207
}
208+
209+
/**
210+
* @param Vector<string> $leaders
211+
* @param Vector<string> $followers
212+
*/
213+
private function buildBoltConnections(
214+
Vector $leaders,
215+
ClientBuilder $builder,
216+
BoltInjections $injections,
217+
Vector $followers
218+
): ClientBuilder {
219+
foreach ($leaders as $i => $leader) {
220+
$builder = $builder->addBoltConnection('leader-'.$i, $this->rebuildUrl(parse_url($leader)), $injections);
221+
$this->maxLeader = $i;
222+
}
223+
foreach ($followers as $i => $follower) {
224+
$builder = $builder->addBoltConnection('follower-'.$i, $this->rebuildUrl(parse_url($follower)), $injections);
225+
$this->maxFollower = $i;
226+
}
227+
228+
return $builder;
229+
}
230+
231+
/**
232+
* @param Vector<string> $leaders
233+
* @param Vector<string> $followers
234+
*/
235+
private function buildHttpConnections(
236+
Vector $leaders,
237+
ClientBuilder $builder,
238+
HttpInjections $injections,
239+
Vector $followers
240+
): ClientBuilder {
241+
foreach ($leaders as $i => $leader) {
242+
$builder = $builder->addHttpConnection('leader-'.$i, $this->rebuildUrl(parse_url($leader)), $injections);
243+
$this->maxLeader = $i;
244+
}
245+
foreach ($followers as $i => $follower) {
246+
$builder = $builder->addHttpConnection('follower-'.$i, $this->rebuildUrl(parse_url($follower)), $injections);
247+
$this->maxFollower = $i;
248+
}
249+
250+
return $builder;
251+
}
252+
253+
/**
254+
* @param iterable<array{addresses: list<string>, role:string}> $servers
255+
*
256+
* @return iterable<array{addresses: list<string>, role:string}>
257+
*/
258+
private function translateTableToHttp(iterable $servers): iterable
259+
{
260+
/** @var list<array{addresses: list<string>, role:string}> */
261+
$tbr = [];
262+
263+
foreach ($servers as $server) {
264+
$row = ['addresses' => [], 'role' => $server['role']];
265+
foreach ($server['addresses'] as $address) {
266+
$row['addresses'][] = $this->rebuildUrl(['host' => parse_url($address, PHP_URL_HOST)]);
267+
}
268+
$tbr[] = $row;
269+
}
270+
271+
return $tbr;
272+
}
201273
}

src/Network/Bolt/BoltDriver.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Laudis\Neo4j\Databags\Neo4jError;
2424
use Laudis\Neo4j\Exception\Neo4jException;
2525
use Laudis\Neo4j\Formatter\BoltCypherFormatter;
26+
use Laudis\Neo4j\Network\AutoRoutedSession;
2627

2728
/**
2829
* @psalm-type ParsedUrl = array{fragment?: string, host: string, pass: string, path?: string, port?: int, query?: string, scheme?: string, user: string}

src/Network/Bolt/BoltInjections.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use function call_user_func;
1717
use function is_callable;
18+
use Laudis\Neo4j\Contracts\Injections;
1819

1920
/**
2021
* @psalm-type SSLContextOptions = null|array{
@@ -39,7 +40,7 @@
3940
*
4041
* @psalm-type LazySSLContextOptions = callable():SSLContextOptions|SSLContextOptions
4142
*/
42-
final class BoltInjections
43+
final class BoltInjections implements Injections
4344
{
4445
/** @var callable():string|string */
4546
private $database;

src/Network/Http/HttpDriver.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Laudis\Neo4j\Databags\RequestData;
2020
use Laudis\Neo4j\Formatter\HttpCypherFormatter;
2121
use Laudis\Neo4j\HttpDriver\RequestFactory;
22+
use Laudis\Neo4j\Network\AutoRoutedSession;
2223
use Laudis\Neo4j\Network\VersionDiscovery;
2324
use Psr\Http\Client\ClientExceptionInterface;
2425

@@ -76,6 +77,9 @@ public function aquireSession(): SessionInterface
7677
$formatter,
7778
$requestData
7879
);
80+
if ($this->injections->hasAutoRouting()) {
81+
$this->session = new AutoRoutedSession($this->session, $this->injections, $this->parsedUrl);
82+
}
7983

8084
return $this->session;
8185
}

0 commit comments

Comments
 (0)