Changeset 223:0cc6ebc4c1bd
- Timestamp:
- 18/04/11 23:34:14 (13 months ago)
- Author:
- Menno Smits <menno@…>
- Branch:
- default
- Message:
-
Changed IDLE support to use select instead of polling
Also made the idle live test a bit more robust when run against slower
servers.
- Files:
-
Legend:
- Unmodified
- Added
- Removed
-
|
r221
|
r223
|
|
| 6 | 6 | import response_lexer |
| 7 | 7 | from operator import itemgetter |
| | 8 | import select |
| 8 | 9 | import socket |
| 9 | | import time |
| 10 | 10 | import warnings |
| 11 | 11 | |
| … |
… |
|
| 112 | 112 | port = default_port |
| 113 | 113 | |
| | 114 | self.use_uid = use_uid |
| | 115 | self.ssl = ssl |
| | 116 | self.folder_encode = True |
| 114 | 117 | self._imap = ImapClass(host, port) |
| 115 | | self.use_uid = use_uid |
| 116 | | self.folder_encode = True |
| 117 | 118 | self._idle_tag = None |
| 118 | 119 | |
| … |
… |
|
| 341 | 342 | By default, this method will block until an IDLE response is |
| 342 | 343 | received. If timeout is provided, the call will block for at |
| 343 | | most this number of seconds (approximately) while waiting for |
| 344 | | an IDLE response. |
| | 344 | most this number of seconds while waiting for an IDLE response. |
| 345 | 345 | |
| 346 | 346 | The return value is a list of received IDLE responses. These |
| … |
… |
|
| 348 | 348 | example: |
| 349 | 349 | |
| 350 | | [(1, 'EXISTS'), |
| 351 | | ('OK', 'Still here'), |
| 352 | | (1, 'FETCH', ('FLAGS', ('\NotJunk',))), |
| 353 | | (0, 'EXPUNGE')] |
| 354 | | |
| 355 | | An attempt is made to group responses that were sent together |
| 356 | | by the server by waiting for a little longer after the first |
| 357 | | IDLE response is received. |
| 358 | | """ |
| 359 | | timeouts = 0 |
| 360 | | resps = [] |
| 361 | | start_t = time.time() |
| 362 | | |
| 363 | | def blocking_done(): |
| 364 | | # Wait for one timed out read to try group IDLE responses |
| 365 | | # that were sent together |
| 366 | | return resps and timeouts > 1 |
| 367 | | |
| 368 | | if timeout is None: |
| 369 | | done = blocking_done |
| 370 | | else: |
| 371 | | def done(): |
| 372 | | return blocking_done() or (time.time() - start_t >= timeout) |
| 373 | | |
| | 350 | [('OK', 'Still here'), |
| | 351 | (1, 'EXISTS'), |
| | 352 | (1, 'FETCH', ('FLAGS', ('\\NotJunk',)))] |
| | 353 | """ |
| 374 | 354 | # make the socket non-blocking so the timeout can be |
| 375 | 355 | # implemented for this call |
| 376 | | self._imap.sock.settimeout(0.1) |
| | 356 | if self.ssl: |
| | 357 | sock = self._imap.sslobj |
| | 358 | else: |
| | 359 | sock = self._imap.sock |
| | 360 | sock.setblocking(0) |
| 377 | 361 | try: |
| 378 | | while not done(): |
| 379 | | try: |
| 380 | | line = self._imap._get_line() |
| 381 | | except socket.timeout: |
| 382 | | timeouts += 1 |
| 383 | | else: |
| 384 | | resps.append(_parse_idle_response(line)) |
| | 362 | resps = [] |
| | 363 | rs, _, _ = select.select([sock], [], [], timeout) |
| | 364 | if rs: |
| | 365 | while True: |
| | 366 | try: |
| | 367 | line = self._imap._get_line() |
| | 368 | except (socket.timeout, socket.error): |
| | 369 | break |
| | 370 | else: |
| | 371 | resps.append(_parse_idle_response(line)) |
| 385 | 372 | return resps |
| 386 | 373 | finally: |
| 387 | | self._imap.sock.settimeout(None) |
| | 374 | sock.setblocking(1) |
| 388 | 375 | |
| 389 | 376 | def idle_done(self): |
-
|
r220
|
r223
|
|
| 10 | 10 | import sys |
| 11 | 11 | import time |
| 12 | | import threading |
| 13 | 12 | from datetime import datetime |
| 14 | 13 | from ConfigParser import SafeConfigParser, NoOptionError |
| … |
… |
|
| 466 | 465 | |
| 467 | 466 | # Check for the idle data |
| 468 | | responses = self.client.idle_check(timeout=1) |
| | 467 | responses = self.client.idle_check(timeout=5) |
| 469 | 468 | text, more_responses = self.client.idle_done() |
| 470 | 469 | self.assertIn((1, 'EXISTS'), responses) |
| 471 | | self.assertIn('idle', text.lower()) |
| 472 | | self.assertIsInstance(more_responses, list) |
| 473 | | |
| | 470 | self.assertTrue(isinstance(text, str)) |
| | 471 | self.assertGreater(len(text), 0) |
| | 472 | self.assertTrue(isinstance(more_responses, list)) |
| | 473 | |
| | 474 | # Check for IDLE data returned by idle_done() |
| 474 | 475 | self.client.idle() |
| | 476 | client2.select_folder('INBOX') |
| 475 | 477 | client2.append('INBOX', SIMPLE_MESSAGE) |
| 476 | | time.sleep(1) |
| | 478 | time.sleep(2) # Allow some time for the IDLE response to be sent |
| 477 | 479 | |
| 478 | 480 | text, responses = self.client.idle_done() |
| 479 | 481 | self.assertIn((2, 'EXISTS'), responses) |
| 480 | | self.assertIn('idle', text.lower()) |
| | 482 | self.assertTrue(isinstance(text, str)) |
| | 483 | self.assertGreater(len(text), 0) |
| | 484 | |
| 481 | 485 | |
| 482 | 486 | return LiveTest |