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, 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 initLogger(self): return Logger(self.appName)
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()
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)