Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/process/win32.py

Revision 2012 (checked in by fumanchu, 3 weeks ago)

Doc tweaks.

  • Property svn:eol-style set to native
Line 
1 """Windows service. Requires pywin32."""
2
3 import os
4 import thread
5 import win32api
6 import win32con
7 import win32event
8 import win32service
9 import win32serviceutil
10
11 from cherrypy.process import wspbus, plugins
12
13
14 class ConsoleCtrlHandler(plugins.SimplePlugin):
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     """A Web Site Process Bus implementation for Win32.
73     
74     Instead of time.sleep, this bus blocks using native win32event objects.
75     """
76    
77     def __init__(self):
78         self.events = {}
79         wspbus.Bus.__init__(self)
80    
81     def _get_state_event(self, state):
82         """Return a win32event for the given state (creating it if needed)."""
83         try:
84             return self.events[state]
85         except KeyError:
86             event = win32event.CreateEvent(None, 0, 0,
87                                            u"WSPBus %s Event (pid=%r)" %
88                                            (state.name, os.getpid()))
89             self.events[state] = event
90             return event
91    
92     def _get_state(self):
93         return self._state
94     def _set_state(self, value):
95         self._state = value
96         event = self._get_state_event(value)
97         win32event.PulseEvent(event)
98     state = property(_get_state, _set_state)
99    
100     def wait(self, state, interval=0.1):
101         """Wait for the given state, KeyboardInterrupt or SystemExit.
102         
103         Since this class uses native win32event objects, the interval
104         argument is ignored.
105         """
106         # Don't wait for an event that beat us to the punch ;)
107         if self.state != state:
108             event = self._get_state_event(state)
109             win32event.WaitForSingleObject(event, win32event.INFINITE)
110
111
112 class _ControlCodes(dict):
113     """Control codes used to "signal" a service via ControlService.
114     
115     User-defined control codes are in the range 128-255. We generally use
116     the standard Python value for the Linux signal and add 128. Example:
117     
118         >>> signal.SIGUSR1
119         10
120         control_codes['graceful'] = 128 + 10
121     """
122    
123     def key_for(self, obj):
124         """For the given value, return its corresponding key."""
125         for key, val in self.iteritems():
126             if val is obj:
127                 return key
128         raise ValueError("The given object could not be found: %r" % obj)
129
130 control_codes = _ControlCodes({'graceful': 138})
131
132
133 def signal_child(service, command):
134     if command == 'stop':
135         win32serviceutil.StopService(service)
136     elif command == 'restart':
137         win32serviceutil.RestartService(service)
138     else:
139         win32serviceutil.ControlService(service, control_codes[command])
140
141
142 class PyWebService(win32serviceutil.ServiceFramework):
143     """Python Web Service."""
144    
145     _svc_name_ = "Python Web Service"
146     _svc_display_name_ = "Python Web Service"
147     _svc_deps_ = None        # sequence of service names on which this depends
148     _exe_name_ = "pywebsvc"
149     _exe_args_ = None        # Default to no arguments
150    
151     # Only exists on Windows 2000 or later, ignored on windows NT
152     _svc_description_ = "Python Web Service"
153    
154     def SvcDoRun(self):
155         from cherrypy import process
156         process.bus.start()
157         process.bus.block()
158    
159     def SvcStop(self):
160         from cherrypy import process
161         self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
162         process.bus.exit()
163    
164     def SvcOther(self, control):
165         process.bus.publish(control_codes.key_for(control))
166
167
168 if __name__ == '__main__':
169     win32serviceutil.HandleCommandLine(PyWebService)
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets