File Coverage

blib/lib/Mojo/Webqq/Util.pm
Criterion Covered Total %
statement 18 240 7.5
branch 0 108 0.0
condition 0 78 0.0
subroutine 6 34 17.6
pod 0 27 0.0
total 24 487 4.9


line stmt bran cond sub pod time code
1             package Mojo::Webqq::Util;
2 1     1   9 use Carp qw();
  1         2  
  1         31  
3 1     1   5 use Encode qw();
  1         2  
  1         20  
4 1     1   5 use IO::Handle;
  1         2  
  1         40  
5 1     1   503 use Mojo::JSON qw();
  1         22275  
  1         29  
6 1     1   9 use Mojo::Util qw();
  1         2  
  1         18  
7 1     1   413 use Mojo::Webqq::Counter;
  1         3  
  1         2734  
8             sub new_counter {
9 0     0 0   my $self = shift;
10 0           return Mojo::Webqq::Counter->new(client=>$self,@_);
11             }
12             sub url_escape {
13 0     0 0   my $self = shift;
14 0           return Mojo::Util::url_escape(@_);
15             }
16              
17             sub slurp {
18 0     0 0   my $self = shift;
19 0           my $path = shift;
20              
21 0 0         open my $file, '<', $path or Carp::croak qq{Can't open file "$path": $!};
22 0           my $ret = my $content = '';
23 0           while ($ret = $file->sysread(my $buffer, 131072, 0)) { $content .= $buffer }
  0            
24 0 0         Carp::croak qq{Can't read from file "$path": $!} unless defined $ret;
25              
26 0           return $content;
27             }
28             sub spurt {
29 0     0 0   my $self = shift;
30 0           my ($content, $path) = @_;
31 0 0         open my $file, '>', $path or Carp::croak qq{Can't open file "$path": $!};
32 0 0         defined $file->syswrite($content)
33             or Carp::croak qq{Can't write to file "$path": $!};
34 0           return $content;
35             }
36             sub encode{
37 0     0 0   my $self = shift;
38 0           return Mojo::Util::encode(@_);
39             }
40             sub decode{
41 0     0 0   my $self = shift;
42 0           return Mojo::Util::decode(@_);
43             }
44              
45             sub encode_utf8{
46 0     0 0   my $self = shift;
47 0           return Mojo::Util::encode("utf8",@_);
48             }
49              
50             sub from_json{
51 0     0 0   my $self = shift;
52 0           my $r = eval{
53 0 0         if($self->json_codec_mode == 0){
    0          
54 0           my $json = Mojo::JSON::from_json(@_);
55 0           $json;
56             }
57             elsif($self->json_codec_mode == 1){
58 0           my $json = Mojo::JSON::decode_json(@_);
59 0           $self->reform($json);
60 0           $json;
61             }
62             else{
63 0           my $json = Mojo::JSON::from_json(@_);
64 0           $json;
65             }
66             };
67 0 0         if($@){
68 0           $self->warn($@);
69 0           $self->warn(__PACKAGE__ . "::from_json return undef value");
70 0           return undef;
71             }
72             else{
73 0 0         $self->warn(__PACKAGE__ . "::from_json return undef value") if not defined $r;
74 0           return $r;
75             }
76             }
77             sub to_json{
78 0     0 0   my $self = shift;
79 0           my $r = eval{
80 0           Mojo::JSON::to_json(@_);
81             };
82 0 0         if($@){
83 0           $self->warn($@);
84 0           $self->warn(__PACKAGE__ . "::to_json return undef value");
85 0           return undef;
86             }
87             else{
88 0 0         $self->warn(__PACKAGE__ . "::to_json return undef value") if not defined $r;
89 0           return $r;
90             }
91             }
92             sub decode_json{
93 0     0 0   my $self = shift;
94 0           my $r = eval{
95 0           Mojo::JSON::decode_json(@_);
96             };
97 0 0         if($@){
98 0           $self->warn($@);
99 0           $self->warn(__PACKAGE__ . "::decode_json return undef value");
100 0           return undef;
101             }
102             else{
103 0 0         $self->warn(__PACKAGE__ . "::decode_json return undef value") if not defined $r;
104 0           return $r;
105             }
106             }
107             sub encode_json{
108 0     0 0   my $self = shift;
109 0           my $r = eval{
110 0           Mojo::JSON::encode_json(@_);
111             };
112 0 0         if($@){
113 0           $self->warn($@);
114 0 0         $self->warn(__PACKAGE__ . "encode_json return undef value") if not defined $r;
115 0           return undef;
116             }
117             else{
118 0 0         $self->warn(__PACKAGE__ . "encode_json return undef value") if not defined $r;
119 0           return $r;
120             }
121             }
122              
123             sub safe_truncate {
124 0     0 0   my $self = shift;
125 0           my $input = shift;
126 0 0         return $input if not defined $input;
127 0   0       my $truncate_length = shift // 21;
128              
129 0 0         return $input if (length($input) < $truncate_length);
130              
131 0           my @bytes = unpack('C*', $input);
132 0           my $i = 0;
133 0           while (1)
134             {
135 0           my $utf8_bytes;
136 0 0 0       if (($bytes[$i] & 0x80) == 0) {
    0 0        
    0 0        
    0          
137 0           $utf8_bytes = 1;
138             }
139             elsif (($bytes[$i] & 0xc0) != 0 and ($bytes[$i] & 0x20) == 0) {
140 0           $utf8_bytes = 2;
141             }
142             elsif (($bytes[$i] & 0xe0) != 0 and ($bytes[$i] & 0x10) == 0) {
143 0           $utf8_bytes = 3;
144             }
145             elsif (($bytes[$i] & 0xf0) != 0 and ($bytes[$i] & 0x08) == 0) {
146 0           $utf8_bytes = 4;
147             }
148             else {
149 0           $utf8_bytes = 1;
150             }
151              
152 0 0         if ($i + $utf8_bytes > $truncate_length) {
    0          
153 0           last;
154             }
155             elsif ($i + $utf8_bytes == $truncate_length) {
156 0           $i = $truncate_length;
157 0           last;
158             }
159             else {
160 0           $i += $utf8_bytes;
161             }
162             }
163 0           return substr($input, 0, $i);
164             }
165              
166             sub truncate {
167 0     0 0   my $self = shift;
168 0   0       my $out_and_err = shift || '';
169 0           my %p = @_;
170 0   0       my $max_bytes = $p{max_bytes} || 200;
171 0   0       my $max_lines = $p{max_lines} || 8;
172 0           my $is_truncated = 0;
173 0 0         if(length($out_and_err)>$max_bytes){
174 0           $out_and_err = substr($out_and_err,0,$max_bytes);
175 0           $is_truncated = 1;
176             }
177 0           my @l =split /\n/,$out_and_err,$max_lines+1;
178 0 0         if(@l>$max_lines){
179 0           $out_and_err = join "\n",@l[0..$max_lines-1];
180 0           $is_truncated = 1;
181             }
182 0 0         return $out_and_err. ($is_truncated?"\n(已截断)":"");
183             }
184             sub code2state {
185 0     0 0   my $self = shift;
186 0           my %c = qw(
187             10 online
188             20 offline
189             30 away
190             40 hidden
191             50 busy
192             60 callme
193             70 silent
194             );
195 0   0       return $c{$_[0]} || "online";
196             }
197             sub code2client {
198 0     0 0   my $self = shift;
199 0           my %c = qw(
200             1 pc
201             21 mobile
202             24 iphone
203             41 web
204             );
205 0   0       return $c{$_[0]} || 'unknown';
206             }
207              
208             sub reform{
209 0     0 0   my $self = shift;
210 0           my $ref = shift;
211 0           my %opt = @_;
212 0   0       my $unicode = $opt{unicode} // 0;
213 0   0       my $recursive = $opt{recursive} // 1;
214 0           my $cb = $opt{filter};
215 0   0       my $deep = $opt{deep} // 0;
216 0 0         if(ref $ref eq 'HASH'){
    0          
217 0           my @reform_hash_keys;
218 0           for (keys %$ref){
219 0 0 0       next if ref $cb eq "CODE" and !$cb->("HASH",$deep,$_,$ref->{$_});
220 0 0         if($_ !~ /^[[:ascii:]]+$/){
221 0 0 0       if($unicode and not Encode::is_utf8($_)){
    0 0        
222 0           push @reform_hash_keys,[ $_,Encode::decode_utf8($_) ];
223             }
224             elsif(!$unicode and Encode::is_utf8($_)){
225 0           push @reform_hash_keys,[ $_,Encode::encode_utf8($_) ];
226             }
227             }
228            
229 0 0 0       if(ref $ref->{$_} eq ""){
    0 0        
230 0 0 0       if($unicode and not Encode::is_utf8($ref->{$_}) ){
    0 0        
231 0           Encode::_utf8_on($ref->{$_});
232             }
233             elsif( !$unicode and Encode::is_utf8($ref->{$_}) ){
234 0           Encode::_utf8_off($ref->{$_});
235             }
236             }
237             elsif( $recursive and ref $ref->{$_} eq "ARRAY" or ref $ref->{$_} eq "HASH"){
238 0           $self->reform($ref->{$_},@_,deep=>$deep+1);
239             }
240             #else{
241             # $self->die("不支持的hash结构\n");
242             #}
243             }
244              
245 0           for(@reform_hash_keys){ $ref->{$_->[1]} = delete $ref->{$_->[0]} }
  0            
246             }
247             elsif(ref $ref eq 'ARRAY'){
248 0           for(@$ref){
249 0 0 0       next if ref $cb eq "CODE" and !$cb->("ARRAY",$deep,$_);
250 0 0 0       if(ref $_ eq ""){
    0 0        
251 0 0 0       if($unicode and not Encode::is_utf8($_) ){
    0 0        
252 0           Encode::_utf8_on($_);
253             }
254             elsif( !$unicode and Encode::is_utf8($_) ){
255 0           Encode::_utf8_off($_);
256             }
257             }
258             elsif($recursive and ref $_ eq "ARRAY" or ref $_ eq "HASH"){
259 0           $self->reform($_,@_,deep=>$deep+1);
260             }
261             #else{
262             # $self->die("不支持的hash结构\n");
263             #}
264             }
265             }
266             else{
267 0           $self->die("不支持的数据结构");
268             }
269 0           $self;
270             }
271              
272             sub array_diff{
273 0     0 0   my $self = shift;
274 0           my $old = shift;
275 0           my $new = shift;
276 0           my $compare = shift;
277 0           my $old_hash = {};
278 0           my $new_hash = {};
279 0           my $added = [];
280 0           my $deleted = [];
281 0           my $same = {};
282              
283 0           my %e = map {$compare->($_) => undef} @{$new};
  0            
  0            
284 0           for(@{$old}){
  0            
285 0 0         unless(exists $e{$compare->($_)}){
286 0           push @{$deleted},$_;
  0            
287             }
288             else{
289 0           $same->{$compare->($_)}[0] = $_;
290             }
291             }
292              
293 0           %e = map {$compare->($_) => undef} @{$old};
  0            
  0            
294 0           for(@{$new}){
  0            
295 0 0         unless(exists $e{$compare->($_)}){
296 0           push @{$added},$_;
  0            
297             }
298             else{
299 0           $same->{$compare->($_)}[1] = $_;
300             }
301             }
302 0           return $added,$deleted,[values %$same];
303             }
304              
305             sub array_unique {
306 0     0 0   my $self = shift;
307 0           my $array = shift;
308 0           my $diff = shift;
309 0           my $info = shift;
310 0           my @result;
311             my %info;
312 0           my %tmp;
313 0           for(@$array){
314 0           my $id = $diff->($_);
315 0           $tmp{$id}++;
316             }
317 0           my $i = 0;
318 0           for(@$array){
319 0           my $id = $diff->($_);
320 0 0         next if not exists $tmp{$id} ;
321 0 0         if($tmp{$id}>1){
322 0 0         $self->debug("$info array_unique id duplicate: [$id]($tmp{$id})") if defined $info;
323 0           $i++;
324 0           next;
325             }
326 0           push @result,$_;
327 0 0         $info{$id} = $_ if wantarray;
328             }
329 0 0 0       $self->debug("$info array_unique id duplicate total count: $i") if defined $info and $i >0;
330 0 0         return wantarray?(\@result,\%info):\@result;
331             }
332             sub die{
333 0     0 0   my $self = shift;
334 0     0     local $SIG{__DIE__} = sub{$self->log->fatal(@_);exit -1};
  0            
  0            
335 0           Carp::confess(@_);
336             }
337             sub info{
338 0     0 0   my $self = shift;
339 0           $self->log->info(@_);
340 0           $self;
341             }
342             sub msg{
343 0     0 0   my $self = shift;
344 0           $self->log->msg(@_);
345 0           $self;
346             }
347             sub warn{
348 0     0 0   my $self = shift;
349             ref $_[0] eq 'HASH' ?
350 0 0 0       ($_[0]->{level_color} //= 'yellow' and $_[0]->{content_color} //= 'yellow')
351             : unshift @_,{level_color=>'yellow',content_color=>'yellow'};
352 0           $self->log->warn(@_);
353 0           $self;
354             }
355             sub error{
356 0     0 0   my $self = shift;
357             ref $_[0] eq 'HASH' ?
358 0 0 0       ($_[0]->{level_color} //= 'red' and $_[0]->{content_color} //= 'red')
359             : unshift @_,{level_color=>'red',content_color=>'red'};
360 0           $self->log->error(@_);
361 0           $self;
362             }
363             sub fatal{
364 0     0 0   my $self = shift;
365             ref $_[0] eq 'HASH' ?
366 0 0 0       ($_[0]->{level_color} //= 'red' and $_[0]->{content_color} //= 'red')
367             : unshift @_,{level_color=>'red',content_color=>'red'};
368 0           $self->log->fatal(@_);
369 0           $self;
370             }
371             sub debug{
372 0     0 0   my $self = shift;
373             ref $_[0] eq 'HASH' ?
374 0 0 0       ($_[0]->{level_color} //= 'blue' and $_[0]->{content_color} //= 'blue')
375             : unshift @_,{level_color=>'blue',content_color=>'blue'};
376 0           $self->log->debug(@_);
377 0           $self;
378             }
379             sub print {
380 0     0 0   my $self = shift;
381 0 0         $self->log->info({time=>'',level=>'',}, join defined $,?$,:'',@_);
382 0           $self;
383             }
384             sub stdout_line {
385 0     0 0   my $self = shift;
386 0           my $data = $_[0];
387 0           $data=~s/[\r\n]+$//s;
388 0           STDOUT->printflush($data . "\n");
389 0           $self;
390             }
391              
392             1;