Index: third_party/cherrypy/process/win32.py |
=================================================================== |
--- third_party/cherrypy/process/win32.py (revision 0) |
+++ third_party/cherrypy/process/win32.py (revision 0) |
@@ -0,0 +1,174 @@ |
+"""Windows service. Requires pywin32.""" |
+ |
+import os |
+import win32api |
+import win32con |
+import win32event |
+import win32service |
+import win32serviceutil |
+ |
+from cherrypy.process import wspbus, plugins |
+ |
+ |
+class ConsoleCtrlHandler(plugins.SimplePlugin): |
+ """A WSPBus plugin for handling Win32 console events (like Ctrl-C).""" |
+ |
+ def __init__(self, bus): |
+ self.is_set = False |
+ plugins.SimplePlugin.__init__(self, bus) |
+ |
+ def start(self): |
+ if self.is_set: |
+ self.bus.log('Handler for console events already set.', level=40) |
+ return |
+ |
+ result = win32api.SetConsoleCtrlHandler(self.handle, 1) |
+ if result == 0: |
+ self.bus.log('Could not SetConsoleCtrlHandler (error %r)' % |
+ win32api.GetLastError(), level=40) |
+ else: |
+ self.bus.log('Set handler for console events.', level=40) |
+ self.is_set = True |
+ |
+ def stop(self): |
+ if not self.is_set: |
+ self.bus.log('Handler for console events already off.', level=40) |
+ return |
+ |
+ try: |
+ result = win32api.SetConsoleCtrlHandler(self.handle, 0) |
+ except ValueError: |
+ # "ValueError: The object has not been registered" |
+ result = 1 |
+ |
+ if result == 0: |
+ self.bus.log('Could not remove SetConsoleCtrlHandler (error %r)' % |
+ win32api.GetLastError(), level=40) |
+ else: |
+ self.bus.log('Removed handler for console events.', level=40) |
+ self.is_set = False |
+ |
+ def handle(self, event): |
+ """Handle console control events (like Ctrl-C).""" |
+ if event in (win32con.CTRL_C_EVENT, win32con.CTRL_LOGOFF_EVENT, |
+ win32con.CTRL_BREAK_EVENT, win32con.CTRL_SHUTDOWN_EVENT, |
+ win32con.CTRL_CLOSE_EVENT): |
+ self.bus.log('Console event %s: shutting down bus' % event) |
+ |
+ # Remove self immediately so repeated Ctrl-C doesn't re-call it. |
+ try: |
+ self.stop() |
+ except ValueError: |
+ pass |
+ |
+ self.bus.exit() |
+ # 'First to return True stops the calls' |
+ return 1 |
+ return 0 |
+ |
+ |
+class Win32Bus(wspbus.Bus): |
+ """A Web Site Process Bus implementation for Win32. |
+ |
+ Instead of time.sleep, this bus blocks using native win32event objects. |
+ """ |
+ |
+ def __init__(self): |
+ self.events = {} |
+ wspbus.Bus.__init__(self) |
+ |
+ def _get_state_event(self, state): |
+ """Return a win32event for the given state (creating it if needed).""" |
+ try: |
+ return self.events[state] |
+ except KeyError: |
+ event = win32event.CreateEvent(None, 0, 0, |
+ "WSPBus %s Event (pid=%r)" % |
+ (state.name, os.getpid())) |
+ self.events[state] = event |
+ return event |
+ |
+ def _get_state(self): |
+ return self._state |
+ def _set_state(self, value): |
+ self._state = value |
+ event = self._get_state_event(value) |
+ win32event.PulseEvent(event) |
+ state = property(_get_state, _set_state) |
+ |
+ def wait(self, state, interval=0.1, channel=None): |
+ """Wait for the given state(s), KeyboardInterrupt or SystemExit. |
+ |
+ Since this class uses native win32event objects, the interval |
+ argument is ignored. |
+ """ |
+ if isinstance(state, (tuple, list)): |
+ # Don't wait for an event that beat us to the punch ;) |
+ if self.state not in state: |
+ events = tuple([self._get_state_event(s) for s in state]) |
+ win32event.WaitForMultipleObjects(events, 0, win32event.INFINITE) |
+ else: |
+ # Don't wait for an event that beat us to the punch ;) |
+ if self.state != state: |
+ event = self._get_state_event(state) |
+ win32event.WaitForSingleObject(event, win32event.INFINITE) |
+ |
+ |
+class _ControlCodes(dict): |
+ """Control codes used to "signal" a service via ControlService. |
+ |
+ User-defined control codes are in the range 128-255. We generally use |
+ the standard Python value for the Linux signal and add 128. Example: |
+ |
+ >>> signal.SIGUSR1 |
+ 10 |
+ control_codes['graceful'] = 128 + 10 |
+ """ |
+ |
+ def key_for(self, obj): |
+ """For the given value, return its corresponding key.""" |
+ for key, val in self.items(): |
+ if val is obj: |
+ return key |
+ raise ValueError("The given object could not be found: %r" % obj) |
+ |
+control_codes = _ControlCodes({'graceful': 138}) |
+ |
+ |
+def signal_child(service, command): |
+ if command == 'stop': |
+ win32serviceutil.StopService(service) |
+ elif command == 'restart': |
+ win32serviceutil.RestartService(service) |
+ else: |
+ win32serviceutil.ControlService(service, control_codes[command]) |
+ |
+ |
+class PyWebService(win32serviceutil.ServiceFramework): |
+ """Python Web Service.""" |
+ |
+ _svc_name_ = "Python Web Service" |
+ _svc_display_name_ = "Python Web Service" |
+ _svc_deps_ = None # sequence of service names on which this depends |
+ _exe_name_ = "pywebsvc" |
+ _exe_args_ = None # Default to no arguments |
+ |
+ # Only exists on Windows 2000 or later, ignored on windows NT |
+ _svc_description_ = "Python Web Service" |
+ |
+ def SvcDoRun(self): |
+ from cherrypy import process |
+ process.bus.start() |
+ process.bus.block() |
+ |
+ def SvcStop(self): |
+ from cherrypy import process |
+ self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) |
+ process.bus.exit() |
+ |
+ def SvcOther(self, control): |
+ process.bus.publish(control_codes.key_for(control)) |
+ |
+ |
+if __name__ == '__main__': |
+ win32serviceutil.HandleCommandLine(PyWebService) |
Property changes on: third_party/cherrypy/process/win32.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |