Skip to content

Commit 2c632ea

Browse files
committed
Added microsecond support for timeout
1 parent ebf442d commit 2c632ea

File tree

5 files changed

+77
-5
lines changed

5 files changed

+77
-5
lines changed

src/connection/AConnection.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ abstract class AConnection implements IConnection
3131
* AConnection constructor.
3232
* @param string $ip
3333
* @param int $port
34-
* @param int $timeout
34+
* @param int|float $timeout
3535
*/
36-
public function __construct(string $ip = '127.0.0.1', int $port = 7687, int $timeout = 15)
36+
public function __construct(string $ip = '127.0.0.1', int $port = 7687, $timeout = 15)
3737
{
3838
$this->ip = $ip;
3939
$this->port = $port;

src/connection/IConnection.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
*/
1212
interface IConnection
1313
{
14-
public function __construct(string $ip = '127.0.0.1', int $port = 7687, int $timeout = 15);
14+
/**
15+
* @param int|float $timeout
16+
*/
17+
public function __construct(string $ip = '127.0.0.1', int $port = 7687, $timeout = 15);
1518

1619
public function connect(): bool;
1720

src/connection/Socket.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ public function connect(): bool
4242

4343
socket_set_option($this->socket, SOL_TCP, TCP_NODELAY, 1);
4444
socket_set_option($this->socket, SOL_SOCKET, SO_KEEPALIVE, 1);
45-
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => $this->timeout, 'usec' => 0]);
46-
socket_set_option($this->socket, SOL_SOCKET, SO_SNDTIMEO, ['sec' => $this->timeout, 'usec' => 0]);
45+
$timeoutSeconds = floor($this->timeout);
46+
$microSeconds = floor(($this->timeout - $timeoutSeconds) * 1000000);
47+
$timeoutOption = ['sec' => $timeoutSeconds, 'usec' => $microSeconds];
48+
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, $timeoutOption);
49+
socket_set_option($this->socket, SOL_SOCKET, SO_SNDTIMEO, $timeoutOption);
4750

4851
$conn = @socket_connect($this->socket, $this->ip, $this->port);
4952
if (!$conn) {

src/connection/StreamSocket.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
use Bolt\Bolt;
77
use Bolt\error\ConnectException;
8+
use function floor;
9+
use function stream_set_timeout;
810

911
/**
1012
* Stream socket class
@@ -66,6 +68,11 @@ public function connect(): bool
6668
}
6769
}
6870

71+
$timeout = (int) floor($this->timeout);
72+
if (!stream_set_timeout($this->stream, $timeout, (int) floor(($this->timeout - $timeout) * 1000000))) {
73+
throw new ConnectException('Cannot set timeout on stream');
74+
}
75+
6976
return true;
7077
}
7178

tests/SocketTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Bolt\tests;
4+
5+
use Bolt\Bolt;
6+
use Bolt\connection\StreamSocket;
7+
use Bolt\error\ConnectException;
8+
use Exception;
9+
use PHPUnit\Framework\TestCase;
10+
use function microtime;
11+
12+
final class SocketTest extends TestCase
13+
{
14+
/**
15+
* @throws Exception
16+
*/
17+
public function testMillisecondTimeout(): void
18+
{
19+
$socket = new StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', (int) ($GLOBALS['NEO_PORT'] ?? 7687), 1.5);
20+
$bolt = new Bolt($socket);
21+
22+
$bolt->init('Test/1.0', $GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']);
23+
24+
$time = microtime(true);
25+
try {
26+
$bolt->run('FOREACH ( i IN range(1,10000) |
27+
MERGE (d:Day {day: i})
28+
)');
29+
} catch (ConnectException $e) {
30+
$newTime = microtime(true);
31+
32+
$this->assertEqualsWithDelta(1.5, $newTime - $time, 0.2);
33+
}
34+
35+
self::assertTrue(true);
36+
}
37+
38+
/**
39+
* @throws Exception
40+
*/
41+
public function testSecondsTimeout(): void
42+
{
43+
$socket = new StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', (int) ($GLOBALS['NEO_PORT'] ?? 7687), 1);
44+
$bolt = new Bolt($socket);
45+
$bolt->init('Test/1.0', $GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']);
46+
47+
$time = microtime(true);
48+
try {
49+
$bolt->run('FOREACH ( i IN range(1,10000) |
50+
MERGE (d:Day {day: i})
51+
)');
52+
$this->assertTrue(false, 'No timeout error triggered');
53+
} catch (ConnectException $e) {
54+
$newTime = microtime(true);
55+
56+
$this->assertEqualsWithDelta(1.0, $newTime - $time, 0.2);
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)