app.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # note: https://responder.kennethreitz.org/en/latest/search.html?q=resp.content
  2. from hub import methods
  3. import traceback
  4. import requests
  5. import importlib
  6. def generate_app():
  7. """"""
  8. # from settings import action_methods
  9. from lib.LineManage import LineManage
  10. # see: https://lzomedia.com/blog/host-fastapi-backend-api-and-react-app-frontend-locally/
  11. # --- define middleware --- see: https://www.starlette.io/middleware/
  12. # from starlette.applications import Starlette
  13. # from starlette.middleware import Middleware
  14. # # from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
  15. # # from starlette.middleware.trustedhost import TrustedHostMiddlewar
  16. # middleware = [
  17. # Middleware(
  18. # TrustedHostMiddleware,
  19. # allow_credentials=True,
  20. # allowed_hosts=['*'],
  21. # allow_methods=["*"],
  22. # allow_headers=["*"],
  23. # ),
  24. # # Middleware(HTTPSRedirectMiddleware)
  25. # ]
  26. # --- define app --- see: https://responder.kennethreitz.org/en/latest/tour.html#cors
  27. import responder
  28. app = responder.API(
  29. # cors=True,
  30. # allow_methods=['*'],
  31. # allow_credentials=True,
  32. )
  33. async def coroutine_method(method, _params):
  34. """协程方法"""
  35. # run_at = time.time()
  36. result = await method(**_params)
  37. # methods.debug_log(f"app.coroutine_method", f"use time {round(time.time() - run_at, 2)}s")
  38. return result
  39. def foreground_method(method, _params):
  40. """等待返回"""
  41. # run_at = time.time()
  42. result = method(**_params)
  43. # methods.debug_log(f"app.foreground_method", f"use time {round(time.time() - run_at, 2)}s")
  44. return result
  45. @app.background.task
  46. def background_method(method, _params):
  47. """不等返回"""
  48. # run_at = time.time()
  49. result = method(**_params)
  50. # methods.debug_log(f"app.background_method", f"use time {round(time.time() - run_at, 2)}s")
  51. return result
  52. async def run_method(code, _params):
  53. config_dict = {
  54. 7000: ('v1', 'f7000', 'IsAsync'),
  55. 70000: ('v1', 'f70000', 'IsBack'),
  56. }
  57. if code not in config_dict:
  58. return dict(code=2, detail=f"{code} not found!")
  59. else:
  60. script_name, method_name, method_type = config_dict[code]
  61. script = importlib.import_module(f"api.httpapi.{script_name}")
  62. method = getattr(script, method_name)
  63. del _params['code']
  64. if method_type == 'IsAsync':
  65. return await coroutine_method(method, _params)
  66. elif method_type == 'IsBack':
  67. return foreground_method(method, _params)
  68. elif method_type == 'NoBack':
  69. return background_method(method, _params)
  70. @app.route('/httpapi')
  71. async def httpapi(request, response):
  72. try:
  73. # --- fill ---
  74. if request.params:
  75. params = dict(request.params.items())
  76. else:
  77. params = await request.media()
  78. # --- debug ---
  79. methods.debug_log('app.httpapi92', f"#params: {params}")
  80. # --- check ---
  81. if 'code' not in params:
  82. response.media = dict(code=-1, reason="error98", detail=f"参数缺失")
  83. else:
  84. code = params.get('code')
  85. result = await run_method(code, params)
  86. methods.debug_log('app.httpapi102', f"#result: {result}")
  87. if result.__class__.__name__ == 'bytes':
  88. response.content = result
  89. elif result.__class__.__name__ == 'str':
  90. response.text = result
  91. elif result.__class__.__name__ == 'dict':
  92. response.media = result
  93. elif result.__class__.__name__ == 'Future':
  94. response.media = dict(code=0, detail=f"{result} is running.")
  95. elif not result:
  96. response.media = dict(code=0, detail=f"return is null.")
  97. else:
  98. response.media = dict(code=0, detail=f"return type is {result.__class__.__name__}.")
  99. except Exception as exception:
  100. methods.debug_log("app.httpapi118", f"#exception: {exception.__class__.__name__}")
  101. methods.debug_log("app.httpapi118", f"#traceback: {traceback.format_exc()}")
  102. response.media = dict(code=-1, reason=exception.__class__.__name__, detail=f"{methods.trace_log()}")
  103. @app.route('/wsapi', websocket=True)
  104. async def wsapi(client):
  105. """
  106. let wsuri = `${location.protocol === 'https' ? 'wss' : 'ws'}://${location.host}:8801/wsapi`;
  107. connect_json_text = {
  108. line_id: 连接id,暂为token
  109. }
  110. )
  111. send_json_text_1 = {
  112. face_uuid: 匹配到的人脸id
  113. face_name: 人脸名称
  114. input_face_b64: 抓拍图片(b64格式字符串)
  115. }
  116. """
  117. try:
  118. await client.accept()
  119. while True:
  120. # --- check ---
  121. data = await client.receive_text() # 消息接受方法 receive_{text/json/bytes}
  122. if not data:
  123. methods.debug_log('app.wsapi140', f"#reason: error140")
  124. await client.send_json({'code': -1, 'reason': 'error140'})
  125. break
  126. # --- debug ---
  127. # methods.debug_log('app.wsapi145', f"#data: {data} | {type(data)}")
  128. # --- check ---
  129. if not methods.is_json(data):
  130. methods.debug_log('app.wsapi133', f"#reason: error146")
  131. await client.send_json({'code': -1, 'reason': 'error146'})
  132. break
  133. # --- check ---
  134. data = methods.json_loads(data)
  135. if not data.get('code'):
  136. methods.debug_log('app.wsapi144', f"#reason: error157")
  137. await client.send_json({'code': -1, 'reason': 'error157'})
  138. break
  139. # --- debug ---
  140. if data.get('code') not in [2008]:
  141. methods.debug_log('app.wsapi160', f"#data: {data}")
  142. # --- check 2000 ---
  143. code = data.get('code')
  144. if code == 2000:
  145. # --- check ---
  146. if 'acct' not in data or 'pw' not in data:
  147. methods.debug_log('app.wsapi166', f"#reason: error164")
  148. await client.send_json({'code': -1, 'reason': 'error164'})
  149. break
  150. # --- check ---
  151. username = data.get('acct')
  152. password = data.get('pw')
  153. url = 'http://58.34.98.13:8099/api/ar/user/login'
  154. data = {
  155. "acct": username,
  156. "pw": password,
  157. "method": "1" # 客户端类型 1 安卓 2 PC端
  158. }
  159. methods.debug_log('app.wsapi179', f"#url: {url}")
  160. response = requests.post(url=url, json=data)
  161. data = response.json()
  162. if data.get('msg') and data.get('msg') == 'success':
  163. data['code'] = 4000
  164. await client.send_json(data)
  165. else:
  166. methods.debug_log('app.wsapi186', f"#reason: error186")
  167. await client.send_json({'code': -1, 'reason': 'error186'})
  168. # --- save ---
  169. # methods.debug_log('app.wsapi179', f"{dir(client)}")
  170. # methods.debug_log('app.wsapi179', f"#id: {id(client)} | {type(id(client))}")
  171. methods.debug_log('app.wsapi179', f"{type(client)} | {methods.now_ts()} | {id(client)}")
  172. LineManage.line_dict[username] = client, methods.now_ts(), id(client)
  173. # --- check 2008 ---
  174. if code == 2008:
  175. # --- 判断该连接是否是已保存的链接 ---
  176. is_ok = False
  177. for key in list(LineManage.line_dict.keys()):
  178. ws, ts, _id = LineManage.line_dict.get(key)
  179. if _id == id(client):
  180. LineManage.line_dict[username] = client, methods.now_ts(), id(client)
  181. is_ok = True
  182. await client.send_json({'code': 4008, 'result': is_ok})
  183. except Exception as exception:
  184. if exception.__class__.__name__ == 'WebSocketDisconnect':
  185. await client.close()
  186. else:
  187. methods.debug_log("app.wsapi163", f"#exception: {exception.__class__.__name__}")
  188. methods.debug_log("app.wsapi163", f"#traceback: {traceback.format_exc()}")
  189. # --- return ---
  190. return app