File tree Expand file tree Collapse file tree 3 files changed +77
-0
lines changed
Expand file tree Collapse file tree 3 files changed +77
-0
lines changed Original file line number Diff line number Diff line change @@ -385,6 +385,15 @@ func (c *Client) Mailbox() *SelectedMailbox {
385385 return c .mailbox
386386}
387387
388+ // Closed returns a channel that is closed when the connection is closed.
389+ //
390+ // This channel cannot be used to reliably determine whether a connection is healthy. If
391+ // the underlying connection times out, the channel will be closed eventually, but not
392+ // immediately. To check whether the connection is healthy, send a command (such as Noop).
393+ func (c * Client ) Closed () <- chan struct {} {
394+ return c .decCh
395+ }
396+
388397// Close immediately closes the connection.
389398func (c * Client ) Close () error {
390399 c .mutex .Lock ()
Original file line number Diff line number Diff line change 1+ package imapclient_test
2+
3+ import (
4+ "testing"
5+ "time"
6+
7+ "github.com/emersion/go-imap/v2"
8+ )
9+
10+ // TestClient_Closed tests that the Closed() channel is closed when the
11+ // connection is explicitly closed via Close().
12+ func TestClient_Closed (t * testing.T ) {
13+ client , server := newClientServerPair (t , imap .ConnStateAuthenticated )
14+ defer server .Close ()
15+
16+ closedCh := client .Closed ()
17+ if closedCh == nil {
18+ t .Fatal ("Closed() returned nil channel" )
19+ }
20+
21+ select {
22+ case <- closedCh :
23+ t .Fatal ("Closed() channel closed before calling Close()" )
24+ default : // Expected
25+ }
26+
27+ if err := client .Close (); err != nil {
28+ t .Fatalf ("Close() = %v" , err )
29+ }
30+
31+ select {
32+ case <- closedCh :
33+ t .Log ("Closed() channel properly closed after Close()" )
34+ case <- time .After (2 * time .Second ):
35+ t .Fatal ("Closed() channel not closed after Close()" )
36+ }
37+ }
Original file line number Diff line number Diff line change @@ -378,3 +378,34 @@ func ExampleClient_Authenticate_oauth() {
378378 log .Fatalf ("authentication failed: %v" , err )
379379 }
380380}
381+
382+ func ExampleClient_Closed () {
383+ c , err := imapclient .DialTLS ("mail.example.org:993" , nil )
384+ if err != nil {
385+ log .Fatalf ("failed to dial IMAP server: %v" , err )
386+ }
387+
388+ selected := false
389+
390+ go func (c * imapclient.Client ) {
391+ if err := c .Login ("root" , "asdf" ).Wait (); err != nil {
392+ log .Fatalf ("failed to login: %v" , err )
393+ }
394+
395+ if _ , err := c .Select ("INBOX" , nil ).Wait (); err != nil {
396+ log .Fatalf ("failed to select INBOX: %v" , err )
397+ }
398+
399+ selected = true
400+
401+ c .Close ()
402+ }(c )
403+
404+ // This channel shall be closed when the connection is closed.
405+ <- c .Closed ()
406+ log .Println ("Connection has been closed" )
407+
408+ if ! selected {
409+ log .Fatalf ("Connection was closed before selecting mailbox" )
410+ }
411+ }
You can’t perform that action at this time.
0 commit comments