Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

194 lines
7.5KB

  1. # -*- coding: utf-8 -*-
  2. # filename: main.py
  3. import web
  4. import time
  5. import hashlib
  6. import textwrap
  7. from channel.channel import Channel
  8. import channel.wechatmp.reply as reply
  9. import channel.wechatmp.receive as receive
  10. from common.log import logger
  11. from config import conf
  12. class WechatMPServer():
  13. def __init__(self):
  14. pass
  15. def startup(self):
  16. urls = (
  17. '/wx', 'WechatMPChannel',
  18. )
  19. app = web.application(urls, globals())
  20. app.run()
  21. from concurrent.futures import ThreadPoolExecutor
  22. thread_pool = ThreadPoolExecutor(max_workers=8)
  23. cache_dict = dict()
  24. query1 = dict()
  25. query2 = dict()
  26. query3 = dict()
  27. class WechatMPChannel(Channel):
  28. def GET(self):
  29. try:
  30. data = web.input()
  31. if len(data) == 0:
  32. return "hello, this is handle view"
  33. signature = data.signature
  34. timestamp = data.timestamp
  35. nonce = data.nonce
  36. echostr = data.echostr
  37. token = conf().get('wechatmp_token') #请按照公众平台官网\基本配置中信息填写
  38. data_list = [token, timestamp, nonce]
  39. data_list.sort()
  40. sha1 = hashlib.sha1()
  41. # map(sha1.update, data_list) #python2
  42. sha1.update("".join(data_list).encode('utf-8'))
  43. hashcode = sha1.hexdigest()
  44. print("handle/GET func: hashcode, signature: ", hashcode, signature)
  45. if hashcode == signature:
  46. return echostr
  47. else:
  48. return ""
  49. except Exception as Argument:
  50. return Argument
  51. def _do_build_reply(self, cache_key, fromUser, message):
  52. context = dict()
  53. context['session_id'] = fromUser
  54. reply_text = super().build_reply_content(message, context)
  55. # The query is done, record the cache
  56. logger.info("[threaded] Get reply_text for {}".format(message))
  57. global cache_dict
  58. cache_dict[cache_key] = (1, reply_text)
  59. def POST(self):
  60. try:
  61. queryTime = time.time()
  62. webData = web.data()
  63. # logger.debug("[wechatmp] Receive request:\n" + webData.decode("utf-8"))
  64. recMsg = receive.parse_xml(webData)
  65. if isinstance(recMsg, receive.Msg) and recMsg.MsgType == 'text':
  66. fromUser = recMsg.FromUserName
  67. toUser = recMsg.ToUserName
  68. createTime = recMsg.CreateTime
  69. message = recMsg.Content.decode("utf-8")
  70. message_id = recMsg.MsgId
  71. logger.info("{}:{} [wechatmp] Receive post query {} {}: {}".format(web.ctx.env.get('REMOTE_ADDR'), web.ctx.env.get('REMOTE_PORT'), fromUser, message_id, message))
  72. global cache_dict
  73. global query1
  74. global query2
  75. global query3
  76. cache_key = fromUser
  77. cache = cache_dict.get(cache_key)
  78. reply_text = ""
  79. # New request
  80. if cache == None:
  81. # The first query begin, reset the cache
  82. cache_dict[cache_key] = (0, "")
  83. thread_pool.submit(self._do_build_reply, cache_key, fromUser, message)
  84. query1[cache_key] = False
  85. query2[cache_key] = False
  86. query3[cache_key] = False
  87. # Request again
  88. elif cache[0] == 0 and query1.get(cache_key) == True and query2.get(cache_key) == True and query3.get(cache_key) == True:
  89. query1[cache_key] = False
  90. query2[cache_key] = False
  91. query3[cache_key] = False
  92. elif cache[0] == 1:
  93. reply_text = cache[1]
  94. query1[cache_key] = True
  95. query2[cache_key] = True
  96. query3[cache_key] = True
  97. cache = cache_dict.get(cache_key)
  98. if query1.get(cache_key) == False:
  99. # The first query from wechat official server
  100. logger.debug("[wechatmp] query1 {}".format(cache_key))
  101. query1[cache_key] = True
  102. cnt = 0
  103. while cache[0] == 0 and cnt < 45:
  104. cnt = cnt + 1
  105. time.sleep(0.1)
  106. cache = cache_dict.get(cache_key)
  107. if cnt == 45:
  108. # waiting for timeout (the POST query will be closed by wechat official server)
  109. time.sleep(5)
  110. # and do nothing
  111. return
  112. else:
  113. reply_text = cache[1]
  114. elif query2.get(cache_key) == False:
  115. # The second query from wechat official server
  116. logger.debug("[wechatmp] query2 {}".format(cache_key))
  117. query2[cache_key] = True
  118. cnt = 0
  119. while cache[0] == 0 and cnt < 45:
  120. cnt = cnt + 1
  121. time.sleep(0.1)
  122. cache = cache_dict.get(cache_key)
  123. if cnt == 45:
  124. # waiting for timeout (the POST query will be closed by wechat official server)
  125. time.sleep(5)
  126. # and do nothing
  127. return
  128. else:
  129. reply_text = cache[1]
  130. elif query3.get(cache_key) == False:
  131. # The third query from wechat official server
  132. logger.debug("[wechatmp] query3 {}".format(cache_key))
  133. query3[cache_key] = True
  134. cnt = 0
  135. while cache[0] == 0 and cnt < 45:
  136. cnt = cnt + 1
  137. time.sleep(0.1)
  138. cache = cache_dict.get(cache_key)
  139. if cnt == 45:
  140. # Have waiting for 3x5 seconds
  141. # return timeout message
  142. reply_text = "服务器有点忙,回复任意文字再次尝试。"
  143. logger.info("[wechatmp] Three queries has finished For {}: {}".format(fromUser, message_id))
  144. replyPost = reply.TextMsg(fromUser, toUser, reply_text).send()
  145. return replyPost
  146. else:
  147. reply_text = cache[1]
  148. if float(time.time()) - float(queryTime) > 4.8:
  149. logger.info("[wechatmp] Timeout for {} {}".format(fromUser, message_id))
  150. return
  151. cache_dict.pop(cache_key)
  152. logger.info("{}:{} [wechatmp] Do send {}".format(web.ctx.env.get('REMOTE_ADDR'), web.ctx.env.get('REMOTE_PORT'), reply_text))
  153. replyPost = reply.TextMsg(fromUser, toUser, reply_text).send()
  154. return replyPost
  155. elif isinstance(recMsg, receive.Event) and recMsg.MsgType == 'event':
  156. toUser = recMsg.FromUserName
  157. fromUser = recMsg.ToUserName
  158. content = textwrap.dedent("""\
  159. 感谢您的关注!
  160. 这里是ChatGPT。
  161. 资源有限,回复较慢,请不要着急。
  162. """)
  163. replyMsg = reply.TextMsg(toUser, fromUser, content)
  164. return replyMsg.send()
  165. else:
  166. print("暂且不处理")
  167. return "success"
  168. except Exception as Argment:
  169. print(Argment)
  170. return Argment