Package cherrypy :: Package process :: Module win32
[hide private]
[frames] | no frames]

Source Code for Module cherrypy.process.win32

  1  """Windows service. Requires pywin32.""" 
  2   
  3  import os 
  4  import win32api 
  5  import win32con 
  6  import win32event 
  7  import win32service 
  8  import win32serviceutil 
  9   
 10  from cherrypy.process import wspbus, plugins 
 11   
 12   
13 -class ConsoleCtrlHandler(plugins.SimplePlugin):
14 15 """A WSPBus plugin for handling Win32 console events (like Ctrl-C).""" 16
17 - def __init__(self, bus):
18 self.is_set = False 19 plugins.SimplePlugin.__init__(self, bus)
20
21 - def start(self):
22 if self.is_set: 23 self.bus.log('Handler for console events already set.', level=40) 24 return 25 26 result = win32api.SetConsoleCtrlHandler(self.handle, 1) 27 if result == 0: 28 self.bus.log('Could not SetConsoleCtrlHandler (error %r)' % 29 win32api.GetLastError(), level=40) 30 else: 31 self.bus.log('Set handler for console events.', level=40) 32 self.is_set = True
33
34 - def stop(self):
35 if not self.is_set: 36 self.bus.log('Handler for console events already off.', level=40) 37 return 38 39 try: 40 result = win32api.SetConsoleCtrlHandler(self.handle, 0) 41 except ValueError: 42 # "ValueError: The object has not been registered" 43 result = 1 44 45 if result == 0: 46 self.bus.log('Could not remove SetConsoleCtrlHandler (error %r)' % 47 win32api.GetLastError(), level=40) 48 else: 49 self.bus.log('Removed handler for console events.', level=40) 50 self.is_set = False
51
52 - def handle(self, event):
53 """Handle console control events (like Ctrl-C).""" 54 if event in (win32con.CTRL_C_EVENT, win32con.CTRL_LOGOFF_EVENT, 55 win32con.CTRL_BREAK_EVENT, win32con.CTRL_SHUTDOWN_EVENT, 56 win32con.CTRL_CLOSE_EVENT): 57 self.bus.log('Console event %s: shutting down bus' % event) 58 59 # Remove self immediately so repeated Ctrl-C doesn't re-call it. 60 try: 61 self.stop() 62 except ValueError: 63 pass 64 65 self.bus.exit() 66 # 'First to return True stops the calls' 67 return 1 68 return 0
69 70
71 -class Win32Bus(wspbus.Bus):
72 73 """A Web Site Process Bus implementation for Win32. 74 75 Instead of time.sleep, this bus blocks using native win32event objects. 76 """ 77
78 - def __init__(self):
79 self.events = {} 80 wspbus.Bus.__init__(self)
81
82 - def _get_state_event(self, state):
83 """Return a win32event for the given state (creating it if needed).""" 84 try: 85 return self.events[state] 86 except KeyError: 87 event = win32event.CreateEvent(None, 0, 0, 88 "WSPBus %s Event (pid=%r)" % 89 (state.name, os.getpid())) 90 self.events[state] = event 91 return event
92
93 - def _get_state(self):
94 return self._state
95
96 - def _set_state(self, value):
97 self._state = value 98 event = self._get_state_event(value) 99 win32event.PulseEvent(event)
100 state = property(_get_state, _set_state) 101
102 - def wait(self, state, interval=0.1, channel=None):
103 """Wait for the given state(s), KeyboardInterrupt or SystemExit. 104 105 Since this class uses native win32event objects, the interval 106 argument is ignored. 107 """ 108 if isinstance(state, (tuple, list)): 109 # Don't wait for an event that beat us to the punch ;) 110 if self.state not in state: 111 events = tuple([self._get_state_event(s) for s in state]) 112 win32event.WaitForMultipleObjects( 113 events, 0, win32event.INFINITE) 114 else: 115 # Don't wait for an event that beat us to the punch ;) 116 if self.state != state: 117 event = self._get_state_event(state) 118 win32event.WaitForSingleObject(event, win32event.INFINITE)
119 120
121 -class _ControlCodes(dict):
122 123 """Control codes used to "signal" a service via ControlService. 124 125 User-defined control codes are in the range 128-255. We generally use 126 the standard Python value for the Linux signal and add 128. Example: 127 128 >>> signal.SIGUSR1 129 10 130 control_codes['graceful'] = 128 + 10 131 """ 132
133 - def key_for(self, obj):
134 """For the given value, return its corresponding key.""" 135 for key, val in self.items(): 136 if val is obj: 137 return key 138 raise ValueError("The given object could not be found: %r" % obj)
139 140 control_codes = _ControlCodes({'graceful': 138}) 141 142
143 -def signal_child(service, command):
144 if command == 'stop': 145 win32serviceutil.StopService(service) 146 elif command == 'restart': 147 win32serviceutil.RestartService(service) 148 else: 149 win32serviceutil.ControlService(service, control_codes[command])
150 151
152 -class PyWebService(win32serviceutil.ServiceFramework):
153 154 """Python Web Service.""" 155 156 _svc_name_ = "Python Web Service" 157 _svc_display_name_ = "Python Web Service" 158 _svc_deps_ = None # sequence of service names on which this depends 159 _exe_name_ = "pywebsvc" 160 _exe_args_ = None # Default to no arguments 161 162 # Only exists on Windows 2000 or later, ignored on windows NT 163 _svc_description_ = "Python Web Service" 164
165 - def SvcDoRun(self):
166 from cherrypy import process 167 process.bus.start() 168 process.bus.block()
169
170 - def SvcStop(self):
171 from cherrypy import process 172 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 173 process.bus.exit()
174
175 - def SvcOther(self, control):
177 178 179 if __name__ == '__main__': 180 win32serviceutil.HandleCommandLine(PyWebService) 181