WSGIService.py (6384B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\net\WSGIService.py 2 import socket 3 import uthread 4 import blue 5 import log 6 from carbon.common.script.sys.service import Service 7 from carbon.common.script.sys.serviceConst import ROLE_SERVICE, SERVICE_RUNNING, SERVICE_STOPPED 8 from cherrypy import wsgiserver 9 from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter 10 11 class TaskletThreadPool(object): 12 13 def __init__(self, server, min = 10, max = -1): 14 self.server = server 15 self.min = min 16 17 def start(self): 18 pass 19 20 def stop(self, timeout = None): 21 pass 22 23 def put(self, obj): 24 if obj is wsgiserver._SHUTDOWNREQUEST: 25 return 26 t = uthread.new(self.Run, obj) 27 t.context = 'WSGIService::GenericTaskletThreadPool' 28 t.run() 29 30 def Run(self, conn): 31 conn.socket.setblockingsend(self.server.service.blockingSend) 32 try: 33 try: 34 conn.communicate() 35 finally: 36 conn.close() 37 38 except (KeyboardInterrupt, SystemExit) as exc: 39 self.server.interrupt = exc 40 41 42 wsgiserver.ThreadPool = TaskletThreadPool 43 44 class MyCherryPyWSGIServer(wsgiserver.CherryPyWSGIServer): 45 46 def bind(self, family, type, proto = 0): 47 super(MyCherryPyWSGIServer, self).bind(family, type, proto) 48 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0) 49 50 51 class CherryServerRunner(object): 52 53 def __init__(self, server, ntasks = 2, ssl = False): 54 self.server = server 55 self.running = False 56 self.ntasks = ntasks - 1 57 self.listening = 0 58 wsgiserver.LogError = self.LogCherryError 59 60 def Start(self): 61 self.running = True 62 uthread.new(self._ServeFirst) 63 if self.ntasks: 64 blue.pyos.synchro.SleepWallclock(1) 65 for t in xrange(self.ntasks): 66 self.listening += 1 67 uthread.new(self._ServeOthers) 68 69 def Stop(self): 70 self.running = False 71 self.server.stop() 72 del self.server 73 74 def LogCherryError(self): 75 log.LogException('CherryPy server internal error') 76 77 def _ServeFirst(self): 78 self.server.start() 79 80 def _ServeOthers(self): 81 try: 82 while self.running and self.server.ready: 83 self.server.tick() 84 85 finally: 86 self.running = False 87 self.listening -= 1 88 89 def on_wrap_start(self): 90 self.listening -= 1 91 if self.listening < self.ntasks: 92 self.listening += 1 93 uthread.new(self.wrap_task) 94 95 def on_wrap_done(self): 96 self.listening += 1 97 98 def wrap_task(self): 99 try: 100 if self.running and self.server.ready: 101 self.server.tick() 102 finally: 103 self.listening -= 1 104 105 106 class SSLAdapter(BuiltinSSLAdapter): 107 runner = None 108 109 def wrap(self, socket): 110 if self.runner: 111 self.runner.on_wrap_start() 112 result = super(SSLAdapter, self).wrap(socket) 113 if self.runner: 114 self.runner.on_wrap_done() 115 return result 116 117 118 class WSGIService(Service): 119 __exportedcalls__ = {'StartServer': [ROLE_SERVICE], 120 'StopServer': [ROLE_SERVICE]} 121 __guid__ = 'svc.WSGIService' 122 __dependencies__ = [] 123 __configvalues__ = {'blockingSend': False} 124 125 def OnSetConfigValue(self, key, value): 126 if key == 'blockingSend': 127 value = bool(value) 128 return value 129 130 def GetHtmlStateDetails(self, k, v, detailed): 131 if k == 'blockingSend': 132 return ('block on send', v) 133 134 def Run(self, memStream = None): 135 self.runners = {} 136 self.state = SERVICE_RUNNING 137 self.idx = 1 138 for key in self.__configvalues__.iterkeys(): 139 val = getattr(self, key) 140 self.OnSetConfigValue(key, val) 141 142 def Stop(self, memStream = None): 143 for runner in self.runners: 144 runner.Stop() 145 146 self.runners = {} 147 self.state = SERVICE_STOPPED 148 149 def Restart(self): 150 self.LogInfo('Restarting WSGIService') 151 for idx, (args, runners) in self.runners.items(): 152 self.LogInfo('Restarting WSGI Server ' + repr(args)) 153 self.StopRunners(runners) 154 self.runners[idx] = (args, self.StartServerInt(args)) 155 156 def StartServer(self, middleware, port, protocol = 'HTTP/1.1', enableIPv6 = True, serverName = None, ssl = None): 157 args = (middleware, 158 port, 159 protocol, 160 enableIPv6, 161 serverName, 162 ssl) 163 runners = self.StartServerInt(args) 164 idx = self.idx 165 self.idx += 1 166 self.runners[idx] = (args, runners) 167 return idx 168 169 def StopServer(self, idx): 170 self.StopRunners(self.runners[idx][1]) 171 del self.runners[idx] 172 173 def StartServerInt(self, args): 174 runners = self.StartCherry(*args) 175 for runner in runners: 176 runner.Start() 177 178 self.LogInfo('%s WSGI server running: %r' % (type, args)) 179 return runners 180 181 def StartCherry(self, middleware, port, protocol = 'HTTP/1.1', enableIPv6 = True, serverName = None, ssl = None): 182 if ssl: 183 184 def Adapter(runner): 185 certificate, private_key = ssl 186 adapter = SSLAdapter(certificate, private_key) 187 adapter.runner = runner 188 return adapter 189 190 else: 191 192 def Adapter(runner): 193 return None 194 195 if enableIPv6: 196 addr = ('::', port) 197 else: 198 addr = ('0.0.0.0', port) 199 server = MyCherryPyWSGIServer(addr, middleware, request_queue_size=socket.SOMAXCONN, server_name=serverName) 200 server.service = self 201 runner = CherryServerRunner(server, ssl=ssl) 202 server.ssl_adapter = Adapter(runner) 203 runners = (runner,) 204 if enableIPv6 and not hasattr(socket, 'IPV6_V6ONLY'): 205 addr = ('0.0.0.0', port) 206 server = MyCherryPyWSGIServer(addr, middleware, request_queue_size=socket.SOMAXCONN, server_name=serverName) 207 server.service = self 208 runner = CherryServerRunner(server, ssl=ssl) 209 server.ssl_adapter = Adapter(runner) 210 runners += (runner,) 211 return runners 212 213 def StopRunners(self, runners): 214 for runner in runners: 215 runner.Stop()