diff --git a/src/calibre/srv/loop.py b/src/calibre/srv/loop.py index 8d3d5308bd..58828363b2 100644 --- a/src/calibre/srv/loop.py +++ b/src/calibre/srv/loop.py @@ -12,10 +12,9 @@ from Queue import Queue, Full from threading import Thread, current_thread, Lock from io import DEFAULT_BUFFER_SIZE, BytesIO -from calibre.constants import iswindows from calibre.srv.errors import MaxSizeExceeded from calibre.srv.opts import Options -from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking, Corked +from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking, Corked, HandleInterrupt from calibre.utils.socket_inheritance import set_socket_inherit from calibre.utils.logging import ThreadSafeLog @@ -321,54 +320,6 @@ class SocketFile(object): # {{{ # }}} -class HandleInterrupt(object): # {{{ - - # On windows socket functions like accept(), recv(), send() are not - # interrupted by a Ctrl-C in the console. So to make Ctrl-C work we have to - # use this special context manager. See the echo server example at the - # bottom of this file for how to use it. - - def __init__(self, action): - if not iswindows: - return # Interrupts work fine on POSIX - self.action = action - from ctypes import WINFUNCTYPE, windll - from ctypes.wintypes import BOOL, DWORD - - kernel32 = windll.LoadLibrary('kernel32') - - # - PHANDLER_ROUTINE = WINFUNCTYPE(BOOL, DWORD) - self.SetConsoleCtrlHandler = kernel32.SetConsoleCtrlHandler - self.SetConsoleCtrlHandler.argtypes = (PHANDLER_ROUTINE, BOOL) - self.SetConsoleCtrlHandler.restype = BOOL - - @PHANDLER_ROUTINE - def handle(event): - if event == 0: # CTRL_C_EVENT - if self.action is not None: - self.action() - self.action = None - # Typical C implementations would return 1 to indicate that - # the event was processed and other control handlers in the - # stack should not be executed. However, that would - # prevent the Python interpreter's handler from translating - # CTRL-C to a `KeyboardInterrupt` exception, so we pretend - # that we didn't handle it. - return 0 - self.handle = handle - - def __enter__(self): - if iswindows: - if self.SetConsoleCtrlHandler(self.handle, 1) == 0: - raise WindowsError() - - def __exit__(self, *args): - if iswindows: - if self.SetConsoleCtrlHandler(self.handle, 0) == 0: - raise WindowsError() -# }}} - class Connection(object): # {{{ ' A thin wrapper around an active socket ' diff --git a/src/calibre/srv/utils.py b/src/calibre/srv/utils.py index 840d6ef44b..60d6ced1d1 100644 --- a/src/calibre/srv/utils.py +++ b/src/calibre/srv/utils.py @@ -12,6 +12,8 @@ from urlparse import parse_qs import repr as reprlib from email.utils import formatdate +from calibre.constants import iswindows + def http_date(timeval=None): return type('')(formatdate(timeval=timeval, usegmt=True)) @@ -176,3 +178,52 @@ def eintr_retry_call(func, *args, **kwargs): if getattr(e, 'errno', None) in socket_errors_eintr: continue raise + +class HandleInterrupt(object): # {{{ + + # On windows socket functions like accept(), recv(), send() are not + # interrupted by a Ctrl-C in the console. So to make Ctrl-C work we have to + # use this special context manager. See the echo server example at the + # bottom of this file for how to use it. + + def __init__(self, action): + if not iswindows: + return # Interrupts work fine on POSIX + self.action = action + from ctypes import WINFUNCTYPE, windll + from ctypes.wintypes import BOOL, DWORD + + kernel32 = windll.LoadLibrary('kernel32') + + # + PHANDLER_ROUTINE = WINFUNCTYPE(BOOL, DWORD) + self.SetConsoleCtrlHandler = kernel32.SetConsoleCtrlHandler + self.SetConsoleCtrlHandler.argtypes = (PHANDLER_ROUTINE, BOOL) + self.SetConsoleCtrlHandler.restype = BOOL + + @PHANDLER_ROUTINE + def handle(event): + if event == 0: # CTRL_C_EVENT + if self.action is not None: + self.action() + self.action = None + # Typical C implementations would return 1 to indicate that + # the event was processed and other control handlers in the + # stack should not be executed. However, that would + # prevent the Python interpreter's handler from translating + # CTRL-C to a `KeyboardInterrupt` exception, so we pretend + # that we didn't handle it. + return 0 + self.handle = handle + + def __enter__(self): + if iswindows: + if self.SetConsoleCtrlHandler(self.handle, 1) == 0: + raise WindowsError() + + def __exit__(self, *args): + if iswindows: + if self.SetConsoleCtrlHandler(self.handle, 0) == 0: + raise WindowsError() +# }}} +