You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
9.8KB

  1. from fastapi import APIRouter,Request,FastAPI
  2. from pydantic import BaseModel
  3. from fastapi import APIRouter, Depends
  4. from pydantic import BaseModel, ValidationError
  5. from common.log import logger
  6. from model.models import AgentConfig,validate_wxid
  7. from services.gewe_service import GeWeService,get_gewe_service
  8. from services.redis_service import RedisService
  9. from model.models import AgentConfig,validate_wxid
  10. from common.utils import *
  11. import time,asyncio
  12. agent_router = APIRouter(prefix="/api/agent")
  13. class GetAgentLoginRequest(BaseModel):
  14. tel: str
  15. class GetWxQRCodeRequest(BaseModel):
  16. tel: str
  17. tokenId:str
  18. regionId:str
  19. agentTokenId:str
  20. class LogincCaptchCode(BaseModel):
  21. tokenId: str
  22. captchCode:str
  23. @agent_router.post("/getlogin", response_model=None)
  24. async def get_login(request: Request, body: GetAgentLoginRequest, ):
  25. tel = body.tel
  26. return await request.app.state.gewe_service.get_login_info_from_cache_async(tel)
  27. @agent_router.post("/getwxqrcode", response_model=None)
  28. async def get_wx_qrcode(request: Request, body: GetWxQRCodeRequest, ):
  29. tel = body.tel
  30. token_id =body.tokenId
  31. region_id= body.regionId
  32. agent_token_id= body.agentTokenId
  33. loginfo=await request.app.state.gewe_service.get_login_info_from_cache_async(tel)
  34. status=loginfo.get('status','0')
  35. if status=='1':
  36. msg=f'手机号{tel},wx_token{token_id} 已经微信登录,终止登录流程'
  37. logger.info(msg)
  38. return {'code': 501, 'message': msg}
  39. now=time.time()
  40. expried_time=int(now)+150
  41. flag=await request.app.state.gewe_service.acquire_login_lock_async(token_id,150)
  42. if not flag:
  43. msg=f'手机号{tel}, wx_token{token_id} 登录进行中,稍后再试'
  44. logger.info(msg)
  45. return {'code': 501, 'message': msg}
  46. app_id=loginfo.get('appId','')
  47. qr_code = await request.app.state.gewe_service.get_login_qr_code_async(token_id, app_id,region_id)
  48. if not qr_code:
  49. msg=f"获取二维码失败,qr_code: {qr_code}"
  50. await request.app.state.gewe_service.release_login_lock_async(token_id)
  51. logger.info(msg)
  52. return {'code': 501, 'message': msg}
  53. uuid = qr_code.get('uuid',None)
  54. if not uuid:
  55. msg=f"uuid获取二维码失败,uuid: {uuid}"
  56. await request.app.state.gewe_service.release_login_lock_async(token_id)
  57. logger.info(msg)
  58. return {'code': 501, 'message': msg}
  59. app_id = app_id or qr_code.get('appId')
  60. base64_string = qr_code.get('qrImgBase64',None)
  61. await request.app.state.gewe_service.qrCallback(uuid,base64_string)
  62. hash_key = f"__AI_OPS_WX__:LOGININFO:{tel}"
  63. print(hash_key)
  64. # thread = threading.Thread(target=waitting_login_result, args=(gewe_chat.wxchat,token_id, app_id,region_id, agent_token_id,hash_key, uuid,now))
  65. # thread.daemon = True
  66. # thread.start()
  67. loop = asyncio.get_event_loop()
  68. future = asyncio.run_coroutine_threadsafe(
  69. waitting_login_result(request,token_id, app_id,region_id, agent_token_id,hash_key, uuid,now),
  70. loop
  71. )
  72. return {
  73. "tokenId": token_id,
  74. "tel": tel,
  75. "base64Img": base64_string,
  76. "expiredTime": expried_time,
  77. }
  78. async def waitting_login_result(request: Request, token_id, app_id,region_id, agent_token_id,hash_key, uuid,start_time):
  79. agent_tel=hash_key.split(":")[-1]
  80. try:
  81. while True:
  82. now = time.time()
  83. if now - start_time > 150:
  84. logger.info(f'{token_id} 使用 {app_id} 扫二维码登录超时')
  85. break
  86. logger.info(f"{token_id} 使用 {app_id},等待扫码登录,二维码有效时间 {150 - int(now - start_time)} 秒")
  87. captch_code = await request.app.state.gewe_service.get_login_wx_captch_code_from_cache_async(token_id)
  88. captch_code= captch_code if captch_code else ''
  89. logger.info(f"{token_id} 使用 {app_id} 的验证码 {captch_code}")
  90. ret,msg,res = await request.app.state.gewe_service.check_login_async(token_id, app_id, uuid,captch_code)
  91. if ret == 200:
  92. flag = res.get('status')
  93. if flag == 2:
  94. logger.info(f"登录成功: {res}")
  95. head_img_url=res.get('headImgUrl','')
  96. login_info = res.get('loginInfo', {})
  97. wxid=login_info.get('wxid',agent_tel)
  98. cache_login_info=await request.app.state.gewe_service.get_login_info_from_cache_async(agent_tel)
  99. cache_wxid=cache_login_info.get('wxid','')
  100. if not cache_login_info and cache_wxid!=wxid and cache_wxid!='':
  101. logger.warning(f"agent_tel {agent_tel} , wxid {wxid} 与 cache_wxid {cache_wxid} 不匹配,登录失败")
  102. await request.app.state.gewe_service.logout_async(token_id,app_id)
  103. # k_message=utils.login_result_message(token_id,agent_tel,region_id,agent_token_id,'')
  104. # kafka_helper.kafka_client.produce_message(k_message)
  105. break
  106. login_info.update({'appId': app_id, 'uuid': uuid, 'tokenId': token_id,'status': 1,'headImgUrl':head_img_url,'regionId':region_id})
  107. cache_login_info=await request.app.state.redis_service.get_hash(hash_key)
  108. if 'appId' not in cache_login_info:
  109. login_info.update({"create_at":int(time.time()),"modify_at":int(time.time())})
  110. # 默认配置
  111. config=AgentConfig.model_validate({
  112. "chatroomIdWhiteList": [],
  113. "agentTokenId": agent_token_id,
  114. "agentEnabled": False,
  115. "addContactsFromChatroomIdWhiteList": [],
  116. "chatWaitingMsgEnabled": True
  117. })
  118. else:
  119. login_info.update({"modify_at":int(time.time())})
  120. # 已有配置
  121. config_cache=await request.app.state.gewe_service.get_wxchat_config_from_cache_async(wxid)
  122. config=AgentConfig.model_validate(config_cache)
  123. cleaned_login_info = {k: (v if v is not None else '') for k, v in login_info.items()}
  124. #wxid=cleaned_login_info.get('wxid',agent_tel)
  125. # 保存配置信息
  126. config_dict=config.model_dump()
  127. await request.app.state.gewe_service.save_wxchat_config_async(wxid,config_dict)
  128. # 保存登录信息
  129. await request.app.state.redis_service.set_hash(hash_key, cleaned_login_info)
  130. await request.app.state.gewe_service.release_login_lock_async(token_id)
  131. # 登录结果推送到kafka
  132. k_message=login_result_message(token_id,agent_tel,region_id,agent_token_id,wxid)
  133. await request.app.state.kafka_service.send_message_async(k_message)
  134. # 同步联系人列表
  135. ret,msg,contacts_list=await request.app.state.gewe_service.fetch_contacts_list_async(token_id,app_id)
  136. if ret!=200:
  137. logger.warning(f"同步联系人列表失败: {ret}-{msg}")
  138. break
  139. friend_wxids = [c for c in contacts_list['friends'] if c not in ['fmessage', 'medianote','weixin','weixingongzhong']] # 可以调整截取范围
  140. data=await request.app.state.gewe_service.save_contacts_brief_to_cache_async(token_id, app_id, wxid, friend_wxids)
  141. chatrooms=contacts_list['chatrooms']
  142. # 同步群列表
  143. logger.info(f'{wxid} 的群数量 {len(chatrooms)}')
  144. logger.info(f'{wxid} 同步群列表')
  145. await request.app.state.gewe_service.save_groups_info_to_cache_async(token_id, app_id, wxid, chatrooms)
  146. logger.info(f'{wxid} 同步群成员')
  147. # 同步群成员
  148. await request.app.state.gewe_service.save_groups_members_to_cache_async(token_id, app_id, wxid, chatrooms)
  149. logger.info(f'{wxid} 全量好友信息推送到kafka')
  150. # 联系人推送到kafka
  151. k_message=wx_all_contacts_message(wxid,data)
  152. await request.app.state.kafka_service.send_message_async(k_message)
  153. # 全量群信息推送到kafka
  154. logger.info(f'{wxid} 全量群信息推送到kafka')
  155. all_groups_info_menbers=await request.app.state.gewe_service.get_groups_info_members_from_cache_async(wxid)
  156. k_message=wx_groups_info_members_message(wxid,all_groups_info_menbers)
  157. await request.app.state.kafka_service.send_message_async(k_message)
  158. break
  159. else:
  160. logger.info(f"登录检查中: {ret}-{msg}-{res}")
  161. await asyncio.sleep(5)
  162. finally:
  163. await request.app.state.gewe_service.release_login_lock_async(token_id)
  164. @agent_router.post("/logincaptchcode", response_model=None)
  165. async def login_captch_code(request: Request, body: LogincCaptchCode, ):
  166. token_id = body.tokenId
  167. captch_code=body.captchCode
  168. res=await request.app.state.gewe_service.save_login_wx_captch_code_to_cache_async(token_id,captch_code)
  169. return {'message': '操作成功'}