utils.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from functools import wraps
  4. import socket
  5. import commands
  6. import jimit as ji
  7. import json
  8. from flask import make_response, g, request
  9. from flask.wrappers import Response
  10. from werkzeug.utils import import_string, cached_property
  11. import jwt
  12. from models import app_config, logger
  13. from database import Database as db
  14. __author__ = 'James Iter'
  15. __date__ = '2017/03/01'
  16. __contact__ = 'james.iter.cn@gmail.com'
  17. __copyright__ = '(c) 2017 by James Iter.'
  18. class Utils(object):
  19. exit_flag = False
  20. thread_counter = 0
  21. @staticmethod
  22. def shell_cmd(cmd):
  23. try:
  24. exit_status, output = commands.getstatusoutput(cmd)
  25. return exit_status, str(output)
  26. except Exception as e:
  27. return -1, e.message
  28. @classmethod
  29. def signal_handle(cls, signum=0, frame=None):
  30. cls.exit_flag = True
  31. raise RuntimeError('Shutdown app!')
  32. @staticmethod
  33. def dumps2response(func):
  34. """
  35. 视图装饰器
  36. http://dormousehole.readthedocs.org/en/latest/patterns/viewdecorators.html
  37. """
  38. @wraps(func)
  39. def _dumps2response(*args, **kwargs):
  40. ret = func(*args, **kwargs)
  41. if func.func_name != 'r_before_request' and ret is None:
  42. ret = dict()
  43. ret['state'] = ji.Common.exchange_state(20000)
  44. if isinstance(ret, dict) and 'state' in ret:
  45. response = make_response()
  46. response.data = json.dumps(ret, ensure_ascii=False)
  47. response.status_code = int(ret['state']['code'])
  48. if 'redirect' in ret and request.args.get('auto_redirect', 'True') == 'True':
  49. response.status_code = int(ret['redirect'].get('code', ret['state']['code']))
  50. response.headers['location'] = ret['redirect'].get('location', request.host_url)
  51. # 参考链接:
  52. # http://werkzeug.pocoo.org/docs/0.11/wrappers/#werkzeug.wrappers.BaseResponse.autocorrect_location_header
  53. # 变量操纵位置 werkzeug/wrappers.py
  54. response.autocorrect_location_header = False
  55. return response
  56. if isinstance(ret, Response):
  57. return ret
  58. return _dumps2response
  59. @staticmethod
  60. def superuser(func):
  61. @wraps(func)
  62. def _superuser(*args, **kwargs):
  63. if not g.superuser:
  64. ret = dict()
  65. ret['state'] = ji.Common.exchange_state(40301)
  66. return ret
  67. return func(*args, **kwargs)
  68. return _superuser
  69. @staticmethod
  70. def generate_token(uid, ttl=app_config['token_ttl'], audience=None):
  71. payload = {
  72. 'iat': ji.Common.ts(), # 创建于
  73. 'nbf': ji.Common.ts(), # 在此之前不可用
  74. 'exp': ji.Common.ts() + ttl, # 过期时间
  75. 'uid': uid
  76. }
  77. if audience is not None:
  78. payload['aud'] = audience
  79. return jwt.encode(payload=payload, key=app_config['jwt_secret'], algorithm=app_config['jwt_algorithm'])
  80. @staticmethod
  81. def verify_token(token, audience=None):
  82. ret = dict()
  83. ret['state'] = ji.Common.exchange_state(20000)
  84. try:
  85. if audience is None:
  86. payload = jwt.decode(jwt=token, key=app_config['jwt_secret'], algorithms=app_config['jwt_algorithm'])
  87. else:
  88. payload = jwt.decode(jwt=token, key=app_config['jwt_secret'], algorithms=app_config['jwt_algorithm'],
  89. audience=audience)
  90. return payload
  91. except jwt.InvalidTokenError, e:
  92. logger.error(e.message)
  93. ret['state'] = ji.Common.exchange_state(41208)
  94. raise ji.JITError(json.dumps(ret))
  95. @staticmethod
  96. def emit_instruction(message):
  97. db.r.publish(app_config['instruction_channel'], message=message)
  98. @staticmethod
  99. def port_is_opened(port):
  100. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  101. result = s.connect_ex(('0.0.0.0', port))
  102. if result == 0:
  103. return True
  104. else:
  105. return False
  106. class LazyView(object):
  107. """
  108. 惰性载入视图
  109. http://dormousehole.readthedocs.org/en/latest/patterns/lazyloading.html
  110. """
  111. def __init__(self, import_name):
  112. self.__module__, self.__name__ = import_name.rsplit('.', 1)
  113. self.import_name = import_name
  114. @cached_property
  115. def view(self):
  116. return import_string(self.import_name)
  117. def __call__(self, *args, **kwargs):
  118. return self.view(*args, **kwargs)
  119. def add_rule_api(blueprint, rule, api_func=None, **options):
  120. blueprint.add_url_rule(rule=rule, view_func=LazyView(''.join(['api.', api_func])), **options)
  121. def add_rule_views(blueprint, rule, views_func=None, **options):
  122. blueprint.add_url_rule(rule=rule, view_func=LazyView(''.join(['views.', views_func])), **options)