Skip to content

Commit cb11050

Browse files
committed
Merge branch 'cacheing'
2 parents 58028d3 + 61e6d52 commit cb11050

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2232
-725
lines changed

composer.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,23 @@
3333
"php-http/message-factory": "^1.0",
3434
"stefanak-michal/bolt": "^4.1",
3535
"symfony/polyfill-php80": "^1.2",
36+
"psr/simple-cache": "^1.0",
3637
"ext-json": "*"
3738
},
39+
"provide": {
40+
"psr/simple-cache-implementation": "2.0|3.0"
41+
},
3842
"suggest": {
3943
"ext-bcmath": "Needed to implement bolt protocol",
44+
"ext-sysvsem": "Needed for enabling connection pooling between processes",
4045
"composer-runtime-api": "Install composer 2 for auto detection of version in user agent"
4146
},
4247
"require-dev": {
4348
"phpunit/phpunit": "^9.0",
4449
"nyholm/psr7": "^1.3",
4550
"nyholm/psr7-server": "^1.0",
4651
"kriswallsmith/buzz": "^1.2",
47-
"vimeo/psalm": "4.23.0",
52+
"vimeo/psalm": "^4.27",
4853
"friendsofphp/php-cs-fixer": "3.8.0",
4954
"psalm/plugin-phpunit": "^0.15.1",
5055
"monolog/monolog": "^2.2",
@@ -54,7 +59,8 @@
5459
"psr/container": "^1.1",
5560
"lctrs/psalm-psr-container-plugin": "^1.3",
5661
"symfony/uid": "^5.0",
57-
"symfony/var-dumper": "^5.0"
62+
"symfony/var-dumper": "^5.0",
63+
"cache/integration-tests": "dev-master"
5864
},
5965
"autoload": {
6066
"psr-4": {

src/Authentication/BasicAuth.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ public function authenticateBolt(V3 $bolt, string $userAgent): array
6262
/** @var array{server: string, connection_id: string, hints: list} */
6363
return $bolt->hello(Auth::basic($this->username, $this->password, $userAgent));
6464
}
65+
66+
public function toString(UriInterface $uri): string
67+
{
68+
return sprintf('Basic %s:%s@%s:%s', $this->username, '######', $uri->getHost(), $uri->getPort() ?? '');
69+
}
6570
}

src/Authentication/KerberosAuth.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Laudis\Neo4j\Contracts\AuthenticateInterface;
1919
use Psr\Http\Message\RequestInterface;
2020
use Psr\Http\Message\UriInterface;
21+
use function sprintf;
2122

2223
/**
2324
* Authenticates connections using a kerberos token.
@@ -53,4 +54,9 @@ public function authenticateBolt(V3 $bolt, string $userAgent): array
5354
/** @var array{server: string, connection_id: string, hints: list} */
5455
return $bolt->hello(Auth::bearer($this->token, $userAgent));
5556
}
57+
58+
public function toString(UriInterface $uri): string
59+
{
60+
return sprintf('Kerberos %s@%s:%s', $this->token, $uri->getHost(), $uri->getPort() ?? '');
61+
}
5662
}

src/Authentication/NoAuth.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Laudis\Neo4j\Contracts\AuthenticateInterface;
1919
use Psr\Http\Message\RequestInterface;
2020
use Psr\Http\Message\UriInterface;
21+
use function sprintf;
2122

2223
/**
2324
* Doesn't authenticate connections.
@@ -42,4 +43,9 @@ public function authenticateBolt(V3 $bolt, string $userAgent): array
4243
/** @var array{server: string, connection_id: string, hints: list} */
4344
return $bolt->hello(Auth::none($userAgent));
4445
}
46+
47+
public function toString(UriInterface $uri): string
48+
{
49+
return sprintf('No Auth %s:%s', $uri->getHost(), $uri->getPort() ?? '');
50+
}
4551
}

src/Authentication/OpenIDConnectAuth.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Laudis\Neo4j\Contracts\AuthenticateInterface;
1717
use Psr\Http\Message\RequestInterface;
1818
use Psr\Http\Message\UriInterface;
19+
use function sprintf;
1920

2021
final class OpenIDConnectAuth implements AuthenticateInterface
2122
{
@@ -48,4 +49,9 @@ public function authenticateBolt(V3 $bolt, string $userAgent): array
4849
/** @var array{server: string, connection_id: string, hints: list} */
4950
return $bolt->hello(Auth::bearer($this->token));
5051
}
52+
53+
public function toString(UriInterface $uri): string
54+
{
55+
return sprintf('OpenId %s@%s:%s', $this->token, $uri->getHost(), $uri->getPort() ?? '');
56+
}
5157
}

src/Basic/Driver.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ public function verifyConnectivity(): bool
5656

5757
/**
5858
* @param string|UriInterface $uri
59-
* @pure
6059
*/
6160
public static function create($uri, ?DriverConfiguration $configuration = null, ?AuthenticateInterface $authenticate = null): self
6261
{

src/Bolt/BoltConnection.php

Lines changed: 52 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,36 @@
1313

1414
namespace Laudis\Neo4j\Bolt;
1515

16-
use BadMethodCallException;
1716
use Bolt\error\IgnoredException;
1817
use Bolt\error\MessageException;
1918
use Bolt\protocol\V3;
2019
use Bolt\protocol\V4;
21-
use Laudis\Neo4j\BoltFactory;
20+
use function in_array;
2221
use Laudis\Neo4j\Common\ConnectionConfiguration;
22+
use Laudis\Neo4j\Contracts\AuthenticateInterface;
2323
use Laudis\Neo4j\Contracts\ConnectionInterface;
24+
use Laudis\Neo4j\Contracts\FormatterInterface;
2425
use Laudis\Neo4j\Databags\BookmarkHolder;
2526
use Laudis\Neo4j\Databags\DatabaseInfo;
26-
use Laudis\Neo4j\Databags\DriverConfiguration;
2727
use Laudis\Neo4j\Enum\AccessMode;
2828
use Laudis\Neo4j\Enum\ConnectionProtocol;
2929
use Laudis\Neo4j\Types\CypherList;
30-
use LogicException;
3130
use Psr\Http\Message\UriInterface;
32-
use RuntimeException;
3331
use function str_starts_with;
3432
use WeakReference;
3533

3634
/**
37-
* @implements ConnectionInterface<V3>
35+
* @implements ConnectionInterface<array{0: V3, 1: Connection}>
3836
*
39-
* @psalm-import-type BoltMeta from \Laudis\Neo4j\Contracts\FormatterInterface
37+
* @psalm-import-type BoltMeta from FormatterInterface
4038
*/
41-
final class BoltConnection implements ConnectionInterface
39+
class BoltConnection implements ConnectionInterface
4240
{
43-
private ?V3 $boltProtocol;
41+
private V3 $boltProtocol;
4442
/** @psalm-readonly */
4543
private ConnectionConfiguration $config;
46-
/** @psalm-readonly */
47-
private BoltFactory $factory;
44+
private string $serverState;
4845

49-
private string $serverState = 'DISCONNECTED';
5046
/**
5147
* @note We are using references to "subscribed results" to maintain backwards compatibility and try and strike
5248
* a balance between performance and ease of use.
@@ -61,30 +57,31 @@ final class BoltConnection implements ConnectionInterface
6157
* @var list<WeakReference<CypherList>>
6258
*/
6359
private array $subscribedResults = [];
60+
private AuthenticateInterface $auth;
61+
private Connection $connection;
62+
private string $userAgent;
6463

65-
/**
66-
* @psalm-mutation-free
67-
*/
68-
public function __construct(BoltFactory $factory, ?V3 $boltProtocol, ConnectionConfiguration $config)
64+
public function getImplementation()
6965
{
70-
$this->factory = $factory;
71-
$this->boltProtocol = $boltProtocol;
72-
$this->config = $config;
73-
if ($boltProtocol) {
74-
$this->serverState = 'READY';
75-
}
66+
return [$this->boltProtocol, $this->connection];
7667
}
7768

7869
/**
7970
* @psalm-mutation-free
8071
*/
81-
public function getImplementation(): V3
72+
public function __construct(V3 $protocol, Connection $connection, AuthenticateInterface $auth, string $userAgent, ConnectionConfiguration $config)
8273
{
83-
if ($this->boltProtocol === null) {
84-
throw new RuntimeException('Connection is closed');
85-
}
74+
$this->boltProtocol = $protocol;
75+
$this->serverState = 'READY';
76+
$this->auth = $auth;
77+
$this->connection = $connection;
78+
$this->userAgent = $userAgent;
79+
$this->config = $config;
80+
}
8681

87-
return $this->boltProtocol;
82+
public function getEncryptionLevel(): string
83+
{
84+
return $this->connection->getEncryptionLevel();
8885
}
8986

9087
/**
@@ -135,6 +132,11 @@ public function getDatabaseInfo(): ?DatabaseInfo
135132
return $this->config->getDatabaseInfo();
136133
}
137134

135+
public function getAuthentication(): AuthenticateInterface
136+
{
137+
return $this->auth;
138+
}
139+
138140
/**
139141
* @psalm-mutation-free
140142
*/
@@ -143,37 +145,12 @@ public function isOpen(): bool
143145
return $this->serverState !== 'DISCONNECTED' && $this->serverState !== 'DEFUNCT';
144146
}
145147

146-
public function open(): void
147-
{
148-
if ($this->boltProtocol !== null) {
149-
throw new BadMethodCallException('Cannot open a connection that is already open');
150-
}
151-
152-
$this->boltProtocol = $this->factory->build()[0];
153-
}
154-
155148
public function setTimeout(float $timeout): void
156149
{
157-
$this->factory->getConnection()->setTimeout($timeout);
150+
$this->connection->setTimeout($timeout);
158151
}
159152

160-
/**
161-
* Closes the connection.
162-
*
163-
* Any of the preconditioned states are: 'READY', 'STREAMING', 'TX_READY', 'TX_STREAMING', 'FAILED', 'INTERRUPTED'.
164-
* Sends signal: 'DISCONNECT'
165-
*/
166-
public function close(): void
167-
{
168-
$this->consumeResults();
169-
170-
$this->protocol()->goodbye();
171-
172-
$this->serverState = 'DEFUNCT';
173-
$this->boltProtocol = null; // has to be set to null as the sockets don't recover nicely contrary to what the underlying code might lead you to believe
174-
}
175-
176-
private function consumeResults(): void
153+
public function consumeResults(): void
177154
{
178155
foreach ($this->subscribedResults as $result) {
179156
$result = $result->get();
@@ -230,11 +207,6 @@ public function begin(?string $database, ?float $timeout, BookmarkHolder $holder
230207
$this->serverState = 'TX_READY';
231208
}
232209

233-
public function getFactory(): BoltFactory
234-
{
235-
return $this->factory;
236-
}
237-
238210
/**
239211
* Discards a result.
240212
*
@@ -273,7 +245,7 @@ public function discard(?int $qid): void
273245
*/
274246
public function run(string $text, array $parameters, ?string $database, ?float $timeout, BookmarkHolder $holder): array
275247
{
276-
if (!str_starts_with($this->serverState, 'TX_') || str_starts_with($this->getServerVersion(), '3')) {
248+
if (in_array($this->serverState, ['STREAMING', 'TX_STREAMING'])) {
277249
$this->consumeResults();
278250
}
279251

@@ -349,6 +321,11 @@ public function rollback(): void
349321
$this->serverState = 'READY';
350322
}
351323

324+
public function protocol(): V3
325+
{
326+
return $this->boltProtocol;
327+
}
328+
352329
/**
353330
* Pulls a result set.
354331
*
@@ -363,10 +340,10 @@ public function pull(?int $qid, ?int $fetchSize): array
363340
$bolt = $this->protocol();
364341
try {
365342
if (!$bolt instanceof V4) {
366-
/** @var non-empty-list<list> */
343+
/** @var non-empty-list<list> $tbr */
367344
$tbr = $bolt->pullAll($extra);
368345
} else {
369-
/** @var non-empty-list<list> */
346+
/** @var non-empty-list<list> $tbr */
370347
$tbr = $bolt->pull($extra);
371348
}
372349
} catch (MessageException $e) {
@@ -384,18 +361,17 @@ public function pull(?int $qid, ?int $fetchSize): array
384361
return $tbr;
385362
}
386363

387-
/**
388-
* @psalm-mutation-free
389-
*/
390-
public function getDriverConfiguration(): DriverConfiguration
391-
{
392-
return $this->config->getDriverConfiguration();
393-
}
394-
395364
public function __destruct()
396365
{
397366
if ($this->serverState !== 'FAILED' && $this->isOpen()) {
398-
$this->close();
367+
if (in_array($this->serverState, ['STREAMING', 'TX_STREAMING'])) {
368+
$this->consumeResults();
369+
}
370+
371+
$this->protocol()->goodbye();
372+
373+
$this->serverState = 'DEFUNCT';
374+
unset($this->boltProtocol); // has to be set to null as the sockets don't recover nicely contrary to what the underlying code might lead you to believe;
399375
}
400376
}
401377

@@ -440,15 +416,6 @@ public function subscribeResult(CypherList $result): void
440416
$this->subscribedResults[] = WeakReference::create($result);
441417
}
442418

443-
private function protocol(): V3
444-
{
445-
if ($this->boltProtocol === null) {
446-
throw new LogicException('Cannot use protocol if it is not created');
447-
}
448-
449-
return $this->boltProtocol;
450-
}
451-
452419
private function interpretResult(array $result): void
453420
{
454421
if (str_starts_with($this->serverState, 'TX_')) {
@@ -475,4 +442,9 @@ private function countResults(): int
475442

476443
return $ctr;
477444
}
445+
446+
public function getUserAgent(): string
447+
{
448+
return $this->userAgent;
449+
}
478450
}

0 commit comments

Comments
 (0)