Skip to content

Commit 0a627d9

Browse files
committed
setup connection reopening when ssl configuration differs
Signed-off-by: ghlen <[email protected]>
1 parent 470e22e commit 0a627d9

File tree

2 files changed

+95
-48
lines changed

2 files changed

+95
-48
lines changed

src/Bolt/BoltConnectionPool.php

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Laudis\Neo4j\Contracts\ConnectionInterface;
2626
use Laudis\Neo4j\Contracts\ConnectionPoolInterface;
2727
use Laudis\Neo4j\Databags\DatabaseInfo;
28+
use Laudis\Neo4j\Databags\DriverConfiguration;
2829
use Laudis\Neo4j\Databags\SessionConfiguration;
2930
use Laudis\Neo4j\Enum\ConnectionProtocol;
3031
use Laudis\Neo4j\Neo4j\RoutingTable;
@@ -39,8 +40,14 @@
3940
*/
4041
final class BoltConnectionPool implements ConnectionPoolInterface
4142
{
42-
/** @var array<string, list<ConnectionInterface<Bolt>>> */
43+
/** @var array<string, list<BoltConnection>> */
4344
private static array $connectionCache = [];
45+
private DriverConfiguration $driverConfig;
46+
47+
public function __construct(DriverConfiguration $driverConfig)
48+
{
49+
$this->driverConfig = $driverConfig;
50+
}
4451

4552
/**
4653
* @throws Exception
@@ -60,8 +67,20 @@ public function acquire(
6067
self::$connectionCache[$key] = [];
6168
}
6269

63-
foreach (self::$connectionCache[$key] as $connection) {
70+
foreach (self::$connectionCache[$key] as $i => $connection) {
6471
if (!$connection->isOpen()) {
72+
$sslConfig = $connection->getDriverConfiguration()->getSslConfiguration();
73+
$newSslConfig = $this->driverConfig->getSslConfiguration();
74+
if ($sslConfig->getMode() !== $newSslConfig->getMode() ||
75+
$sslConfig->isVerifyPeer() === $newSslConfig->isVerifyPeer()
76+
) {
77+
$connection = $this->openConnection($connectingTo, $socketTimeout, $uri, $table, $authenticate, $userAgent, $config);
78+
79+
/** @psalm-suppress PropertyTypeCoercion */
80+
self::$connectionCache[$key][$i] = $connection;
81+
82+
return $connection;
83+
}
6584
$connection->open();
6685

6786
$authenticate->authenticateBolt($connection->getImplementation(), $connectingTo, $userAgent);
@@ -70,52 +89,7 @@ public function acquire(
7089
}
7190
}
7291

73-
$socket = new StreamSocket($connectingTo->getHost(), $connectingTo->getPort() ?? 7687, $socketTimeout);
74-
75-
$this->configureSsl($uri, $connectingTo, $socket, $table);
76-
77-
$bolt = new Bolt($socket);
78-
$authenticate->authenticateBolt($bolt, $connectingTo, $userAgent);
79-
80-
// We create a weak reference to optimise the socket usage. This way the connection can reuse the bolt variable
81-
// the first time it tries to connect. Only when this function is finished and the returned connection is closed
82-
// will the reference return null, prompting the need to reopen and recreate the bolt object on the same socket.
83-
$originalBolt = WeakReference::create($bolt);
84-
85-
/**
86-
* @var array{'name': 0, 'version': 1, 'edition': 2}
87-
* @psalm-suppress all
88-
*/
89-
$fields = array_flip($bolt->run(<<<'CYPHER'
90-
CALL dbms.components()
91-
YIELD name, versions, edition
92-
UNWIND versions AS version
93-
RETURN name, version, edition
94-
CYPHER
95-
)['fields']);
96-
97-
/** @var array{0: array{0: string, 1: string, 2: string}} $results */
98-
$results = $bolt->pullAll();
99-
100-
$connection = new BoltConnection(
101-
$results[0][$fields['name']].'-'.$results[0][$fields['edition']].'/'.$results[0][$fields['version']],
102-
$connectingTo,
103-
$results[0][$fields['version']],
104-
ConnectionProtocol::determineBoltVersion($bolt),
105-
$config->getAccessMode(),
106-
new DatabaseInfo($config->getDatabase()),
107-
static function () use ($socket, $authenticate, $connectingTo, $userAgent, $originalBolt) {
108-
$bolt = $originalBolt->get();
109-
if ($bolt === null) {
110-
$bolt = new Bolt($socket);
111-
$authenticate->authenticateBolt($bolt, $connectingTo, $userAgent);
112-
}
113-
114-
return $bolt;
115-
}
116-
);
117-
118-
$connection->open();
92+
$connection = $this->openConnection($connectingTo, $socketTimeout, $uri, $table, $authenticate, $userAgent, $config);
11993

12094
self::$connectionCache[$key][] = $connection;
12195

@@ -174,4 +148,64 @@ public function canConnect(UriInterface $uri, AuthenticateInterface $authenticat
174148

175149
return true;
176150
}
151+
152+
private function openConnection(
153+
UriInterface $connectingTo,
154+
float $socketTimeout,
155+
UriInterface $uri,
156+
?RoutingTable $table,
157+
AuthenticateInterface $authenticate,
158+
string $userAgent,
159+
SessionConfiguration $config
160+
): BoltConnection {
161+
$socket = new StreamSocket($connectingTo->getHost(), $connectingTo->getPort() ?? 7687, $socketTimeout);
162+
163+
$this->configureSsl($uri, $connectingTo, $socket, $table);
164+
165+
$bolt = new Bolt($socket);
166+
$authenticate->authenticateBolt($bolt, $connectingTo, $userAgent);
167+
168+
// We create a weak reference to optimise the socket usage. This way the connection can reuse the bolt variable
169+
// the first time it tries to connect. Only when this function is finished and the returned connection is closed
170+
// will the reference return null, prompting the need to reopen and recreate the bolt object on the same socket.
171+
$originalBolt = WeakReference::create($bolt);
172+
173+
/**
174+
* @var array{'name': 0, 'version': 1, 'edition': 2}
175+
* @psalm-suppress all
176+
*/
177+
$fields = array_flip($bolt->run(<<<'CYPHER'
178+
CALL dbms.components()
179+
YIELD name, versions, edition
180+
UNWIND versions AS version
181+
RETURN name, version, edition
182+
CYPHER
183+
)['fields']);
184+
185+
/** @var array{0: array{0: string, 1: string, 2: string}} $results */
186+
$results = $bolt->pullAll();
187+
188+
$connection = new BoltConnection(
189+
$results[0][$fields['name']].'-'.$results[0][$fields['edition']].'/'.$results[0][$fields['version']],
190+
$connectingTo,
191+
$results[0][$fields['version']],
192+
ConnectionProtocol::determineBoltVersion($bolt),
193+
$config->getAccessMode(),
194+
new DatabaseInfo($config->getDatabase()),
195+
$this->driverConfig,
196+
static function () use ($socket, $authenticate, $connectingTo, $userAgent, $originalBolt) {
197+
$bolt = $originalBolt->get();
198+
if ($bolt === null) {
199+
$bolt = new Bolt($socket);
200+
$authenticate->authenticateBolt($bolt, $connectingTo, $userAgent);
201+
}
202+
203+
return $bolt;
204+
}
205+
);
206+
207+
$connection->open();
208+
209+
return $connection;
210+
}
177211
}

src/Common/BoltConnection.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use function call_user_func;
1818
use Laudis\Neo4j\Contracts\ConnectionInterface;
1919
use Laudis\Neo4j\Databags\DatabaseInfo;
20+
use Laudis\Neo4j\Databags\DriverConfiguration;
2021
use Laudis\Neo4j\Enum\AccessMode;
2122
use Laudis\Neo4j\Enum\ConnectionProtocol;
2223
use Psr\Http\Message\UriInterface;
@@ -45,6 +46,8 @@ final class BoltConnection implements ConnectionInterface
4546
* @psalm-readonly
4647
*/
4748
private $connector;
49+
/** @psalm-readonly */
50+
private DriverConfiguration $driverConfiguration;
4851

4952
/**
5053
* @psalm-mutation-free
@@ -58,6 +61,7 @@ public function __construct(
5861
ConnectionProtocol $protocol,
5962
AccessMode $accessMode,
6063
DatabaseInfo $databaseInfo,
64+
DriverConfiguration $config,
6165
$connector
6266
) {
6367
$this->serverAgent = $serverAgent;
@@ -67,6 +71,7 @@ public function __construct(
6771
$this->accessMode = $accessMode;
6872
$this->databaseInfo = $databaseInfo;
6973
$this->connector = $connector;
74+
$this->driverConfiguration = $config;
7075
}
7176

7277
/**
@@ -148,4 +153,12 @@ public function close(): void
148153
{
149154
$this->bolt = null;
150155
}
156+
157+
/**
158+
* @psalm-mutation-free
159+
*/
160+
public function getDriverConfiguration(): DriverConfiguration
161+
{
162+
return $this->driverConfiguration;
163+
}
151164
}

0 commit comments

Comments
 (0)