File Coverage

blib/lib/Mojo/Weixin/Message/Handle.pm
Criterion Covered Total %
statement 36 424 8.4
branch 0 282 0.0
condition 0 85 0.0
subroutine 12 27 44.4
pod 4 7 57.1
total 52 825 6.3


line stmt bran cond sub pod time code
1             package Mojo::Weixin;
2 1     1   8 use strict;
  1         2  
  1         45  
3 1     1   7 use Mojo::Weixin::Const qw(%KEY_MAP_USER %KEY_MAP_GROUP %KEY_MAP_GROUP_MEMBER %KEY_MAP_FRIEND %KEY_MAP_MEDIA_CODE);
  1         2  
  1         111  
4 1     1   7 use List::Util qw(first);
  1         2  
  1         109  
5 1     1   402 use Mojo::Weixin::Message;
  1         3  
  1         15  
6 1     1   42 use Mojo::Weixin::Const;
  1         2  
  1         93  
7 1     1   7 use Mojo::Weixin::Message;
  1         3  
  1         4  
8 1     1   795 use Mojo::Weixin::Message::Queue;
  1         3  
  1         37  
9 1     1   442 use Mojo::Weixin::Message::Remote::_upload_media;
  1         3  
  1         31  
10 1     1   432 use Mojo::Weixin::Message::Remote::_get_media;
  1         3  
  1         41  
11 1     1   445 use Mojo::Weixin::Message::Remote::_send_media_message;
  1         3  
  1         29  
12 1     1   716 use Mojo::Weixin::Message::Remote::_send_text_message;
  1         3  
  1         33  
13 1     1   424 use Mojo::Weixin::Message::Remote::_revoke_message;
  1         2  
  1         4925  
14             $Mojo::Weixin::Message::LAST_DISPATCH_TIME = undef;
15             $Mojo::Weixin::Message::SEND_INTERVAL = 3;
16              
17             sub gen_message_queue{
18 0     0 0   my $self = shift;
19             Mojo::Weixin::Message::Queue->new(callback_for_get=>sub{
20 0     0     my $msg = shift;
21 0 0         return if $self->is_stop;
22 0 0         if($msg->class eq "recv"){
    0          
23 0 0         if($msg->format eq "media"){
24 0 0         if($self->download_media){
25             $self->_get_media($msg,sub{
26 0           my ($path,$data,$msg) = @_;
27 0 0 0       if($msg->media_size == 0 and $msg->media_type eq 'emoticon'){
28 0           $msg->content("[表情](获取数据为空,可能需要手机查看)");
29             }
30             else{
31 0           $msg->content( $msg->content. "(". $msg->media_path . ")");
32             }
33 0           $self->emit(receive_media=>$path,$data,$msg);
34 0           $self->emit(receive_message=>$msg);
35 0           });
36             }
37             else{
38 0           $self->emit(receive_message=>$msg);
39             }
40             }
41 0           else{ $self->emit(receive_message=>$msg);}
42             }
43             elsif($msg->class eq "send"){
44 0 0         if($msg->source ne "local"){
45 0           $msg->send_status(code=>0,msg=>"发送成功",info=>"来自其他设备");
46 0 0         if($msg->format eq "media"){
47 0 0         if($self->download_media){
48             $self->_get_media($msg,sub{
49 0           my ($path,$data,$msg) = @_;
50 0 0 0       if($msg->media_size == 0 and $msg->media_type eq 'emoticon'){
51 0           $msg->content("[表情](获取数据为空,可能需要手机查看)");
52             }
53             else{
54 0           $msg->content( $msg->content. "(". $msg->media_path . ")");
55             }
56 0 0         $msg->cb->($self,$msg) if ref $msg->cb eq 'CODE';
57 0           $self->emit(send_media=>$path,$data,$msg);
58 0           $self->emit(send_message=>$msg);
59 0           });
60             }
61             else{
62 0 0         $msg->cb->($self,$msg) if ref $msg->cb eq 'CODE';
63 0           $self->emit(send_message=>$msg);
64             }
65             }
66             else{
67 0 0         $msg->cb->($self,$msg) if ref $msg->cb eq 'CODE';
68 0           $self->emit(send_message=>$msg);
69             }
70 0           return;
71             }
72             #消息的ttl值减少到0则丢弃消息
73 0 0         if($msg->ttl <= 0){
74 0           $self->debug("消息[ " . $msg->id. " ]已被消息队列丢弃,当前TTL: ". $msg->ttl);
75 0           $msg->send_status(code=>-5,msg=>"发送失败",info=>"TTL失效");
76 0 0         if(ref $msg->cb eq 'CODE'){
77 0           $msg->cb->(
78             $self,
79             $msg,
80             );
81             }
82 0           $self->emit(send_message=>
83             $msg,
84             );
85 0           return;
86             }
87 0           my $ttl = $msg->ttl;
88 0           $msg->ttl(--$ttl);
89              
90 0           my $delay = 0;
91 0           my $now = time;
92 0 0         if(defined $Mojo::Weixin::Message::LAST_DISPATCH_TIME){
93 0 0         $delay = $now<$Mojo::Weixin::Message::LAST_DISPATCH_TIME+$Mojo::Weixin::Message::SEND_INTERVAL?
94             $Mojo::Weixin::Message::LAST_DISPATCH_TIME+$Mojo::Weixin::Message::SEND_INTERVAL-$now
95             : 0;
96             }
97             $self->timer($delay,sub{
98 0           $msg->time(time);
99 0 0         if($msg->format eq "text"){
    0          
100 0           $self->_send_text_message($msg);
101             }
102             elsif($msg->format eq "media"){
103 0           $self->_send_media_message($msg);
104             }
105 0           });
106 0           $Mojo::Weixin::Message::LAST_DISPATCH_TIME = $now+$delay;
107             }
108 0           });
109             }
110             sub _parse_synccheck_data{
111 0     0     my @logout_code = qw(1100 1101 1102 1205);
112 0           my $self = shift;
113 0           my($retcode,$selector) = @_;
114 0 0 0       if(defined $retcode and defined $selector){
115 0 0 0       if($retcode == 0 and $selector != 0){
    0 0        
    0 0        
    0          
    0          
116 0           $self->_synccheck_error_count(0);
117 0           $self->_sync();
118             }
119             elsif($retcode == 0 and $selector == 0){
120 0           $self->_synccheck_error_count(0);
121             }
122             elsif($retcode == 1101 and $self->stop_with_mobile){
123 0           $self->stop();
124             }
125 0     0     elsif(first {$retcode == $_} @logout_code){
126 0           $self->relogin($retcode);
127 0           return;
128             }
129             elsif($self->_synccheck_error_count <= 10){
130 0           my $c = $self->_synccheck_error_count;
131 0           $self->_synccheck_error_count(++$c);
132             }
133             else{
134 0           $self->relogin();
135 0           return;
136             }
137             }
138             }
139             sub _parse_sync_data {
140 0     0     my $self = shift;
141 0           my $json = shift;
142 0 0         return if not defined $json;
143 0           my @logout_code = qw(1100 1102 1205);
144 0 0         if($json->{BaseResponse}{Ret} == 1101){#手机端强制下线 或 其他设备登录Web微信
    0          
    0          
145 0           $self->info("收到下线通知");
146 0           $self->logout($json->{BaseResponse}{Ret});
147 0           $self->stop();
148             }
149 0     0     elsif(first {$json->{BaseResponse}{Ret} == $_} @logout_code ){
150 0           $self->relogin($json->{BaseResponse}{Ret});
151 0           return;
152             }
153             elsif($json->{BaseResponse}{Ret} !=0){
154 0           $self->warn("收到无法识别消息代码[$json->{BaseResponse}{Ret}],已将其忽略");
155 0           $self->emit(unknown_retcode=>$json->{BaseResponse}{Ret});
156 0           return;
157             }
158 0 0         $self->sync_key($json->{SyncKey}) if $json->{SyncKey}{Count}!=0;
159 0 0         $self->synccheck_key($json->{SyncCheckKey}) if $json->{SyncCheckKey}{Count}!=0;
160 0 0         $self->skey($json->{SKey}) if $json->{SKey};
161              
162              
163             #群组或联系人变更
164 0 0         if($json->{ModContactCount}!=0){
165 0           for my $e (@{$json->{ModContactList}}){
  0            
166 0 0         if($self->is_group_id($e->{UserName})){#群组
167 0           my $group = {member=>[]};
168 0           for(keys %KEY_MAP_GROUP){
169 0   0       $group->{$_} = $e->{$KEY_MAP_GROUP{$_}} // "";
170             }
171 0 0         if($e->{MemberCount} != 0){
172 0           for my $m (@{$e->{MemberList}}){
  0            
173 0           my $member = {};
174 0           for(keys %KEY_MAP_GROUP_MEMBER){
175 0   0       $member->{$_} = $m->{$KEY_MAP_GROUP_MEMBER{$_}} // "";
176             }
177 0           push @{ $group->{member} }, $member;
  0            
178             }
179             }
180 0           my $g = $self->search_group(id=>$group->{id});
181 0 0         if(not defined $g){#新增群组
182 0 0         if(not $self->update_group($group->{id},1)){
183 0           $self->add_group(Mojo::Weixin::Group->new($group));
184             }
185             }
186             else{#更新已有联系人
187 0           $g->update($group);
188             }
189             }
190             else{#联系人
191 0           my $friend = {};
192 0           for(keys %KEY_MAP_FRIEND){
193 0 0         $friend->{$_} = $e->{$KEY_MAP_FRIEND{$_}} if defined $e->{$KEY_MAP_FRIEND{$_}};
194             }
195 0           my $f = $self->search_friend(id=>$friend->{id});
196 0 0         if(not defined $f){
197 0           $self->add_friend(Mojo::Weixin::Friend->new($friend));
198             }
199 0           else{$f->update($friend)}
200             }
201             }
202             }
203              
204 0 0         if($json->{ModChatRoomMemberCount}!=0){
205            
206             }
207              
208 0 0         if($json->{DelContactCount}!=0){
209 0           for my $e (@{$json->{DelContactList}}){
  0            
210 0 0         if($self->is_group_id($e->{UserName})){
211 0           my $g = $self->search_group(id=>$e->{UserName});
212 0 0         $self->remove_group($g) if defined $g;
213             }
214             else{
215 0           my $f = $self->search_friend(id=>$e->{UserName});
216 0 0         $self->remove_friend($f) if defined $f;
217             }
218             }
219             }
220              
221             #有新消息
222 0 0         if($json->{AddMsgCount} != 0){
223 0           for my $e (@{$json->{AddMsgList}}){
  0            
224 0           my $msg = {};
225 0           for(keys %KEY_MAP_MESSAGE){
226 0   0       $msg->{$_} = $e->{$KEY_MAP_MESSAGE{$_}} // "";
227             }
228 0 0 0       if($e->{MsgType} == 1){#好友消息或群消息
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
229 0           $msg->{format} = "text";
230             }
231             elsif($e->{MsgType} == 3){#图片消息
232 0           $msg->{format} = "media";
233 0           $msg->{media_type} = "image";
234 0           $msg->{media_code} = $e->{MsgType};
235 0           $msg->{media_id} = $msg->{id} . ":" . $msg->{media_code};
236             }
237             elsif($e->{MsgType} == 47){#表情或gif图片
238 0           $msg->{format} = "media";
239 0           $msg->{media_type} = "emoticon";
240 0           $msg->{media_code} = $e->{MsgType};
241 0           $msg->{media_id} = $msg->{id} . ":" . $msg->{media_code};
242             }
243             elsif($e->{MsgType} == 62){#小视频
244 0           $msg->{format} = "media";
245 0           $msg->{media_type} = "microvideo";
246 0           $msg->{media_code} = $e->{MsgType};
247 0           $msg->{media_id} = $msg->{id} . ":" . $msg->{media_code};
248             }
249             elsif($e->{MsgType} == 43){#视频
250 0           $msg->{format} = "media";
251 0           $msg->{media_type} = "video";
252 0           $msg->{media_code} = $e->{MsgType};
253 0           $msg->{media_id} = $msg->{id} . ":" . $msg->{media_code};
254             }
255             elsif($e->{MsgType} == 34){#语音
256 0           $msg->{format} = "media";
257 0           $msg->{media_type} = "voice";
258 0           $msg->{media_code} = $e->{MsgType};
259 0           $msg->{media_id} = $msg->{id} . ":" . $msg->{media_code};
260             }
261             elsif($e->{MsgType} == 37){#好友推荐消息
262 0           $msg->{format} = "text";
263             #$msg->{class} = "recv";
264             #$msg->{type} = "friend_message";
265             #$msg->{receiver_id} = $self->user->id;
266             #$msg->{sender_id} = $e->{FromUserName};
267 0           my $id = $e->{RecommendInfo}{UserName};
268 0           my $displayname = $e->{RecommendInfo}{NickName};
269 0           my $verify = $e->{RecommendInfo}{Content};
270 0           my $ticket = $e->{RecommendInfo}{Ticket};
271             #$msg->data({id=>$id,verify=>$verify,ticket=>$ticket,displayname=>$displayname});
272             #$msg->{content} = "收到[ " . $displayname . " ]好友验证请求:" . ($verify?$verify:"(验证内容为空)");
273 0           $self->_webwxstatusnotify($e->{FromUserName},1);
274 0           $self->emit("friend_request",$id,$displayname,$verify,$ticket);
275 0           next;
276             }
277             elsif($e->{MsgType} == 10000){#群提示消息
278 0           $msg->{format} = "text";
279             }
280             elsif($e->{MsgType} == 10002){#撤回消息
281 0           $msg->{format} = "revoke";
282             }
283             elsif($e->{MsgType} == 49 and $e->{AppMsgType} == 6) {#文件分享
284 0           $msg->{format} = "media";
285 0           $msg->{media_type} = "file";
286 0           $msg->{media_code} = $e->{AppMsgType};
287 0           $msg->{media_id} = $e->{MediaId} . ":" . $e->{AppMsgType};
288 0           $msg->{media_name} = $e->{FileName};
289 0           $msg->{media_size} = $e->{FileSize};
290             }
291             elsif($e->{MsgType} == 49 and $e->{AppMsgType} == 5) {#应用分享
292 0           $msg->{format} = "app";
293 0           $msg->{app_title} = $e->{FileName};
294 0           $msg->{app_url} = $e->{Url};
295             }
296             elsif($e->{MsgType} == 49 and $e->{AppMsgType} == 2000){#转账信息
297 0           $msg->{format} = "payment";
298             }
299             elsif($e->{MsgType} == 42){#名片消息
300 0           $msg->{format} = "card";
301 0           $msg->{card_name} = $e->{RecommendInfo}{NickName};
302 0           $msg->{card_id} = $e->{RecommendInfo}{UserName};
303 0           $msg->{card_province} = $e->{RecommendInfo}{Province};
304 0           $msg->{card_city} = $e->{RecommendInfo}{City};
305 0           $msg->{card_account} = $e->{RecommendInfo}{Alias};
306 0           $msg->{card_sex} = $self->code2sex($e->{RecommendInfo}{Sex});
307             #$msg->{card_avatar} = '';
308             }
309             elsif($e->{MsgType} == 51){#会话、联系人信息同步
310 0 0 0       if($e->{StatusNotifyCode} == 4 or $e->{StatusNotifyCode} == 2){#联系人、群组信息需要同步
311 0           my @id = split /,/,$e->{StatusNotifyUserName};
312 0           my @group_ids;
313             my @friend_ids;
314 0           for (@id){
315 0 0         next if $_ eq $self->user->id;
316 0 0         if($self->is_group_id($_)){push @group_ids,$_ if not $self->search_group(id=>$_);}
  0 0          
317 0 0         else{push @friend_ids,$_ if not $self->search_friend(id=>$_);}
318             }
319 0 0         $self->update_group(@group_ids) if @group_ids;
320 0 0         $self->update_friend(@friend_ids) if @friend_ids;
321             }
322 0           next;
323             }
324 0           else{next;}
325 0 0         if($e->{FromUserName} eq $self->user->id){#发送的消息
326 0           $msg->{source} = 'outer';
327 0           $msg->{class} = "send";
328 0           $msg->{sender_id} = $self->user->id;
329 0 0         if($self->is_group_id($e->{ToUserName})){
330 0           $msg->{type} = "group_message";
331 0           $msg->{group_id} = $e->{ToUserName};
332             }
333             else{
334 0           $msg->{type} = "friend_message";
335 0           $msg->{receiver_id} = $e->{ToUserName};
336             }
337             }
338             #elsif($e->{ToUserName} eq $self->user->id){#接收的消息
339             else{#接收的消息
340 0           $msg->{class} = "recv";
341 0           $msg->{receiver_id} = $self->user->id;
342 0           $msg->{type} = "group_message";
343 0 0         if($self->is_group_id($e->{FromUserName})){#接收到群组消息
344 0           $msg->{group_id} = $e->{FromUserName};
345 0 0         if($e->{MsgType} == 10000){#群提示信息
    0          
346 0           $msg->{type} = "group_notice";
347             }
348             elsif( $msg->{content}=~/^(\@.+?):(.*)$/s ){
349 0           my ($member_id,$content) = ($1,$2);
350 0 0 0       if(defined $member_id and defined $content){
351 0           $msg->{sender_id} = $member_id;
352 0           $msg->{content} = $content;
353             }
354             }
355             }
356             else{#接收到的好友消息
357 0           $msg->{type} = "friend_message";
358 0           $msg->{sender_id} = $e->{FromUserName};
359             }
360             }
361 0 0         if($msg->{format} eq "media"){
    0          
362 0 0         $msg->{content} = '[图片]' if $msg->{media_type} eq "image";
363 0 0         $msg->{content} = '[语音]' if $msg->{media_type} eq "voice";
364 0 0         $msg->{content} = '[视频]' if $msg->{media_type} eq "video";
365 0 0         $msg->{content} = '[小视频]' if $msg->{media_type} eq "microvideo";
366 0 0         $msg->{content} = '[表情]' if $msg->{media_type} eq "emoticon";
367 0 0         $msg->{content} = '[文件]' if $msg->{media_type} eq "file";
368             }
369             elsif(defined $msg->{content}){
370 0           eval{$msg->{content} = Mojo::Util::html_unescape($msg->{content});};
  0            
371 0 0         $self->warn("html entities unescape fail: $@") if $@;
372             }
373 0 0         if($msg->{format} eq "app"){
    0          
    0          
    0          
374 0           eval{
375 0           $msg->{content}=~s//\n/g;
376 0           require Mojo::DOM;
377 0           my $dom = Mojo::DOM->new($msg->{content});
378 0 0         if( $dom->at('msg > appmsg > type')->content != 5){
379 0           $msg->{content} = "[应用分享]标题:$msg->{app_title}\n[应用分享]链接:$msg->{app_url}";
380 0           return;
381             }
382 0           $msg->{app_id} = $dom->at('msg > appmsg')->attr->{appid};
383 0           $msg->{app_title} = $dom->at('msg > appmsg > title')->content;
384 0           $msg->{app_name} = $dom->at('msg > appinfo > appname')->content;
385 0           $msg->{app_url} = $dom->at('msg > appmsg > url')->content;
386 0           $msg->{app_desc} = $dom->at('msg > appmsg > des')->content;
387 0           for( ($msg->{app_title},$msg->{app_desc},$msg->{app_url},$msg->{app_name}) ){
388 0           s//$1/sg;
389             }
390 0           $msg->{app_url} = Mojo::Util::html_unescape($msg->{app_url});
391 0   0       $msg->{content} = "[应用分享]标题:@{[$msg->{app_title} || '未知']}\n[应用分享]描述:@{[$msg->{app_desc} || '未知']}\n[应用分享]应用:@{[$msg->{app_name} || '未知']}\n[应用分享]链接:@{[$msg->{app_url} || '未知']}";
  0   0        
  0   0        
  0   0        
  0            
392             };
393 0 0         if($@){
394 0 0         $self->warn("app message xml parse fail: $@") if $@;
395 0           $msg->{content} = "[应用分享]标题:$msg->{app_title}\n[应用分享]链接:$msg->{app_url}";
396             }
397             }
398             elsif($msg->{format} eq "revoke"){
399             #wxid_8mn2bmkx40so2210726438344835386562261263795
400 0           eval{
401 0           require Mojo::DOM;
402 0           my $dom = Mojo::DOM->new($msg->{content});
403 0 0         return if $dom->at('sysmsg')->attr->{type} ne 'revokemsg';
404             #$msg->{revoke_session} = $dom->at('sysmsg > revokemsg > session')->content;
405 0           $msg->{revoke_id} = $dom->at('sysmsg > revokemsg > msgid')->content;
406 0           $msg->{content} = $dom->at('sysmsg > revokemsg > replacemsg')->content;
407 0           $msg->{content}=~s//$1/g;
408              
409             #纠正自己撤回消息时,消息类型错乱的问题
410 0 0 0       if($msg->{content} eq '你撤回了一条消息' and $msg->{class} eq 'recv'){
411 0           $msg->{class} = 'send';
412 0           $msg->{source} = 'outer';
413 0 0         if($msg->{type} eq "group_message"){
    0          
414 0           $msg->{sender_id} = $msg->{receiver_id};
415 0           delete $msg->{receiver_id};
416             }
417             elsif($msg->{type} eq "friend_message"){
418 0           ($msg->{sender_id},$msg->{receiver_id}) = ($msg->{receiver_id},$msg->{sender_id});
419             }
420             }
421 0           $msg->{content} = "[撤回消息](" . $msg->{content} . ")";
422             };
423 0 0         if($@){
424 0 0         $self->warn("app message xml parse fail: $@") if $@;
425 0           $msg->{content} = "[撤回消息]";
426             }
427             }
428             elsif($msg->{format} eq "card"){
429             #
430 0           $msg->{content}=~s//\n/g;
431 0           eval{
432 0           require Mojo::DOM;
433 0           my $dom = Mojo::DOM->new($msg->{content});
434 0           $msg->{card_avatar} = $dom->at('msg')->attr->{bigheadimgurl};
435 0           $msg->{card_name} = $dom->at('msg')->attr->{nickname};
436 0           $msg->{card_account} = $dom->at('msg')->attr->{alias};
437 0           $msg->{card_province} = $dom->at('msg')->attr->{province};
438 0           $msg->{card_city} = $dom->at('msg')->attr->{city};
439 0           $msg->{card_sex} = $self->code2sex($dom->at('msg')->attr->{sex});
440             };
441 0 0         $self->warn("app message xml parse fail: $@") if $@;
442 0   0       $msg->{content} = "[名片]昵称:@{[$msg->{card_name} || '未知']}\n[名片]性别:@{[$msg->{card_sex} || '未知']}\n[名片]位置:@{[$msg->{card_province} || '未知']} @{[$msg->{card_city} || '未知']}\n[名片]头像:@{[$msg->{card_avatar} || '未知']}";
  0   0        
  0   0        
  0   0        
  0   0        
  0            
443             }
444             elsif($msg->{format} eq 'payment'){
445             #

<![CDATA[微信转账]]>


2000







1










446 0           $msg->{content}=~s//\n/g;
447 0           eval{
448 0           require Mojo::DOM;
449 0           my $dom = Mojo::DOM->new($msg->{content});
450 0           $msg->{content} = $dom->at('msg > appmsg > des')->content;
451 0           $msg->{content}=~s//$1/g;
452             };
453 0 0         $self->warn("payment message xml parse fail: $@") if $@;
454 0           $msg->{content} = "[转账](" . $msg->{content} . ")";
455             }
456 0           $self->message_queue->put(Mojo::Weixin::Message->new($msg));
457             }
458             }
459              
460 0 0         if($json->{ContinueFlag}!=0){
461 0           $self->_sync();
462 0           return;
463             }
464             }
465              
466             sub send_message{
467 0     0 1   my $self = shift;
468 0           my $object = shift;
469 0           my $content = shift;
470 0           my $callback = shift;
471 0 0 0       if( ref($object) ne "Mojo::Weixin::Friend" and ref($object) ne "Mojo::Weixin::Group") {
472 0           $self->error("无效的发送消息对象");
473 0           return;
474             }
475 0     0     my $id = sub{my $r = sprintf "%.3f", rand();$r=~s/\.//g;my $t = $self->now() . $r;return $t}->();
  0            
  0            
  0            
  0            
476 0 0         my $msg = Mojo::Weixin::Message->new(
    0          
    0          
477             id => $id,
478             uid=> $id,
479             content => $content,
480             sender_id => $self->user->id,
481             receiver_id => (ref $object eq "Mojo::Weixin::Friend"?$object->id : undef),
482             group_id =>(ref $object eq "Mojo::Weixin::Group"?$object->id : undef),
483             type => (ref $object eq "Mojo::Weixin::Group"?"group_message":"friend_message"),
484             class => "send",
485             format => "text",
486             from => "code",
487             );
488              
489 0 0         $callback->($self,$msg) if ref $callback eq "CODE";
490 0           $self->emit(before_send_message=>$msg);
491 0           $self->message_queue->put($msg);
492              
493             }
494             my %KEY_MAP_MEDIA_TYPE = reverse %KEY_MAP_MEDIA_CODE;
495             sub send_media {
496 0     0 1   my $self = shift;
497 0           my $object = shift;
498 0           my $media = shift;
499 0           my $callback = shift;
500 0 0 0       if( ref($object) ne "Mojo::Weixin::Friend" and ref($object) ne "Mojo::Weixin::Group") {
501 0           $self->error("无效的发送消息对象");
502 0           return;
503             }
504 0           my $media_info = {};
505 0 0         if(ref $media eq ""){
    0          
506 0           $media_info->{media_path} = $media;
507             }
508             elsif(ref $media eq "HASH"){
509 0           $media_info = $media;
510 0 0         if(defined $media_info->{media_id}){#定义了media_id意味着不会上传文件,忽略media_path
511 0           my ($id,$code) = split(/:/,$media_info->{media_id},2);
512 0 0         $media_info->{media_id} = $id if $id;
513 0 0         $media_info->{media_code} = $code if $code;
514 0 0 0       if(!defined $media_info->{media_code} and defined $media_info->{media_type}){
    0          
515 0   0       $media_info->{media_code} = $KEY_MAP_MEDIA_CODE{$media_info->{media_type}} // 6;
516             }
517             elsif(!defined $media_info->{media_code}){
518 0           $media_info->{media_code} = 6;
519             }
520             }
521 0 0 0       if(defined $media_info->{media_code} and !defined $media_info->{media_type}){
522 0   0       $media_info->{media_type} = $KEY_MAP_MEDIA_TYPE{$media_info->{media_code}} || 'file';
523             }
524              
525             }
526              
527             my $media_type = $media_info->{media_type} eq "image" ? "[图片]"
528             : $media_info->{media_type} eq "emoticon" ? "[表情]"
529             : $media_info->{media_type} eq "video" ? "[视频]"
530             : $media_info->{media_type} eq "microvideo"? "[小视频]"
531             : $media_info->{media_type} eq "voicce" ? "[语音]"
532 0 0         : $media_info->{media_type} eq "file" ? "[文件]"
    0          
    0          
    0          
    0          
    0          
533             : "[文件]"
534             ;
535            
536 0     0     my $id = sub{my $r = sprintf "%.3f", rand();$r=~s/\.//g;my $t = $self->now() . $r;return $t}->();
  0            
  0            
  0            
  0            
537             my $msg = Mojo::Weixin::Message->new(
538             id => $id,
539             uid=> $id,
540             media_id => $media_info->{media_id},
541             media_name => $media_info->{media_name},
542             media_type => $media_info->{media_type},
543             media_code => $media_info->{media_code},
544             media_path => $media_info->{media_path},
545             media_data => $media_info->{media_data},
546             media_mime => $media_info->{media_mime},
547             media_size => $media_info->{media_size},
548             media_mtime => $media_info->{media_mtime},
549             media_ext => $media_info->{media_ext},
550 0 0 0       content => "$media_type(" . ($media_info->{media_path} || $media_info->{media_id}) . ")",
    0          
    0          
551             sender_id => $self->user->id,
552             receiver_id => (ref $object eq "Mojo::Weixin::Friend"?$object->id : undef),
553             group_id =>(ref $object eq "Mojo::Weixin::Group"?$object->id : undef),
554             type => (ref $object eq "Mojo::Weixin::Group"?"group_message":"friend_message"),
555             class => "send",
556             format => "media",
557             );
558              
559 0 0         $callback->($self,$msg) if ref $callback eq "CODE";
560 0           $self->message_queue->put($msg);
561             }
562              
563             sub upload_media {
564 0     0 0   my $self = shift;
565 0           my $opt = shift;
566 0           my $callback = pop;
567 0           my $msg = Mojo::Weixin::Message->new(%$opt);
568             $self->_upload_media($msg,sub{
569 0     0     my($msg,$json) = @_;
570 0 0         $callback->({
571             media_id => $msg->media_id,
572             media_code => $msg->media_code,
573             media_type => $msg->media_type,
574             media_path => $msg->media_path,
575             media_name => $msg->media_name,
576             media_size => $msg->media_size,
577             media_mime => $msg->media_mime,
578             media_mtime => $msg->media_mtime,
579             media_ext => $msg->media_ext,
580             }) if ref $callback eq "CODE";
581 0           });
582             }
583             sub reply_message{
584 0     0 1   my $self = shift;
585 0           my $msg = shift;
586 0           my $content = shift;
587 0           my $callback = shift;
588 0 0         if($msg->class eq "recv"){
    0          
589 0 0         if($msg->type eq "group_message"){
    0          
590 0           $self->send_message($msg->group,$content,$callback);
591             }
592             elsif($msg->type eq "friend_message"){
593 0           $self->send_message($msg->sender,$content,$callback);
594             }
595             }
596             elsif($msg->class eq "send"){
597 0 0         if($msg->type eq "group_message"){
    0          
598 0           $self->send_message($msg->group,$content,$callback);
599             }
600             elsif($msg->type eq "friend_message"){
601 0           $self->send_message($msg->receiver,$content,$callback);
602             }
603              
604             }
605             }
606              
607             sub reply_media_message {
608 0     0 1   my $self = shift;
609 0           my $msg = shift;
610 0           my $media = shift;
611 0           my $callback = shift;
612 0 0         if($msg->class eq "recv"){
    0          
613 0 0         if($msg->type eq "group_message"){
    0          
614 0           $self->send_media($msg->group,$media,$callback);
615             }
616             elsif($msg->type eq "friend_message"){
617 0           $self->send_media($msg->sender,$media,$callback);
618             }
619             }
620             elsif($msg->class eq "send"){
621 0 0         if($msg->type eq "group_message"){
    0          
622 0           $self->send_media($msg->group,$media,$callback);
623             }
624             elsif($msg->type eq "friend_message"){
625 0           $self->send_media($msg->receiver,$callback);
626             }
627              
628             }
629             }
630             sub revoke_message {
631 0     0 0   my $self = shift;
632 0           my ($msg_id, $receiver_id);
633 0 0         if(not $_[0]){
    0          
634 0           $self->error("撤回消息失败: 无效的msg对象或者msg_id");
635 0           return;
636             }
637             elsif(ref $_[0] eq "Mojo::Weixin::Message"){
638 0 0         if( not $_[0]->is_success){
639 0           $self->error("撤回消息失败: 无法撤回未成功发送的消息");
640 0           return;
641             }
642 0           $_[0]->dump;
643 0           $msg_id = $_[0]->id;
644 0 0         $receiver_id = $_[0]->type eq 'group_message'?$_[0]->group_id:$_[0]->receiver_id;
645 0 0 0       if(not defined $msg_id or not defined $receiver_id){
646 0           $self->error("撤回消息失败: msg对象中包含无效的msg_id");
647 0           return;
648             }
649             }
650             else{
651 0           ($msg_id, $receiver_id) = $_[0] =~ /^([^:]+):(.+)$/;
652 0 0 0       if(not defined $msg_id or not defined $receiver_id){
653 0           $self->error("撤回消息失败: 无效的msg_id");
654 0           return;
655             }
656             }
657 0           my $ret = $self->_revoke_message($msg_id,$receiver_id);
658 0 0         if($ret){
659 0           $self->debug("消息[$msg_id]撤回成功");
660             }
661             else{
662 0           $self->debug("消息[$msg_id]撤回失败");
663             }
664 0           return $ret;
665             }
666              
667              
668             1;