def serve(cls, endpoint, handler): if isinstance(endpoint, Server): assert False, "TODO" else: #default is to server using SocketServer, endpoint is addresss from concurrence.io.socket import SocketServer socket_server = SocketServer(endpoint, handler) socket_server.serve() return socket_server
class WebService(Loggable): "Abstract web service serving HTTP requests" def __init__(self, inst, service_id, service_type, fqn="mg.core.web.WebService"): Loggable.__init__(self, fqn) self.server = WSGIServer(self.request) self.socket_server = None self.inst = inst self.addr = None self.id = service_id self.type = service_type self.svcinfo = {} self.reqs = 0 self.old_reqstat = self.get_reqstat() def get_reqstat(self): now = time.time() return (now, self.reqs) def serve_socket(self, addr, socket): "Runs a WebService instance accepting connections from given socket" try: from concurrence.io.socket import SocketServer self.socket_server = SocketServer(socket, self.server.handle_connection) self.socket_server.serve() self.info("serving %s:%d on shared socket", addr[0], addr[1]) self.addr = (addr[0], addr[1]) except Exception as err: self.exception("Listen %s:%d: %s", addr[0], addr[1], err) os._exit(1) def stop(self): if self.socket_server: self.socket_server.close() self.socket_server = None def serve(self, addr): "Runs a WebService instance listening given port" try: self.socket_server = self.server.serve(addr) self.info("serving %s:%d", addr[0], addr[1]) self.addr = (addr[0], addr[1]) except Exception as err: self.exception("Listen %s:%d: %s", addr[0], addr[1], err) os._exit(1) def serve_any_port(self, hostaddr=None, port_min=4000, port_max=4999): "Runs a WebService instance listening arbitrarily selected port" if hostaddr is None: hostaddr = self.inst.instaddr for port in xrange(port_min, port_max + 1): try: try: self.socket_server = self.server.serve((hostaddr, port)) self.info("serving %s:%d", hostaddr, port) self.addr = (hostaddr, port) return port except socket.error as err: if err.errno == 98: pass else: raise except Exception as err: self.exception("Listen %s:%d: %s (%s)", hostaddr, port, err, type(err)) os._exit(1) self.error("Couldn't find any available port") os._exit(1) def req(self): try: return Tasklet.current().req except AttributeError: raise RuntimeError("Module.req() called outside of a web handler") def request(self, environ, start_response): "Process single HTTP request" request = Request(environ, start_response) Tasklet.current().req = request try: # remove doubling, leading and trailing slashes, unquote and convert to utf-8 try: uri = re.sub(r'^/*(.*?)/*$', r'\1', re.sub(r'/{2+}', '/', mg.core.tools.urldecode(request.uri()))) except UnicodeDecodeError: return request.send_response("404 Not Found", request.headers, "<html><body><h1>404 Not Found</h1></body></html>") else: return self.request_uri(request, uri) except RuntimeError as e: self.error(e) e = u"%s" % e try: if getattr(request, "upload_handler", None): return request.uresponse(htmlescape(json.dumps({"success": False, "errormsg": e}))) except Exception as e2: self.exception(e2) if type(e) == unicode: e = e.encode("utf-8") return request.send_response("500 Internal Server Error", request.headers, "<html><body><h1>500 Internal Server Error</h1>%s</body></html>" % htmlescape(e)) except Exception as e: try: self.exception(e) except Exception as e2: print "Unhandled exception during logging: %s" % e2 print traceback.format_exc() try: if getattr(request, "upload_handler", None): return request.uresponse(htmlescape(json.dumps({"success": False, "errormsg": "Internal Server Error"}))) except Exception as e2: self.exception(e2) return request.internal_server_error() def request_uri(self, request, uri): "Process HTTP request after URI was extracted, normalized and converted to utf-8" self.reqs += 1 # /service/call/<svcid>/method m = re_service_call.match(uri) if m: (svcid, remainder) = m.group(1, 2) if svcid != self.id: return request.bad_request() uri = remainder # / if uri == "": res = self.req_handler(request, "index", "index", "") if res is not None: return res # /group/hook[/args] m = re_group_hook_args.match(uri) if m: (group, hook, args) = m.group(1, 2, 3) if args is None: args = "" res = self.req_handler(request, group, hook, args) if res is not None: return res # /group/<SOMETHING_UNHANDLED> m = re_group_something_unparsed.match(uri) if m: (group, args) = m.group(1, 2) res = self.req_handler(request, group, "handler", args) if res is not None: return res # /group m = re_group.match(uri) if m: res = self.req_handler(request, uri, "index", "") if res is not None: return res return request.not_found() def publish(self, svcinfo): "Service may fill svcinfo dict with any additional properties that will be announced in service record" old_reqstat = self.old_reqstat new_reqstat = self.get_reqstat() elapsed = new_reqstat[0] - old_reqstat[0] if elapsed > 3: svcinfo["svc-rps"] = (new_reqstat[1] - old_reqstat[1]) / elapsed self.old_reqstat = new_reqstat def set(self, key, val): self.svcinfo[key] = val def svc_req_handler(self, request, hook): return None
class WebService(Loggable): "Abstract web service serving HTTP requests" def __init__(self, inst, service_id, service_type, fqn="mg.core.web.WebService"): Loggable.__init__(self, fqn) self.server = WSGIServer(self.request) self.socket_server = None self.inst = inst self.addr = None self.id = service_id self.type = service_type self.svcinfo = {} self.reqs = 0 self.old_reqstat = self.get_reqstat() def get_reqstat(self): now = time.time() return (now, self.reqs) def serve_socket(self, addr, socket): "Runs a WebService instance accepting connections from given socket" try: from concurrence.io.socket import SocketServer self.socket_server = SocketServer(socket, self.server.handle_connection) self.socket_server.serve() self.info("serving %s:%d on shared socket", addr[0], addr[1]) self.addr = (addr[0], addr[1]) except Exception as err: self.exception("Listen %s:%d: %s", addr[0], addr[1], err) os._exit(1) def stop(self): if self.socket_server: self.socket_server.close() self.socket_server = None def serve(self, addr): "Runs a WebService instance listening given port" try: self.socket_server = self.server.serve(addr) self.info("serving %s:%d", addr[0], addr[1]) self.addr = (addr[0], addr[1]) except Exception as err: self.exception("Listen %s:%d: %s", addr[0], addr[1], err) os._exit(1) def serve_any_port(self, hostaddr=None, port_min=4000, port_max=4999): "Runs a WebService instance listening arbitrarily selected port" if hostaddr is None: hostaddr = self.inst.instaddr for port in xrange(port_min, port_max + 1): try: try: self.socket_server = self.server.serve((hostaddr, port)) self.info("serving %s:%d", hostaddr, port) self.addr = (hostaddr, port) return port except socket.error as err: if err.errno == 98: pass else: raise except Exception as err: self.exception("Listen %s:%d: %s (%s)", hostaddr, port, err, type(err)) os._exit(1) self.error("Couldn't find any available port") os._exit(1) def req(self): try: return Tasklet.current().req except AttributeError: raise RuntimeError("Module.req() called outside of a web handler") def request(self, environ, start_response): "Process single HTTP request" request = Request(environ, start_response) Tasklet.current().req = request try: # remove doubling, leading and trailing slashes, unquote and convert to utf-8 try: uri = re.sub( r'^/*(.*?)/*$', r'\1', re.sub(r'/{2+}', '/', mg.core.tools.urldecode(request.uri()))) except UnicodeDecodeError: return request.send_response( "404 Not Found", request.headers, "<html><body><h1>404 Not Found</h1></body></html>") else: return self.request_uri(request, uri) except RuntimeError as e: self.error(e) e = u"%s" % e try: if getattr(request, "upload_handler", None): return request.uresponse( htmlescape( json.dumps({ "success": False, "errormsg": e }))) except Exception as e2: self.exception(e2) if type(e) == unicode: e = e.encode("utf-8") return request.send_response( "500 Internal Server Error", request.headers, "<html><body><h1>500 Internal Server Error</h1>%s</body></html>" % htmlescape(e)) except Exception as e: try: self.exception(e) except Exception as e2: print "Unhandled exception during logging: %s" % e2 print traceback.format_exc() try: if getattr(request, "upload_handler", None): return request.uresponse( htmlescape( json.dumps({ "success": False, "errormsg": "Internal Server Error" }))) except Exception as e2: self.exception(e2) return request.internal_server_error() def request_uri(self, request, uri): "Process HTTP request after URI was extracted, normalized and converted to utf-8" self.reqs += 1 # /service/call/<svcid>/method m = re_service_call.match(uri) if m: (svcid, remainder) = m.group(1, 2) if svcid != self.id: return request.bad_request() uri = remainder # / if uri == "": res = self.req_handler(request, "index", "index", "") if res is not None: return res # /group/hook[/args] m = re_group_hook_args.match(uri) if m: (group, hook, args) = m.group(1, 2, 3) if args is None: args = "" res = self.req_handler(request, group, hook, args) if res is not None: return res # /group/<SOMETHING_UNHANDLED> m = re_group_something_unparsed.match(uri) if m: (group, args) = m.group(1, 2) res = self.req_handler(request, group, "handler", args) if res is not None: return res # /group m = re_group.match(uri) if m: res = self.req_handler(request, uri, "index", "") if res is not None: return res return request.not_found() def publish(self, svcinfo): "Service may fill svcinfo dict with any additional properties that will be announced in service record" old_reqstat = self.old_reqstat new_reqstat = self.get_reqstat() elapsed = new_reqstat[0] - old_reqstat[0] if elapsed > 3: svcinfo["svc-rps"] = (new_reqstat[1] - old_reqstat[1]) / elapsed self.old_reqstat = new_reqstat def set(self, key, val): self.svcinfo[key] = val def svc_req_handler(self, request, hook): return None