Пример #1
0
    def __init__(self, name):
        super(FlaskService, self).__init__(name)
        self.app = None

        self.api_list = {}  # 注册api
        self.db = None
        self.blueprints = {}
        self.logger = Logger(__name__)
        self.isclosed = False
        self.thread = None
        self.server = None
Пример #2
0
    def __init__(self, name=''):
        self.name = name
        self.conf = {}
        self.caches = None
        self.logger = Logger(__name__)
        self.db = None
        self.config_file = 'settings.yaml'
        self.log_filters = {}
        self.plugins = {}
        self.pluginsIndexed = []
        self.wait_ev = Event()
        self.props = {}
        self.actived = False
        self.inited = False
        self.aborted = False

        global instance
        instance.set(self)
Пример #3
0
 def initLogger(self):
     return Logger(self.appName)
Пример #4
0
class Application(Singleton, object):
    inst = None

    def __init__(self, name=''):
        self.name = name
        self.conf = {}
        self.caches = None
        self.logger = Logger(__name__)
        self.db = None
        self.config_file = 'settings.yaml'
        self.log_filters = {}
        self.plugins = {}
        self.pluginsIndexed = []
        self.wait_ev = Event()
        self.props = {}
        self.actived = False
        self.inited = False
        self.aborted = False

        global instance
        instance.set(self)

    def setProps(self, **kwargs):
        self.props.update(kwargs)

    def getProp(self, name, default_=None):
        return self.props.get(name, default_)

    @property
    def datasourceManager(self):
        from mantis.fundamental.datasource import DatasourceManager
        return DatasourceManager()

    @property
    def serviceManager(self):
        from mantis.fundamental.service import ServiceManager
        return ServiceManager()

    @property
    def messageBrokerManager(self):
        from mantis.fundamental.messagebroker import MessageBrokerManager
        return MessageBrokerManager()

    def getService(self, name):
        from mantis.fundamental.service import ServiceManager
        return ServiceManager().get(name)

    def registerPlugin(self, plugin):
        """注册插件"""
        self.plugins[plugin.id] = plugin
        self.pluginsIndexed.append(plugin)

    def setupPlugins(self):
        from mantis.fundamental.plugin import init_plugins
        init_plugins()
        for p in self.pluginsIndexed:
            p.open()

    def closePlugins(self):
        for p in self.pluginsIndexed:
            p.close()

    def getPlugin(self, name, type=None):
        plugin = self.plugins.get(name)
        if plugin:
            if type and type != plugin.type:
                return None
        return plugin

    def getPlugins(self, type):
        result = []
        for p in self.pluginsIndexed:
            if p.type == type:
                result.append(p)
        return result

    @property
    def appName(self):
        app_name = self.getConfig().get('app_name', '')
        return app_name

    @property
    def appId(self):
        prj_ver = self.getConfig().get('project_version', '')
        name = "%s.%s-%s" % (self.projectName, self.name, os.getpid())
        return name

    def setName(self, name):
        self.name = name
        return self

    def getName(self):
        return self.name

    @property
    def projectName(self):
        prj_name = self.getConfig().get('project_name', '')
        return prj_name

    def getDefaultConfigFile(self):
        if self.config_file and self.config_file[0] == '/':
            return self.config_file  # absoluted path
        return os.path.join(self.getConfigPath(), self.config_file)

    def getHomePath(self):
        # path = os.getenv('CAMEL_HOME')
        # if path:
        #     return os.path.join(path,'products',self.name)
        path = os.getenv('APP_PATH')
        if path:
            return path + '/..'
        path = os.getcwd() + '/..'
        return path

        # path = os.path.join(self.getCamelHomePath(), 'products', self.name)
        # if not os.path.exists(path):
        #     return os.path.dirname(os.path.abspath(__file__))
        # return os.path.join(self.getCamelHomePath(), 'products', self.name)

    def getConfigPath(self):
        return os.path.join(self.getHomePath(), 'etc')

    def getDataPath(self):
        return os.path.join(self.getHomePath(), 'data')

    def getTempPath(self):
        return os.path.join(self.getHomePath(), 'temp')

    def getLogPath(self):
        return os.path.join(self.getHomePath(), 'logs')

    def getRunPath(self):
        return os.path.join(self.getHomePath(), 'run')

    def getLogger(self):
        return self.logger

    def getCamelHomePath(self):
        path = os.getenv('CAMEL_HOME')
        if path:
            return path

        return os.path.join(self.getHomePath(), '../')
        # path = os.getcwd()+'/..'
        # return path
        # return os.path.dirname(os.path.abspath(__file__))+'/..'
        # return CAMEL_HOME

    def getConfig(self):
        return self.conf

    def usage(self):
        pass

    def initOptions(self):
        """从环境变量 APP_NAME 拾取appname
           从命令行 --name 参数拾取appname
        :return:
        """
        if self.name:
            return
        self.name = os.getenv('APP_NAME')
        options, args = getopt.getopt(sys.argv[1:], 'hc:n:',
                                      ['help', 'name=', 'config='])  # : 带参数
        for name, value in options:
            if name in ['-h', "--help"]:
                self.usage()
                sys.exit()
            if name in ('-n', '--name'):
                self.name = value
            if name in ('-c', '--config'):
                self.config_file = name

        if not self.name:
            self.name = ''

    def initDirectories(self):
        from distutils.dir_util import mkpath
        mkpath(self.getConfigPath())
        mkpath(self.getDataPath())
        mkpath(self.getLogPath())
        mkpath(self.getRunPath())
        mkpath(self.getTempPath())

    def initServices(self):
        self.serviceManager.init(self.getConfig().get('services'))

    def initDatasources(self):
        self.datasourceManager.init(self.getConfig().get('datasources'))

    def initMessageBrokers(self):
        self.messageBrokerManager.init(self.getConfig().get('message_brokers'))

    def init(self):

        self.initOptions()
        self.initDirectories()
        self.initConfig()
        self.initLogs()
        self.initPlugins()
        self.initSignal()
        self.initDatasources()
        self.initMessageBrokers()
        self.initServices()

        self.initEnd()
        self.inited = True

        return self

    def initPlugins(self):
        self.setupPlugins()

    def initEnd(self):
        """ create pid file
        """

        pid = os.getpid()
        # filename = os.path.join(self.getRunPath(),'server_{}.pid'.format(timestamp_to_str( timestamp_current())))
        filename = os.path.join(self.getRunPath(), 'server.pid')
        fp = open(filename, 'w')
        fp.write('%s' % pid)
        fp.close()

    def initConfig(self):
        yaml = self.getDefaultConfigFile()
        self.conf = YamlConfigParser(yaml).props
        self._checkConfig()
        if not self.name:
            self.name = self.conf.get('app_name', '')

    def _checkConfig(self):
        """检查配置项是否okay"""
        pass

    def initLogger(self):
        return Logger(self.appName)

    def initLogs(self):
        import logging, string

        # ver = self.conf.get('project_version')
        # project = self.conf.get('project_name')
        # app_id = self.appName
        self.logger = self.initLogger()

        log = self.conf.get('logging')
        level = log.get('level', 'INFO')
        self.logger.setLevel(level)  # 不能设置全局,否则会默认输出到console

        # extra = {'project_name':project,'project_version':ver,'app_id':app_id,'tags':''}
        formatter = logging.Formatter(log.get('format'))
        self.logger.setFormat(formatter)
        # self.logger.setMessageFormat(log.get('message_format'))
        # self.initLogHandlerFilters(log.get('filters',{}))

        handlers = log.get('handlers', [])
        for cfg in handlers:
            handler = self.initLogHandler(cfg)
            if handler:
                # handler.setFormatter(formatter)
                self.logger.addHandler(handler)
                # ss = cfg.get('filter', '').strip()
                # if ss:
                #     ss = map( string.strip ,ss.split(',') )
                #     for s in ss:
                #         flt = self.log_filters.get(s)
                #         if flt:
                #             handler.addFilter(flt)
                #         else:
                #             print 'error: filter<%s> not found!'%s

    def initLogHandlerFilters(self, cfgs):
        filters = {}
        for name, cfg in cfgs.items():
            flt = LogHandlerFilter(name, cfg)
            filters[name] = flt
        self.log_filters = filters

    def initLogHandler(self, cfg):
        """日志handler初始化
        目前仅支持: file(RotatingFileHandler) , console(StreamHandler)

        :param cfg:
        :return:
        """
        from mantis.fundamental.logging.handler import LogFileHandler, LogConsoleHandler

        handler = None
        if cfg.get('type', '').lower() == LogFileHandler.TYPE and cfg.get(
                'enable', False) == True:
            logfile = os.path.join(self.getLogPath(), cfg.get('filename'))
            handler = LogFileHandler(logfile,
                                     encoding=cfg.get('encoding'),
                                     maxBytes=cfg.get('max_bytes'),
                                     backupCount=cfg.get('backup_count'))

        if cfg.get('type').lower() == LogConsoleHandler.TYPE and cfg.get(
                'enable', False) == True:
            handler = LogConsoleHandler()

        return handler

    def run(self):
        if self.aborted:
            return
        self.actived = True
        self.datasourceManager.open()
        self.serviceManager.start()
        self.messageBrokerManager.start()

        forks = self.getConfig().get('forks', 0)
        if forks:
            pids = []
            for nr in range(forks):
                pid = os.fork()
                if pid == 0:  # child process
                    break
                else:
                    pids.append(pid)
            if pids:  #  father process, wait until children all terminated
                for pid in pids:
                    os.waitpid(pid)
        print 'Service [%s] Started..' % self.name
        self.serve_forever()
        self.serviceManager.join()
        print 'Service [%s] Stopped..' % self.name

    def serve_forever(self):
        while not self.wait_ev.is_set() and self.actived:
            self.wait_ev.wait(1)

        print 'serve_forever run end..'

    def abort(self):
        self.aborted = True

    def stop(self):
        # self.inited = False
        self.actived = False
        # print 'To Stop Server..'
        self.messageBrokerManager.stop()
        self.serviceManager.stop()
        self.datasourceManager.close()
        self.wait_ev.set()

    def initSignal(self):
        """多线程时, signal 被发送到创建的子线程中,主线程无法捕获"""
        import signal
        signal.signal(signal.SIGINT, self._sigHandler)

    def _sigHandler(self, signum, frame):
        print 'signal ctrl-c'
        self.stop()
Пример #5
0
class FlaskService(ServiceBase):
    TYPE = 'FlaskService'

    def __init__(self, name):
        super(FlaskService, self).__init__(name)
        self.app = None

        self.api_list = {}  # 注册api
        self.db = None
        self.blueprints = {}
        self.logger = Logger(__name__)
        self.isclosed = False
        self.thread = None
        self.server = None

    def init(self, cfgs, **kwargs):
        #from mantis.fundamental.application.app import instance
        if kwargs.has_key('logger'):
            self.logger = kwargs.get('logger')

        self.cfgs = cfgs
        if kwargs.has_key('app'):
            self.app = kwargs.get('app')
        else:
            static_path = os.getcwd() + '/static'
            template_path = os.getcwd() + '/templates'
            self.app = Flask(
                __name__,
                static_folder=static_path,
                template_folder=template_path
            )  # flask会自动将当前代码目录设置为项目根目录 root_path 导致读取templtes , sta它ic 目录失败

        Compress(self.app)  # okay
        # gzip = Gzip(app) # error

        active = self.getConfig().get('cfgs', {})
        for k, v in active.items():
            self.app.config[k] = v

        self.initCors()
        self.initDatabase()

        self.setupRequestHooks()
        self.initBlueprint()

        self.setupTemplates()

    def setupTemplates(self):
        from werkzeug.routing import BaseConverter
        from flask import Flask, send_file

        class RegexConverter(BaseConverter):
            def __init__(self, map, *args):
                self.map = map
                self.regex = args[0]

        self.app.url_map.converters['regex'] = RegexConverter

        @self.app.route('/<regex(".*\.html$"):template_name>')
        def _template_render(template_name):
            name = os.path.join(self.app.template_folder, template_name)
            return send_file(name)

    def initDatabase(self):
        global db
        if db.get() is None:
            self.db = SQLAlchemy(self.app)
            db.set(self.db)

    def getDatabase(self):
        return self.db

    def initCors(self):
        """
            https://flask-cors.readthedocs.io/en/latest/
        :return:
        """
        if self.getConfig().get('cors_enable', True):
            CORS(self.app)

    def getFlaskApp(self):
        return self.app

    def setupRequestHooks(self):
        self.app.before_request(self.onRequestBefore)
        self.app.teardown_request(self.onRequestTeardown)
        # self.app.after_request(self._requestAfter)  # todo. 导致 send_file 失败
        # 当利用send_file发送二进制数据时,after_request对返回数据进行日志处理,导致数据返回失败

    def _traceRequestInfo(self, opts):
        import json
        trace_data = {'url': request.url}
        if opts.get('header'):
            trace_data['headers'] = request.headers
        if opts.get('body'):
            trace_data['body'] = request.data.replace(
                '\n', ' ')[:opts.get('max_size')]
        return json.dumps(trace_data)

    def _traceResponseInfo(self, opts, response):
        import json
        trace_data = {'url': request.url}
        if opts.get('header'):
            trace_data['headers'] = response.headers
        if opts.get('body'):
            trace_data['body'] = response.data.replace(
                '\n', ' ')[:opts.get('max_size')]
        return json.dumps(trace_data)

    def onRequestBefore(self):
        # pass
        import time
        g.start_time = time.time()

        #
        # trace = self.getConfig().get('http_trace',{}).get('request',{})
        # options = trace.get('options',{'header':False,'body':False,'max_size':1024})
        # urls = trace.get('urls',[])
        # #sort urls by 'match' with desceding.
        # urls = sorted(urls,cmp = lambda x,y: cmp(len(x.get('match')) , len(y.get('match')) ) )
        # urls.reverse()
        #
        # text = ''
        # for url in urls:
        #     m = url.get('match')
        #     if m:
        #         opts = options.copy()
        #         opts['header'] = url.get('header',options.get('header'))
        #         opts['body'] = url.get('body',options.get('body'))
        #         opts['max_size'] = url.get('max_size',options.get('max_size'))
        #         if request.url.find(m) !=-1:
        #             text = self._traceRequestInfo(opts)
        #             break
        # level = self.getConfig().get('http_trace',{}).get('level','DEBUG')
        # text = 'HttpRequest: '+text
        # self.getLogger().log(level,text)

    def onRequestTeardown(self, e):
        pass

    def _requestAfter(self, response):

        trace = self.getConfig().get('http_trace', {}).get('response', {})
        options = trace.get('options', {
            'header': False,
            'body': False,
            'max_size': 1024
        })
        urls = trace.get('urls', [])

        urls = sorted(
            urls,
            cmp=lambda x, y: cmp(len(x.get('match')), len(y.get('match'))))
        urls.reverse()

        text = ''
        for url in urls:
            m = url.get('match')
            if m:
                opts = options.copy()
                opts['header'] = url.get('header', options.get('header'))
                opts['body'] = url.get('body', options.get('body'))
                opts['max_size'] = url.get('max_size', options.get('max_size'))
                if request.url.find(m) != -1:
                    text = self._traceResponseInfo(opts, response)
                    break
        level = self.getConfig().get('http_trace', {}).get('level', 'DEBUG')

        remote_addr = ''
        if request.headers.getlist("X-Forwarded-For"):
            remote_addr = request.headers.getlist("X-Forwarded-For")[0]
        else:
            remote_addr = request.remote_addr

        elapsed = int((time.time() - g.start_time) * 1000)
        text = 'HTTP %s %s %s %sms  ' % (remote_addr, request.method,
                                         request.url, elapsed)
        self.getLogger().log(level, text)

        return response

    def initBlueprint(self):

        cfgs = self.getConfig().get('blueprints', [])
        for cfg in cfgs:
            # module = import_module( cfgs.get('module'))
            if not cfg.get('register', True):
                continue
            package_name = cfg.get('name', '')
            package = cfg.get('package')
            package_url = cfg.get('url')
            modules = cfg.get('modules', [])
            for module in modules:
                module_name = module.get('name', )
                module_url = module.get("url", '')
                path = '%s.%s' % (package, module_name)
                load_module = import_module(path)

                app = Blueprint(module_name, path)
                self.blueprints[path] = app

                # api_module = {'name': u'%s.%s'%(package_name,module_name),'api_list':[]}
                module_name = u'%s.%s' % (package_name, module_name)
                self.api_list[module_name] = []

                routes = module.get('routes', [])
                for route in routes:
                    url = route.get('url', '')
                    name = route.get('name', '')
                    methods = filter(
                        lambda x: len(x) > 0,
                        route.get('methods', '').strip().upper().split(','))

                    if hasattr(load_module, name):
                        func = getattr(load_module, name)
                        path = package_url + module_url
                        path = path.replace('//', '/')
                        if methods:
                            app.route(url, methods=methods)(func)
                        else:
                            app.route(url)(func)
                        self.registerBlueprint(app, path)
                        path = path + '/' + url
                        path = path.replace('//', '/')
                        self.logger.debug('registered blueprint route:' + path)

                        api = {'url': path, 'methods': ('GET', )}

                        if methods:
                            api['methods'] = methods
                        self.api_list[module_name].append(api)

    def registerAPIs(self, manager):
        manager.register_http_service(self.api_list)

    # def _initLogger(self):
    #     from camel.biz.logging.logger import FlaskHttpRequestLogger
    #     return FlaskHttpRequestLogger(self.appId)

    # def start(self,block = True):
    #     # Application.run(self)
    #     http = self.getConfig().get('http')
    #     if http:
    #         self.app.run(host=http.get('host','127.0.0.1'),
    #             port = http.get('port',5000),
    #             threaded = http.get('threaded',True),
    #             debug = http.get('debug',True),
    #             process = http.get('process',1))

    def select_address(self):
        """
        修正http侦听地址 , 如果port未定义或者为0 ,则进行动态选定端口
        :return:
        """
        from mantis.fundamental.utils.network import select_address_port
        http = self.cfgs.get('http')

        if not http.get('port'):  # port 未定义或者为0
            start = 18900
            end = 18950
            address = select_address_port(http.get('host'), start, end)
            self.cfgs.get('http')['port'] = address[1]

    def start(self, block=True):
        self.select_address()

        http = self.getConfig().get('http')
        host = http.get('host', '127.0.0.1')
        port = http.get('port', 5000)
        # app = self.app

        # if http.get('debug', False):
        #     app.run(host,port,debug=True)
        # else:
        #     self.server = wsgi.WSGIServer(( host, port), app)
        #
        #     self.server.start()
        #     Application.run(self)
        # self.server = pywsgi.WSGIServer((host,port),app)
        # self.server.start()

        self.initHttpServer()

        if block:
            self.logger.info('Service: %s started, Listen on %s:%s ...' %
                             (self.name, host, port))
            self.server.serve_forever()
        else:
            self.thread = Thread(target=self.runThread)
            self.thread.setDaemon(True)
            self.thread.start()

    def initHttpServer(self):
        http = self.getConfig().get('http')
        host = http.get('host', '127.0.0.1')
        port = http.get('port', 5000)
        app = self.app
        from mantis.fundamental.application.use_gevent import USE_GEVENT

        print '--' * 20
        if USE_GEVENT:
            from gevent import pywsgi
            from socketio.server import SocketIOServer
            if http.get('websocket', False):
                self.server = SocketIOServer((host, port),
                                             app,
                                             resource="socket.io")
            else:
                self.server = pywsgi.WSGIServer((host, port), app)
                self.server.start()
        else:
            from wsgiref.simple_server import make_server
            self.server = make_server(host, port, app)

        self.logger.info('Service: %s started, Listen on %s:%s ...' %
                         (self.name, host, port))

    def runThread(self):
        # print 'xxxx-Service: %s started, Listen on %s:%s ...' % (self.name, host, port)
        self.server.serve_forever()

    def stop(self):
        from mantis.fundamental.application.use_gevent import USE_GEVENT

        if self.server:
            if USE_GEVENT:
                self.server.stop()
            else:
                self.server.shutdown()

    def registerBlueprint(self, bp, url):
        self.app.register_blueprint(bp, url_prefix=url)