11# -*- coding: utf-8 -*- 
22import  io 
3+ import  os 
4+ import  time 
35import  imghdr 
46import  requests 
57from  bridge .context  import  * 
1113from  common .singleton  import  singleton 
1214from  config  import  conf 
1315
16+ import  asyncio 
17+ from  threading  import  Thread 
18+ 1419import  web 
1520# If using SSL, uncomment the following lines, and modify the certificate path. 
1621# from cheroot.server import HTTPServer 
@@ -25,19 +30,20 @@ class WechatMPChannel(ChatChannel):
2530 def  __init__ (self , passive_reply = True ):
2631 super ().__init__ ()
2732 self .passive_reply  =  passive_reply 
28-  self .flag  =  0 
29- 33+  self .NOT_SUPPORT_REPLYTYPE  =  [] 
34+ self . client = WechatMPClient () 
3035 if  self .passive_reply :
31-  self .NOT_SUPPORT_REPLYTYPE  =  [ReplyType .IMAGE , ReplyType .VOICE ]
3236 # Cache the reply to the user's first message 
3337 self .cache_dict  =  dict ()
3438 # Record whether the current message is being processed 
3539 self .running  =  set ()
3640 # Count the request from wechat official server by message_id 
3741 self .request_cnt  =  dict ()
38-  else :
39-  self .NOT_SUPPORT_REPLYTYPE  =  []
40-  self .client  =  WechatMPClient ()
42+  # The permanent media need to be deleted to avoid media number limit 
43+  self .delete_media_loop  =  asyncio .new_event_loop ()
44+  t  =  Thread (target = self .start_loop , args = (self .delete_media_loop ,))
45+  t .setDaemon (True )
46+  t .start ()
4147
4248
4349 def  startup (self ):
@@ -49,18 +55,63 @@ def startup(self):
4955 port  =  conf ().get ("wechatmp_port" , 8080 )
5056 web .httpserver .runsimple (app .wsgifunc (), ("0.0.0.0" , port ))
5157
58+  def  start_loop (self , loop ):
59+  asyncio .set_event_loop (loop )
60+  loop .run_forever ()
61+ 62+  async  def  delete_media (self , media_id ):
63+  logger .info ("[wechatmp] media {} will be deleted in 10s" .format (media_id ))
64+  await  asyncio .sleep (10 )
65+  self .client .delete_permanent_media (media_id )
66+  logger .info ("[wechatmp] media {} has been deleted" .format (media_id ))
5267
5368 def  send (self , reply : Reply , context : Context ):
5469 receiver  =  context ["receiver" ]
5570 if  self .passive_reply :
56-  logger .info ("[wechatmp] reply to {} cached:\n {}" .format (receiver , reply ))
57-  self .cache_dict [receiver ] =  reply .content 
71+  if  reply .type  ==  ReplyType .TEXT  or  reply .type  ==  ReplyType .INFO  or  reply .type  ==  ReplyType .ERROR :
72+  reply_text  =  reply .content 
73+  logger .info ("[wechatmp] reply to {} cached:\n {}" .format (receiver , reply_text ))
74+  self .cache_dict [receiver ] =  ("text" , reply_text )
75+  elif  reply .type  ==  ReplyType .VOICE :
76+  voice_file_path  =  reply .content 
77+  logger .info ("[wechatmp] voice file path {}" .format (voice_file_path ))
78+  with  open (voice_file_path , 'rb' ) as  f :
79+  filename  =  receiver  +  "-"  +  context ["msg" ].msg_id  +  ".mp3" 
80+  media_id  =  self .client .upload_permanent_media ("voice" , (filename , f , "audio/mpeg" ))
81+  # 根据文件大小估计一个微信自动审核的时间,审核结束前返回将会导致语音无法播放,这个估计有待验证 
82+  f_size  =  os .fstat (f .fileno ()).st_size 
83+  print (f_size )
84+  time .sleep (1.0  +  2  *  f_size  /  1024  /  1024 )
85+  logger .info ("[wechatmp] voice reply to {} uploaded: {}" .format (receiver , media_id ))
86+  self .cache_dict [receiver ] =  ("voice" , media_id )
87+  elif  reply .type  ==  ReplyType .IMAGE_URL : # 从网络下载图片 
88+  img_url  =  reply .content 
89+  pic_res  =  requests .get (img_url , stream = True )
90+  print (pic_res .headers )
91+  image_storage  =  io .BytesIO ()
92+  for  block  in  pic_res .iter_content (1024 ):
93+  image_storage .write (block )
94+  image_storage .seek (0 )
95+  image_type  =  imghdr .what (image_storage )
96+  filename  =  receiver  +  "-"  +  context ["msg" ].msg_id  +  "."  +  image_type 
97+  content_type  =  "image/"  +  image_type 
98+  media_id  =  self .client .upload_permanent_media ("image" , (filename , image_storage , content_type ))
99+  logger .info ("[wechatmp] image reply to {} uploaded: {}" .format (receiver , media_id ))
100+  self .cache_dict [receiver ] =  ("image" , media_id )
101+  elif  reply .type  ==  ReplyType .IMAGE : # 从文件读取图片 
102+  image_storage  =  reply .content 
103+  image_storage .seek (0 )
104+  image_type  =  imghdr .what (image_storage )
105+  filename  =  receiver  +  "-"  +  context ["msg" ].msg_id  +  "."  +  image_type 
106+  content_type  =  "image/"  +  image_type 
107+  media_id  =  self .client .upload_permanent_media ("image" , (filename , image_storage , content_type ))
108+  logger .info ("[wechatmp] image reply to {} uploaded: {}" .format (receiver , media_id ))
109+  self .cache_dict [receiver ] =  ("image" , media_id )
58110 else :
59111 if  reply .type  ==  ReplyType .TEXT  or  reply .type  ==  ReplyType .INFO  or  reply .type  ==  ReplyType .ERROR :
60112 reply_text  =  reply .content 
61113 self .client .send_text (receiver , reply_text )
62114 logger .info ("[wechatmp] Do send to {}: {}" .format (receiver , reply_text ))
63- 64115 elif  reply .type  ==  ReplyType .VOICE :
65116 voice_file_path  =  reply .content 
66117 logger .info ("[wechatmp] voice file path {}" .format (voice_file_path ))
@@ -69,7 +120,6 @@ def send(self, reply: Reply, context: Context):
69120 media_id  =  self .client .upload_media ("voice" , (filename , f , "audio/mpeg" ))
70121 self .client .send_voice (receiver , media_id )
71122 logger .info ("[wechatmp] Do send voice to {}" .format (receiver ))
72- 73123 elif  reply .type  ==  ReplyType .IMAGE_URL : # 从网络下载图片 
74124 img_url  =  reply .content 
75125 pic_res  =  requests .get (img_url , stream = True )
@@ -85,7 +135,6 @@ def send(self, reply: Reply, context: Context):
85135 media_id  =  self .client .upload_media ("image" , (filename , image_storage , content_type ))
86136 self .client .send_image (receiver , media_id )
87137 logger .info ("[wechatmp] sendImage url={}, receiver={}" .format (img_url , receiver ))
88- 89138 elif  reply .type  ==  ReplyType .IMAGE : # 从文件读取图片 
90139 image_storage  =  reply .content 
91140 image_storage .seek (0 )
@@ -95,7 +144,6 @@ def send(self, reply: Reply, context: Context):
95144 media_id  =  self .client .upload_media ("image" , (filename , image_storage , content_type ))
96145 self .client .send_image (receiver , media_id )
97146 logger .info ("[wechatmp] sendImage, receiver={}" .format (receiver ))
98- 99147 return 
100148
101149 def  _success_callback (self , session_id , context , ** kwargs ): # 线程异常结束时的回调函数 
0 commit comments