• cherrypy & gevent patch


    给cherrypy 打gevent WSGIServer的patch

    1. patch Serving 类

    2. 关闭python的原生WSGIServer

    具体使用例子参考 我的开源项目  https://github.com/thomashuang/Lilac

    #!/usr/bin/env python
    
    import cherrypy
    from cherrypy import _cprequest
    from cherrypy.lib import httputil
    import sys
    import logging
    from cherrypy.process import servers
    
    
    LOGGER = logging.getLogger('web.patch')
    
    
    try:
        from greenlet import getcurrent as get_ident
    except ImportError:
        LOGGER.ERROR('You shall install Gevent, if wanna use gevent wsgi server')
        exit(1)
    
    
    def patch_cherrypy():
        cherrypy.serving = GreenletServing()
    
    
    class GreenletServing(object):
        __slots__ = ('__local__', )
    
        def __init__(self):
            object.__setattr__(self, '__local__', {})
            ident = get_ident()
            self.__local__[ident] = {
                'request': _cprequest.Request(httputil.Host("127.0.0.1", 80), httputil.Host("127.0.0.1", 1111)),
                'response': _cprequest.Response()
            }
    
        def load(self, request, response):
            self.__local__[get_ident()] = {
                'request': request,
                'response': response
            }
    
        def __getattr__(self, name):
            try:
                return self.__local__[get_ident()][name]
            except KeyError:
                raise AttributeError(name)
    
        def __setattr__(self, name, value):
            ident = get_ident()
            local = self.__local__
            try:
                local[ident][name] = value
            except KeyError:
                local[ident] = {name: value}
    
        def clear(self):
            """Clear all attributes of the current greenlet."""
            del self.__local__[get_ident()]
    #!/usr/bin/env python
    
    import cherrypy
    import sys
    import logging
    from cherrypy.process import servers
    
    LOGGER = logging.getLogger('web.server')
    
    class GeventWSGIServer(object):
    
        """Adapter for a gevent.wsgi.WSGIServer."""
    
        def __init__(self, *args, **kwargs):
            from lilac.web.patch import patch_cherrypy
    
            patch_cherrypy()
            self.args = args
            self.kwargs = kwargs
            self.ready = False
    
        def start(self):
            """Start the GeventWSGIServer."""
            # We have to instantiate the server class here because its __init__
            from gevent.wsgi import WSGIServer
    
            self.ready = True
            LOGGER.debug('Starting Gevent WSGI Server...')
            self.httpd = WSGIServer(*self.args, **self.kwargs)
            self.httpd.serve_forever()
    
        def stop(self):
            """Stop the HTTP server."""
            LOGGER.debug('Stoping Gevent WSGI Server...')
            self.ready = False
            self.httpd.stop()
    
    
    class WebServer(object):
    
        def __init__(self, server_name='Sola', host='127.0.0.1', port=8080, use_gevent=True, debug=False, encoding='UTF-8'):
            self.server_name = server_name
            self.host = host
            self.port = port
            self.debug = debug
            self.encoding = encoding
            self.use_gevent = use_gevent
            self.config = self.gen_config()
            self.bootstrap()
    
        def bootstrap(self):
            """You can intialize more configs or settings in here"""
            pass
    
        def gen_config(self):
            conf = {
                'global':
                    {
                        'server.socket_host': self.host,
                        'server.socket_port': self.port,
                        'engine.autoreload.on': self.debug,
                        #'log.screen': self.debug,
                        'log.error_file': '',
                        'log.access_file': '',
                        'request.error_response': self.handle_internal_exception,
                        'tools.decode.on': True,
                        "tools.encode.on": True,
                        'tools.encode.encoding': self.encoding,
                        'tools.gzip.on': True,
                        'tools.log_headers.on': False,
                        'request.show_tracebacks': False,
                    }
            }
            if self.use_gevent:
                conf['global']['environment'] = 'embedded'
    
            return conf
    
        def set_404_pape(self, not_found_handler):
            """Custom not found page"""
            self.config['global']['error_page.404'] = not_found_handler
    
    
        def asset(self, path, asset_path):
            """Set servering Static directory"""
            self.config[path] = {
                'tools.staticdir.on': True,
                'tools.staticdir.dir': asset_path
            }
    
        def handle_internal_exception(self):
            """Handle the unknow exception and also throw 5xx status and push message to frontend"""
            cls, e, tb = sys.exc_info()
    
            LOGGER.exception('Unhandled Error %s', e)
            resp = cherrypy.response
            resp.status = 500
            resp.content_type = 'text/html; charset=UTF-8'
    
            if cherrypy.request.method != 'HEAD':
                resp.body = ["""<html>
    <head><title>Internal Server Error </title></head>
    <body><p>An error occurred: <b>%s</b></p></body>
    </html> """ % (str(e))]
    
        def new_route(self):
            return cherrypy.dispatch.RoutesDispatcher()
    
        def create_app(self):
            raise NotImplemented('Must implement create_app in Subclass')
    
        def _bootstrap_app(self):
            ctl, routes = self.create_app()
            cherrypy.config.clear()
            config = {'/': {'request.dispatch': routes}, 'global': self.config}
            config.update(self.config)
            cherrypy.config.update(config)
            return cherrypy.tree.mount(ctl, '/', config)
    
        def serve_forever(self):
            engine = cherrypy.engine
            if hasattr(engine, "signal_handler"):
                engine.signal_handler.subscribe()
            if hasattr(engine, "console_control_handler"):
                engine.console_control_handler.subscribe()
            app = self._bootstrap_app()
            try:
                if self.use_gevent:
                    # Turn off autoreload when using *cgi.
                    #cherrypy.config.update({'engine.autoreload_on': False})
                    addr = cherrypy.server.bind_addr
                    cherrypy.server.unsubscribe()
                    f = GeventWSGIServer(addr, app, log=None)
                    s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr)
                    s.subscribe()
                    engine.start()
                else:
                    cherrypy.quickstart(app)
            except KeyboardInterrupt:
                self.stop()
            else:
                engine.block()
    
        def stop(self):
            cherrypy.engine.stop()
  • 相关阅读:
    学习笔记8:《大型网站技术架构 核心原理与案例分析》之 固若金汤:网站的安全架构
    学习笔记8:《大型网站技术架构 核心原理与案例分析》之 随需应变:网站的可扩展架构
    13 集合
    12 泛型程序设计
    11 异常, 日志, 断言和调试
    10 部署应用程序和applet
    08 事件处理
    06 接口与内部类
    05 继承
    04 对象与类
  • 原文地址:https://www.cnblogs.com/nagi/p/4191425.html
Copyright © 2020-2023  润新知