Skip to content

Commit 3e0ded7

Browse files
committed
Refactor idle to use a generator
1 parent 2019b03 commit 3e0ded7

File tree

3 files changed

+54
-70
lines changed

3 files changed

+54
-70
lines changed

src/Connection/ConnectionInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use DirectoryTree\ImapEngine\Collections\ResponseCollection;
66
use DirectoryTree\ImapEngine\Connection\Responses\TaggedResponse;
77
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
8+
use Generator;
89

910
interface ConnectionInterface
1011
{
@@ -66,7 +67,7 @@ public function startTls(): void;
6667
*
6768
* @see https://datatracker.ietf.org/doc/html/rfc9051#name-idle-command
6869
*/
69-
public function idle(int $timeout): void;
70+
public function idle(int $timeout): Generator;
7071

7172
/**
7273
* Send a "DONE" command.

src/Connection/ImapConnection.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use DirectoryTree\ImapEngine\Exceptions\Exception;
1717
use DirectoryTree\ImapEngine\Exceptions\RuntimeException;
1818
use DirectoryTree\ImapEngine\Support\Str;
19+
use Generator;
1920

2021
class ImapConnection implements ConnectionInterface
2122
{
@@ -489,7 +490,7 @@ public function noop(): TaggedResponse
489490
/**
490491
* {@inheritDoc}
491492
*/
492-
public function idle(int $timeout): void
493+
public function idle(int $timeout): Generator
493494
{
494495
$this->stream->setTimeout($timeout);
495496

@@ -499,6 +500,10 @@ public function idle(int $timeout): void
499500
fn (ContinuationResponse $response) => true,
500501
fn (ContinuationResponse $response) => CommandFailedException::make(new ImapCommand('', 'IDLE'), $response),
501502
);
503+
504+
while ($response = $this->nextReply()) {
505+
yield $response;
506+
}
502507
}
503508

504509
/**

src/Idle.php

Lines changed: 46 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
namespace DirectoryTree\ImapEngine;
44

55
use Carbon\Carbon;
6-
use DirectoryTree\ImapEngine\Connection\Responses\Response;
76
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
87
use DirectoryTree\ImapEngine\Exceptions\ConnectionClosedException;
98
use DirectoryTree\ImapEngine\Exceptions\ConnectionTimedOutException;
109
use DirectoryTree\ImapEngine\Exceptions\Exception;
10+
use Generator;
1111

1212
class Idle
1313
{
@@ -35,33 +35,27 @@ public function await(callable $callback): void
3535
{
3636
$this->connect();
3737

38-
$this->idle();
39-
40-
$ttl = $this->getNextTimeout();
41-
42-
try {
43-
$this->listen($callback, $ttl);
44-
} catch (ConnectionTimedOutException) {
45-
$this->reidle();
46-
47-
$ttl = $this->getNextTimeout();
48-
49-
$this->listen($callback, $ttl);
50-
} catch (ConnectionClosedException) {
51-
$this->reconnect();
52-
38+
// Loop indefinitely, restarting IDLE sessions as needed.
39+
while (true) {
5340
$ttl = $this->getNextTimeout();
5441

55-
$this->listen($callback, $ttl);
42+
try {
43+
$this->listen($callback, $ttl);
44+
} catch (ConnectionTimedOutException) {
45+
$this->restart();
46+
} catch (ConnectionClosedException) {
47+
$this->reconnect();
48+
}
5649
}
5750
}
5851

5952
/**
60-
* Start listening for new messages.
53+
* Start listening for new messages using the idle() generator.
6154
*/
6255
protected function listen(callable $callback, Carbon $ttl): void
6356
{
64-
while ($response = $this->getNextReply()) {
57+
// Iterate over responses yielded by the idle generator.
58+
foreach ($this->idle() as $response) {
6559
if (! $response instanceof UntaggedResponse) {
6660
continue;
6761
}
@@ -74,77 +68,69 @@ protected function listen(callable $callback, Carbon $ttl): void
7468
$ttl = $this->getNextTimeout();
7569
}
7670

77-
if (! Carbon::now()->greaterThanOrEqualTo($ttl)) {
78-
continue;
79-
}
71+
// If we've been idle too long, break out to restart the session.
72+
if (Carbon::now()->greaterThanOrEqualTo($ttl)) {
73+
$this->restart();
8074

81-
try {
82-
// If we've been idle too long, we'll send a DONE and re-IDLE.
83-
// This will keep the server from killing the connection.
84-
// Some Servers require this to avoid disconnection.
85-
$this->done();
86-
} catch (Exception) {
87-
// If done fails, we're likely already disconnected.
88-
// We'll attempt to reconnect and restart the IDLE.
89-
$this->reconnect();
75+
break;
9076
}
91-
92-
$this->idle();
93-
94-
$ttl = $this->getNextTimeout();
9577
}
9678
}
9779

9880
/**
99-
* Connect the client and begin IDLE.
81+
* Get the folder to idle.
10082
*/
101-
protected function connect(): void
83+
protected function folder(): Folder
10284
{
103-
$this->mailbox->connect();
104-
105-
$this->mailbox->select($this->folder(), true);
85+
return $this->mailbox->folders()->find($this->folder);
10686
}
10787

10888
/**
109-
* Reconnect the client and restart IDLE.
89+
* Issue a done command and restart the idle session.
11090
*/
111-
protected function reconnect(): void
91+
protected function restart(): void
11292
{
113-
$this->mailbox->disconnect();
114-
115-
$this->connect();
93+
try {
94+
// Send DONE to terminate the current IDLE session gracefully.
95+
$this->done();
96+
} catch (Exception) {
97+
$this->reconnect();
98+
}
11699
}
117100

118101
/**
119-
* Disconnect the client.
102+
* Reconnect the client and restart the idle session.
120103
*/
121-
protected function disconnect(): void
104+
protected function reconnect(): void
122105
{
123-
$this->done();
124-
125106
$this->mailbox->disconnect();
107+
108+
$this->connect();
126109
}
127110

128111
/**
129-
* Get the folder to idle.
112+
* Connect the client and select the folder to idle.
130113
*/
131-
protected function folder(): Folder
114+
protected function connect(): void
132115
{
133-
return $this->mailbox->folders()->find($this->folder);
116+
$this->mailbox->connect();
117+
118+
$this->mailbox->select($this->folder(), true);
134119
}
135120

136121
/**
137-
* End the current IDLE session and start a new one.
122+
* Disconnect the client.
138123
*/
139-
protected function reidle(): void
124+
protected function disconnect(): void
140125
{
141126
try {
127+
// Attempt to terminate IDLE gracefully.
142128
$this->done();
143129
} catch (Exception) {
144-
$this->reconnect();
130+
// Do nothing.
145131
}
146132

147-
$this->idle();
133+
$this->mailbox->disconnect();
148134
}
149135

150136
/**
@@ -156,23 +142,15 @@ protected function done(): void
156142
}
157143

158144
/**
159-
* Being a new IDLE session.
160-
*/
161-
protected function idle(): void
162-
{
163-
$this->mailbox->connection()->idle($this->timeout);
164-
}
165-
166-
/**
167-
* Get the next reply from the connection.
145+
* Begin a new IDLE session as a generator.
168146
*/
169-
protected function getNextReply(): Response
147+
protected function idle(): Generator
170148
{
171-
return $this->mailbox->connection()->nextReply();
149+
yield from $this->mailbox->connection()->idle($this->timeout);
172150
}
173151

174152
/**
175-
* Get the next timeout.
153+
* Get the next timeout as a Carbon instance.
176154
*/
177155
protected function getNextTimeout(): Carbon
178156
{

0 commit comments

Comments
 (0)