Skip to content

Commit e1abaf0

Browse files
authored
Merge pull request #99 from DirectoryTree/stop-idle
Add ability to break out of idle using timeout callback
2 parents 84e8a80 + f64e073 commit e1abaf0

File tree

4 files changed

+27
-13
lines changed

4 files changed

+27
-13
lines changed

src/Folder.php

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

33
namespace DirectoryTree\ImapEngine;
44

5+
use Closure;
56
use DirectoryTree\ImapEngine\Connection\ImapQueryBuilder;
67
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
78
use DirectoryTree\ImapEngine\Enums\ImapFetchIdentifier;
@@ -92,12 +93,17 @@ public function messages(): MessageQuery
9293
/**
9394
* {@inheritDoc}
9495
*/
95-
public function idle(callable $callback, ?callable $query = null, int $timeout = 300): void
96+
public function idle(callable $callback, ?callable $query = null, callable|int $timeout = 300): void
9697
{
9798
if (! in_array('IDLE', $this->mailbox->capabilities())) {
9899
throw new ImapCapabilityException('Unable to IDLE. IMAP server does not support IDLE capability.');
99100
}
100101

102+
// Normalize timeout into a closure.
103+
if (is_callable($timeout) && ! $timeout instanceof Closure) {
104+
$timeout = $timeout(...);
105+
}
106+
101107
// The message query to use when fetching messages.
102108
$query ??= fn (MessageQuery $query) => $query;
103109

src/FolderInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function messages(): MessageQueryInterface;
4444
/**
4545
* Begin idling on the current folder.
4646
*/
47-
public function idle(callable $callback, ?callable $query = null, int $timeout = 300): void;
47+
public function idle(callable $callback, ?callable $query = null, callable|int $timeout = 300): void;
4848

4949
/**
5050
* Move or rename the current folder.

src/Idle.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Carbon\Carbon;
66
use Carbon\CarbonInterface;
7+
use Closure;
78
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
89
use DirectoryTree\ImapEngine\Exceptions\Exception;
910
use DirectoryTree\ImapEngine\Exceptions\ImapConnectionClosedException;
@@ -18,7 +19,7 @@ class Idle
1819
public function __construct(
1920
protected Mailbox $mailbox,
2021
protected string $folder,
21-
protected int $timeout,
22+
protected Closure|int $timeout,
2223
) {}
2324

2425
/**
@@ -36,10 +37,7 @@ public function await(callable $callback): void
3637
{
3738
$this->connect();
3839

39-
// Loop indefinitely, restarting IDLE sessions as needed.
40-
while (true) {
41-
$ttl = $this->getNextTimeout();
42-
40+
while ($ttl = $this->getNextTimeout()) {
4341
try {
4442
$this->listen($callback, $ttl);
4543
} catch (ImapConnectionTimedOutException) {
@@ -56,7 +54,7 @@ public function await(callable $callback): void
5654
protected function listen(callable $callback, CarbonInterface $ttl): void
5755
{
5856
// Iterate over responses yielded by the idle generator.
59-
foreach ($this->idle() as $response) {
57+
foreach ($this->idle($ttl) as $response) {
6058
if (! $response instanceof UntaggedResponse) {
6159
continue;
6260
}
@@ -69,6 +67,10 @@ protected function listen(callable $callback, CarbonInterface $ttl): void
6967
$ttl = $this->getNextTimeout();
7068
}
7169

70+
if ($ttl === false) {
71+
break;
72+
}
73+
7274
// If we've been idle too long, break out to restart the session.
7375
if (Carbon::now()->greaterThanOrEqualTo($ttl)) {
7476
$this->restart();
@@ -145,16 +147,22 @@ protected function done(): void
145147
/**
146148
* Begin a new IDLE session as a generator.
147149
*/
148-
protected function idle(): Generator
150+
protected function idle(CarbonInterface $ttl): Generator
149151
{
150-
yield from $this->mailbox->connection()->idle($this->timeout);
152+
yield from $this->mailbox->connection()->idle(
153+
(int) Carbon::now()->diffInSeconds($ttl, true)
154+
);
151155
}
152156

153157
/**
154158
* Get the next timeout as a Carbon instance.
155159
*/
156-
protected function getNextTimeout(): CarbonInterface
160+
protected function getNextTimeout(): CarbonInterface|false
157161
{
158-
return Carbon::now()->addSeconds($this->timeout);
162+
if (is_numeric($seconds = value($this->timeout))) {
163+
return Carbon::now()->addSeconds(abs($seconds));
164+
}
165+
166+
return false;
159167
}
160168
}

src/Testing/FakeFolder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function messages(): MessageQueryInterface
8989
/**
9090
* {@inheritDoc}
9191
*/
92-
public function idle(callable $callback, ?callable $query = null, int $timeout = 300): void
92+
public function idle(callable $callback, ?callable $query = null, callable|int $timeout = 300): void
9393
{
9494
foreach ($this->messages as $message) {
9595
$callback($message);

0 commit comments

Comments
 (0)