File Coverage

blib/lib/Net/DirectConnect/filelist.pm
Criterion Covered Total %
statement 42 272 15.4
branch 0 174 0.0
condition 0 128 0.0
subroutine 14 27 51.8
pod 0 2 0.0
total 56 603 9.2


line stmt bran cond sub pod time code
1             #$Id: filelist.pm 1001 2014-05-07 13:08:30Z pro $ $URL: svn://svn.setun.net/dcppp/trunk/lib/Net/DirectConnect/filelist.pm $
2              
3             =head1 SYNOPSIS
4              
5             generate dc++ xml filelist
6              
7             perl filelist.pm /path/to/dir
8              
9             =cut
10              
11             package # no cpan
12             Net::DirectConnect::filelist;
13 1     1   1636 use 5.10.0;
  1         4  
  1         55  
14 1     1   6 use strict;
  1         3  
  1         42  
15 1     1   6 no strict qw(refs);
  1         2  
  1         27  
16 1     1   5 use warnings "NONFATAL" => "all";
  1         3  
  1         141  
17 1     1   7 no warnings qw(uninitialized);
  1         2  
  1         47  
18 1     1   5 no if $] >= 5.017011, warnings => 'experimental::smartmatch';
  1         3  
  1         9  
19 1     1   60 use utf8;
  1         1  
  1         10  
20 1     1   29 use Encode;
  1         3  
  1         100  
21 1     1   5 use Data::Dumper; #dev only
  1         2  
  1         72  
22             $Data::Dumper::Sortkeys = $Data::Dumper::Useqq = $Data::Dumper::Indent = 1;
23             #use Net::DirectConnect;
24 1     1   7 use Net::DirectConnect::adc;
  1         1  
  1         129  
25             our $VERSION = ( split( ' ', '$Revision: 1001 $' ) )[1];
26              
27             =tofix
28             $0 =~ m|^(.+)[/\\].+?$|; #v0
29             our $root_path ||= $1 . '/' if $1;
30             $root_path =~ s|\\|/|g;
31             warn "rp[$root_path]";
32              
33             eval "use lib '$root_path./stat/pslib'";
34             eval "use lib '$root_path./../../../examples/stat/pslib';
35             use psmisc; use pssql;
36             use Net::DirectConnect;
37             use base 'Net::DirectConnect';
38             "; #use Net::DirectConnect;
39             #psmisc::use_try ('Net::DirectConnect');
40             =cut
41              
42 1     1   20 use base 'Net::DirectConnect';
  1         2  
  1         115  
43             #use lib '../../../examples/stat/pslib'; # REMOVE
44             #use lib 'stat/pslib'; # REMOVE
45 1     1   7 use lib::abs('pslib');
  1         3  
  1         11  
46 1     1   816 use psmisc; # REMOVE
  1         3  
  1         58  
47 1     1   1921 use pssql; # REMOVE
  1         3  
  1         5679  
48             our %config;
49             *config = *main::config;
50             $config{ 'log_' . $_ } //= 0 for qw (dmp dcdmp dcdbg trace);
51             $config{ 'log_' . $_ } //= 1 for qw (screen default);
52             Net::DirectConnect::use_try 'Sys::Sendfile' unless $^O =~ /win/i;
53             Net::DirectConnect::use_try 'Sys::Sendfile::FreeBSD' if $^O =~ /freebsd/i;
54             #Net::DirectConnect::use_try 'IO::AIO';
55             my ( $tq, $rq, $vq );
56              
57             sub skip ($$) {
58 0     0 0   my ( $file, $match ) = @_;
59 0 0         return unless length $match;
60             #say join ' ', ('skptst', $file, $match,);
61 0 0         for my $m ( ref $match eq 'ARRAY' ? @$match : $match ) {
62 0 0 0       return 1 if ref $m eq 'Regexp' and $file =~ $m;
63 0 0 0       return 1 if !ref $m and $file eq $m;
64             }
65             }
66              
67             sub new {
68 0     0 0   my $standalone = !ref $_[0];
69 0 0         my $self = ref $_[0] ? shift() : bless {}, $_[0];
70 0 0         shift if $_[0] eq __PACKAGE__;
71             #local %_ = @_;
72             #$self->{$_} = $_{$_} for keys %_;
73 0           $self->func(@_);
74 0           $self->init_main(@_);
75             $self->{'log'} //= sub (@) {
76 0 0 0 0     my $dc = ref $_[0] ? shift : $self || {};
77             #print "PL[$_[0]]";
78 0           psmisc::printlog shift(), "[$dc->{'number'}]", @_,;
79 0   0       },;
80 0   0       $self->{no_sql} //= 0;
81             #
82             # adjustable
83             #
84 0   0       $self->{files} //= 'files.xml';
85 0   0       $self->{tth_cheat} //= 1_000_000; #try find file with same name-size-date
86 0   0       $self->{tth_cheat_no_date} //= 0; #--//-- only name-size
87 0   0       $self->{file_min} //= 0; #skip files smaller
88 0   0       $self->{filelist_scan} //= 3600 * 1; #every seconds, 0 to disable
89 0   0       $self->{filelist_reload} //= 300; #check and load filelist if new, every seconds
90 0   0       $self->{filelist_fork} //= 1;
91 0   0       $self->{file_send_by} //= 1024 * 1024 * 1;
92 0   0       $self->{skip_hidden} //= 1;
93 0   0       $self->{skip_symlink} //= 0;
94 0 0 0       $self->{skip_dir} //= [ qr'(?:^|/)Incomplete(?:/|$)', ( !$self->{skip_hidden} ? () : qr{(?:^|/)\.} ), ];
95 0 0 0       $self->{skip_file} //=
96             [ qr/\.(?:partial|(?:dc)tmp)$/i, qr/^~uTorrentPartFile_/i, ( !$self->{skip_hidden} ? () : qr{(?:^|/)\.} ), ];
97             # $self->{sharesize_mul} //= 3; # make share bigger * sharefiles_mul
98             # $self->{sharesize_add} //= 10_000_000_000; #add to share size virtual bytes
99             # $self->{sharefiles_mul} //=3; #same for files for keeping size/files rate
100             # $self->{sharefiles_add} //= 10_000;
101             # $self->{no_auto_load_partial} //= 1;
102             #
103             # ==========
104             #
105             #$self->{share_full} //= {};
106             #$self->{share_tth} //= {};
107             ##$config{share_root} //= '';
108 0 0         $self->{'share'} = [ $self->{'share'} ] unless ref $self->{'share'};
109 0 0         tr{\\}{/} for @{ $self->{'share'} || [] };
  0            
110 0           Net::DirectConnect::adc::func($self);
111 0           $self->ID_get();
112             #$self->log('idr:', $self->{'INF'}{'ID'});
113             #$self->ID_get();
114 0 0         unless ( $self->{no_sql} ) {
115             local %_ = (
116             'driver' => 'sqlite',
117             #'dbname' => 'files',
118             'database' => 'files',
119             #'auto_connect' => 1,
120             #'log' => sub { shift if ref $_[0]; $self->log(@_) if $self },
121             'log' => $self->{'log'},
122             #'cp_in' => 'cp1251',
123             'connect_tries' => 0, 'connect_chain_tries' => 0, 'error_tries' => 0, 'error_chain_tries' => 0,
124             #insert_by => 1000,
125             #nav_all => 1,
126             #{}
127             #},
128             'upgrade' => sub {
129 0 0   0     my $db = shift if ref $_[0];
130             $db->do("ALTER TABLE filelist ADD COLUMN $_")
131 0           for 'hit INTEGER UNSIGNED NOT NULL DEFAULT 0 ', 'sch INTEGER UNSIGNED NOT NULL DEFAULT 0 ';
132             #$db->do("UPDATE filelist SET hit=0, sch=0 WHERE hit IS NULL");
133             },
134 0           );
135 0   0       $self->{sql}{$_} //= $_{$_} for keys %_;
136 0           my ($short) = $self->{sql}{'driver'} =~ /mysql/;
137 0 0         my %table = (
    0          
138             'filelist' => {
139             'path' => pssql::row(
140             undef,
141             'type' => 'VARCHAR',
142             'length' => ( $short ? 150 : 255 ),
143             'default' => '',
144             'index' => 1,
145             'primary' => 1
146             ),
147             'file' => pssql::row(
148             undef,
149             'type' => 'VARCHAR',
150             'length' => ( $short ? 150 : 255 ),
151             'default' => '',
152             'index' => 1,
153             'primary' => 1
154             ),
155             'tth' => pssql::row( undef, 'type' => 'VARCHAR', 'length' => 40, 'default' => '', 'index' => 1 ),
156             'size' => pssql::row( undef, 'type' => 'BIGINT', 'index' => 1, ),
157             'time' => pssql::row( 'time', ), #'index' => 1,
158             #'added' => pssql::row( 'added', ),
159             #'exists' => pssql::row( undef, 'type' => 'SMALLINT', 'index' => 1, ),
160             'hit' => pssql::row( undef, 'type' => 'INTEGER UNSIGNED NOT NULL DEFAULT 0 ', ),
161             'sch' => pssql::row( undef, 'type' => 'INTEGER UNSIGNED NOT NULL DEFAULT 0', ),
162             },
163             );
164 0 0         if ( $self->{db} ) {
165             #warn 'preFL',Dumper $self->{db}{table}; #$config{'sql'};
166 0           $self->{db}{table}{$_} = $table{$_} for keys %table;
167 0           $self->{db}{upgrade} = $_{upgrade};
168             }
169 0           local %_ = ( 'table' => \%table, );
170 0   0       $self->{sql}{$_} //= $_{$_} for keys %_;
171             #warn ('sqlore:',Data::Dumper::Dumper $self->{'sql'}, \%_),
172 0 0 0       $self->{db} ||= pssql->new( %{ $self->{'sql'} || {} }, );
  0            
173 0           ( $tq, $rq, $vq ) = $self->{db}->quotes();
174             #$self->log('db', Dumper $self->{db});
175             #$self->log('db', 'flist', $self->{db});
176             }
177             $self->{filelist_make} //= sub {
178 0 0   0     my $self = shift if ref $_[0];
179 0           my $notth;
180 0 0         return unless psmisc::lock( 'sharescan', timeout => 0, old => 86400 );
181             #$self->log( 'err', "sorry, cant load Net::DirectConnect::TigerHash for hashing" ), $notth = 1,
182             # unless Net::DirectConnect::use_try 'Net::DirectConnect::TigerHash'; #( $INC{"Net/DirectConnect/TigerHash.pm"} );
183             #$self->log( 'info',"ntth=[$notth]"); exit;
184 0 0         $self->log( 'err', 'forced db upgrade on make' ), $self->{db}->upgrade() if $self->{upgrade_force};
185 0           my $stopscan;
186 0           my $level = 0;
187 0           my $levelreal = 0;
188 0           my ( $sharesize, $sharefiles );
189 0           my $interrupted;
190             my $printinfo = sub () {
191 0           $self->log( 'sharesize', psmisc::human( 'size', $sharesize ), $sharefiles, scalar keys %{ $self->{share_full} } );
  0            
192 0           };
193 0           local $SIG{INT} = sub { ++$stopscan; ++$interrupted; $self->log( 'warn', "INT rec, stopscan" ) };
  0            
  0            
  0            
194 0           local $SIG{INFO} = sub { $printinfo->(); };
  0            
195             #$self->{'INF'}{'ID'}
196 0 0         psmisc::file_rewrite $self->{files}, qq{
197             {'INF'}{'ID'} ? () : qq{CID="$self->{'INF'}{'ID'}" } ),
198             qq{Base="/" Generator="Net::DirectConnect $Net::DirectConnect::VERSION">
199             };
200             #
201             #};
202 0           my %o;
203 0           my $o = sub { our $n; $o{ $_[0] } = ++$n; @_ };
  0            
  0            
  0            
204 0           our %table2filelist = (
205             $o->( file => 'Name' ),
206             $o->( size => 'Size' ),
207             $o->( tth => 'TTH' ),
208             $o->( time => 'TS' ),
209             $o->( hit => 'HIT' ),
210             $o->( sch => 'SCH' )
211             );
212             #warn Dumper \%o, \%table2filelist;
213             my $filelist_line = sub($) {
214 0           for my $f (@_) {
215 0 0 0       next if !length $f->{file} or !length $f->{'tth'};
216             #$f = {%$f};
217 0           $sharesize += $f->{size};
218 0 0         ++$sharefiles if $f->{size};
219             #$f->{file} = Encode::encode( 'utf8', Encode::decode( $self->{charset_fs}, $f->{file} ) ) if $self->{charset_fs};
220 0           psmisc::file_append $self->{files}, "\t" x $level,
221             #qq{\n};
222             qq{
223 0           map { qq{ $table2filelist{$_}="} . psmisc::html_chars( $a = $f->{$_} ) . qq{"} }
224 0 0         sort { $o{$a} <=> $o{$b} } grep { $table2filelist{$_} and $f->{$_} } keys %$f
  0            
225             ),
226             qq{/>\n};
227             #$self->{share_full}{ $f->{tth} } = $f->{full} if $f->{tth}; $self->{share_full}{ $f->{file} } ||= $f->{full};
228 0   0       $f->{'full'} ||= $f->{'path'} . '/' . $f->{'file'};
229              
230             =cu
231             $self->{share_full}{ $f->{'tth'} } = $f->{'full_local'}, $self->{share_tth}{ $f->{'full_local'} } = $f->{'tth'},
232             $self->{share_tth}{ $f->{'file'} } = $f->{'tth'},
233             if $f->{'tth'};
234             $self->{share_full}{ $f->{'file'} } ||= $f->{'full_local'};
235             =cut
236              
237             #$self->log 'set share', "[$f->{file}], [$f->{tth}] = [$self->{share_full}{ $f->{tth} }],[$self->{share_full}{ $f->{file} }]";
238             #$self->log Dumper $self->{share_full};
239             }
240 0           };
241 0           my $scandir;
242             $scandir = sub (@) {
243 0           for my $dir (@_) {
244             #$self->log( 'scandir', $dir, 'charset', $self->{charset_fs} );
245             #$self->log( 'warn', 'stopscan', $stopscan),
246 0 0         last if $stopscan;
247 0           $dir =~ tr{\\}{/};
248 0           $dir =~ s{/+$}{};
249 0 0         opendir( my $dh, $dir ) or ( $self->log( 'err', "can't opendir [$dir]: $!\n" ), next );
250             #$self->log( 'dev','sd', __LINE__,$dh);
251             #@dots =
252 0           ( my $dirname = $dir );
253 0 0         $dirname =
254             #Encode::encode 'utf8',
255             Encode::decode $self->{charset_fs}, $dirname, Encode::FB_WARN if $self->{charset_fs};
256             #$self->log( 'dev','sd', __LINE__,$dh);
257 0 0 0       next if skip( $dirname, $self->{skip_dir} ) or ( $self->{skip_symlink} and -l $dirname );
      0        
258 0 0         unless ($level) {
259 0           for ( split '/', $dirname ) {
260 0 0         psmisc::file_append( $self->{files}, "\t" x $level, qq{\n} ), ++$level, if length $_;
261             }
262             } else {
263 0           $dirname =~
264             #W s/^\w://;
265             #$dirname =~
266             s{.*/}{};
267 0 0         psmisc::file_append( $self->{files}, "\t" x $level, qq{\n} ), ++$level, ++$levelreal,
268             if length $dirname;
269             }
270             #$self->log( 'dev','sd', __LINE__,$dh);
271             #Net::DirectConnect::
272 0   0       psmisc::schedule( [ 10, 10 ], our $my_every_10sec_sub__ ||= sub { $printinfo->() } );
  0            
273             #$self->log( 'readdir', );
274 0           FILE: for my $file ( readdir($dh) ) {
275             #$self->log( 'scanfile', $file, );
276             #$self->log( 'warn', 'stopscan', $stopscan),
277 0 0         last if $stopscan;
278 0 0         next if $file =~ /^\.\.?$/;
279             #$file = Encode::encode( 'utf8', Encode::decode( $self->{charset_fs}, $file ) ) if $self->{charset_fs};
280 0           my $f = { path => $dir, path_local => $dir, file => $file, file_local => $file, full_local => "$dir/$file", };
281             #$f->{full_local} = "$f->{path_local}/$f->{file_local}";
282             #print("d $f->{full}:\n"),
283 0           $f->{dir} = -d $f->{full_local};
284             #filelist_line($f),
285 0 0         if ( $f->{dir} ) {
286             #next FILE if skip ($f->{file}, $self->{skip_dir});
287 0           $scandir->( $f->{full_local} );
288 0           next;
289             }
290 0 0         $f->{size} = -s $f->{full_local} if -f $f->{full_local};
291 0 0         next if $f->{size} < $self->{file_min};
292 0 0         $f->{file} = #Encode::encode 'utf8',
293             Encode::decode $self->{charset_fs}, $f->{file}, Encode::FB_WARN if $self->{charset_fs};
294 0 0         $f->{path} = #Encode::encode 'utf8',
295             Encode::decode $self->{charset_fs}, $f->{path}, Encode::FB_WARN if $self->{charset_fs};
296 0 0 0       next FILE if skip( $f->{file}, $self->{skip_file} ) or ( $self->{skip_symlink} and -l $f->{file} );
      0        
297             #$self->log( 'encfile', $f->{file} , "chs:$self->{charset_fs}");
298 0           $f->{full} = "$f->{path}/$f->{file}";
299 0           $f->{time} = int( $^T - 86400 * -M $f->{full_local} ); #time() -
300             #$self->log 'timed', $f->{time}, psmisc::human('date_time', $f->{time}), -M $f->{full_local}, int (86400 * -M $f->{full_local}), $^T;
301             #'res=',
302             #join "\n", grep { !/^\.\.?/ and
303             #/^\./ && -f "$dir/$_" }
304             #print " ", $file;
305             #todo - select not all cols
306             # $self->log('preselect', $self->{no_sql});
307 0 0         unless ( $self->{no_sql} ) {
308             #$self->log('select go',);# Dumper $f);
309 0           my $indb =
310             $self->{db}->line( "SELECT * FROM ${tq}filelist${tq} WHERE"
311             . " ${rq}path${rq}="
312             . $self->{db}->quote( $f->{path} )
313             . " AND ${rq}file${rq}="
314             . $self->{db}->quote( $f->{file} )
315             . " AND ${rq}size${rq}="
316             . $self->{db}->quote( $f->{size} )
317             . " AND ${rq}time${rq}="
318             . $self->{db}->quote( $f->{time} )
319             . " LIMIT 1" );
320             #$self->log('select', Dumper $indb);
321             #$self->log ('dev', 'already scaned', $indb->{size}),
322 0 0         $filelist_line->( { %$f, %$indb } ), next, if $indb->{size} ~~ $f->{size};
323             #$db->select('filelist', {path=>$f->{path},file=>$f->{file}, });
324             #$self->log Dumper ;
325             #print "\n";
326             #my $tth;
327 0 0         if ( $f->{size} > $self->{tth_cheat} ) {
328 0 0         my $indb =
329             $self->{db}->line( "SELECT * FROM ${tq}filelist${tq} WHERE "
330             . "${rq}file${rq}="
331             . $self->{db}->quote( $f->{file} )
332             . " AND ${rq}size${rq}="
333             . $self->{db}->quote( $f->{size} )
334             . ( $self->{tth_cheat_no_date} ? () : " AND ${rq}time${rq}=" . $self->{db}->quote( $f->{time} ) )
335             . " LIMIT 1" );
336             #$self->log 'sel', Dumper $indb;
337 0 0         if ( $indb->{tth} ) {
338 0           $self->log( 'dev', "already summed", %$f, ' as ', %$indb );
339 0   0       $f->{$_} ||= $indb->{$_} for keys %$indb;
340             #filelist_line($f);
341             #next;
342             }
343             }
344             }
345 0 0 0       if ( !$notth and !$f->{tth} ) {
346             #$self->log 'calc', $f->{full}, "notth=[$notth]";
347 0           my $time = time();
348 0           $f->{tth} = $self->hash_file( $f->{full_local} );
349 0           my $per = time - $time;
350 0 0 0       $self->log(
351             'time', $f->{full}, psmisc::human( 'size', $f->{size} ),
352             'per', psmisc::human( 'time_period', $per ),
353             'speed ps', psmisc::human( 'size', $f->{size} / ( $per or 1 ) ),
354             'total', psmisc::human( 'size', $sharesize )
355             )
356             if
357             #$f->{size} > 100_000 or
358             $per > 1;
359             }
360             #$f->{tth} = $f->{size} > 1_000_000 ? 'bigtth' : tthfile( $f->{full} ); #if -f $full;
361             #print Dumper $self->{share_full};
362             #next;
363             #print ' ', tthfile($full) if -f $full ; #and -s $full < 1_000_000;
364             #print ' ', $f->{tth};
365             #print ' ', $f->{size}; #if -f $f->{full};
366             #print join ':',-M $f->{full}, $^T + 86400 * -M $f->{full},$f->{time};
367             #print "\n";
368 0           $filelist_line->($f);
369 0 0 0       $self->{db}->insert_hash( 'filelist', $f ) if !$self->{no_sql} and $f->{tth};
370             }
371 0           --$level;
372 0           --$levelreal;
373 0           psmisc::file_append $self->{files}, "\t" x $level, qq{\n}; #
374 0           closedir $dh;
375             }
376 0 0         if ( $levelreal < 0 ) {
377             #psmisc::file_append $self->{files}, "\n";
378 0           psmisc::file_append $self->{files}, "\t" x $level, qq{\n} while --$level >= 0;
379 0           $levelreal = $level = 0;
380             }
381             #$level
382 0           };
383             #else {
384 0 0         $self->log(
385             'info', "making filelist $self->{files} from",
386 0           @_, @{ $self->{'share'} || [] },
387             'EXISTS=',
388 0 0         grep { -d } @_,
389 0           @{ $self->{'share'} || [] },
390             );
391             #$self->{db}->do('ANALYZE filelist') unless $self->{no_sql};
392 0 0         $self->{db}->analyze('filelist') unless $self->{no_sql};
393 0           local %_;
394 0 0         $scandir->($_) for ( grep { !$_{$_}++ and -d } @_, @{ $self->{'share'} || [] }, );
  0 0          
  0            
395             #undef $SIG{INT};
396             #undef $SIG{INFO};
397 0           psmisc::file_append $self->{files}, qq{};
398 0           psmisc::file_append $self->{files};
399 0 0         $self->{db}->flush_insert() unless $self->{no_sql};
400 0           local $_;
401 0 0 0       if (
      0        
402             psmisc::use_try 'IO::Compress::Bzip2'
403             and ($_ = !IO::Compress::Bzip2::bzip2( $self->{files} => $self->{files} . '.bz2' )
404             or $self->log( "bzip2 failed: ", $IO::Compress::Bzip2::Bzip2Error ) and 0 )
405             )
406             {
407             #$self->log('bzip',$self->{files} => $self->{files} . '.bz2');
408 0           () = $IO::Compress::Bzip2::Bzip2Error; #no warning
409             } else {
410 0           $self->log( 'dev', 'using system bzip2', $_, $!, ':', `bzip2 --force --keep "$self->{files}"` );
411             }
412             #unless $interrupted;
413             #$self->{share_full}{ $self->{files} . '.bz2' } = $self->{files} . '.bz2'; $self->{share_full}{ $self->{files} } = $self->{files};
414             #}
415 0           psmisc::unlock('sharescan');
416 0           $printinfo->();
417             #$SIG{INT} = $SIG{KILL} = undef;
418 0           return ( $sharesize, $sharefiles );
419 0   0       };
420             $self->{share_add_file} //= sub {
421 0 0   0     my $self = shift if ref $_[0];
422 0           my ( $full_local, $tth, $file ) = @_;
423 0 0         $full_local =~ m{([^/\\]+)$} unless $file;
424 0   0       $file //= $1; # unless length $file;
425             #$full_local = Encode::encode $self->{charset_fs}, Encode::decode 'utf8', $full_local;
426 0 0         $self->{share_full}{$tth} = $full_local, $self->{share_tth}{$full_local} = $tth, $self->{share_tth}{$file} = $tth, if $tth;
427 0 0 0       $self->{share_full}{$file} ||= $full_local if $file;
428             #$self->share_changed();
429 0   0       };
430             $self->{share_changed} //= sub {
431 0 0   0     my $self = shift if ref $_[0];
432             #$self->log('dev', "share_changed");
433 0 0         if ( $self->{'status'} eq 'connected' ) {
434 0 0         if ( $self->{adc} ) { $self->cmd( 'I', 'INF', undef, 'SS', 'SF' ); }
  0            
435 0           else { $self->cmd('MyINFO'); }
436             }
437 0   0       };
438             $self->{filelist_load} //= sub { #{'cmd'}
439 0 0   0     my $self = shift if ref $_[0];
440 0 0         $self->log( 'err', 'forced db upgrade on load' ), $self->{db}->upgrade() if $self->{upgrade_force};
441              
442             =old
443             if ( $config{filelist} and open my $f, '<', $config{filelist} ) {
444             $self->log "loading filelist..";
445             local $/ = '<';
446             while (<$f>) {
447             if ( my ( $file, $time, $tiger ) = /^File Name="([^"]+)" TimeStamp="(\d+)" Root="([^"]+)"/i ) {
448             #$self->{'share_tth'}{ $params->{TR} }
449             $file =~ tr{\\}{/};
450             $self->{share_full}{$tiger} = $file;
451             $self->{share_tth}{$file} = $tiger;
452             }
453             #
454             }
455             close $f;
456             $self->log ".done:", ( scalar keys %{ $self->{share_full} } ), "\n";
457             }
458             =cut
459              
460             #$self->log( "filelist_load try", $global{shareloaded}, -s $self->{files}, ); #ref $_[0]
461             return
462 0 0 0       if !$self->{files}
      0        
      0        
      0        
463             or $Net::DirectConnect::global{shareloaded} == -s $self->{files}
464             or
465             ( $Net::DirectConnect::global{shareloaded} and !psmisc::lock( 'sharescan', readonly => 1, timeout => 0, old => 86400 ) )
466             or !open my $f, '<:encoding(utf8)', $self->{files};
467 0           my ( $sharesize, $sharefiles );
468             #$self->log( 'info', "loading filelist", -s $f );
469 0           $Net::DirectConnect::global{shareloaded} = -s $f;
470 0           local $/ = '<';
471 0           %{ $self->{share_full} } = %{ $self->{share_tth} } = ();
  0            
  0            
472 0           my $dir;
473 0           while (<$f>) {
474             #
475             #
476 0 0         if ( my ( $file, $size, $tth, $ts ) = m{^File Name="([^"]+)" Size="(\d+)" TTH="([^"]+)"}i ) {
    0          
    0          
477 0           my $full_local = ( my $full = "$dir/$file" );
478             #$self->log 'loaded', $dir, $file , $full;
479             #$full_local = Encode::encode $self->{charset_fs}, $full if $self->{charset_fs};
480 0           $full_local = Encode::encode $self->{charset_fs},
481             #Encode::decode 'utf8',
482             $full_local, Encode::FB_WARN;
483 0           $self->share_add_file( $full_local, $tth, $file );
484 0           ++$sharefiles;
485 0           $sharesize += $size;
486             #$self->{'share_tth'}{ $params->{TR} }
487             #$file =~ tr{\\}{/};
488             } elsif ( my ($curdir) = m{^Directory Name="([^"]+)">}i ) { #"mcedit
489 0 0 0       $dir .= ( ( !length $dir and $^O ~~ [ 'MSWin32', 'cygwin' ] ) ? () : '/' ) . $curdir;
490             #$self->log 'now in', $dir;
491             #$self->{files}
492             } elsif (m{^/Directory>}i) {
493 0           $dir =~ s{(?:^|/)[^/]+$}{};
494             #$self->log 'now ba', $dir;
495             }
496             }
497 0           $self->{share_full}{ $self->{files} . '.bz2' } = $self->{files} . '.bz2';
498 0           $self->{share_full}{ $self->{files} } = $self->{files};
499             # $self->{'INF'}{'SS'} = $self->{'sharesize'} = $sharesize;
500             # $self->{'INF'}{'SF'} = $sharefiles;
501 0           $self->log(
502             'info',
503             "loaded filelist size",
504             $Net::DirectConnect::global{shareloaded},
505             ' : files=', $sharefiles, 'bytes=',
506             psmisc::human( 'size', $sharesize ),
507 0           scalar keys %{ $self->{share_full} },
508             "bzsize=", -s $self->{files} . '.bz2',
509             );
510 0           psmisc::unlock('sharescan');
511             #$_[0]->( $sharesize, $sharefiles ) if ref $_[0] ~~ 'CODE';
512             #( $self->{share_size} , $self->{share_files} ) = ( $sharesize, $sharefiles );
513 0 0         $sharefiles *= $self->{sharefiles_mul} if $self->{sharefiles_mul};
514 0           $sharefiles += $self->{sharefiles_add};
515 0 0         $sharesize *= $self->{sharesize_mul} if $self->{sharesize_mul};
516 0           $sharesize += $self->{sharesize_add};
517 0 0         $self->{sharefiles} = $self->{INF}{SF} = $sharefiles, $self->{INF}{SS} = $self->{sharesize} = $sharesize, if $sharesize;
518 0           $self->share_changed();
519 0           return ( $sharesize, $sharefiles );
520 0   0       };
521             $self->{search_stat_update} = sub {
522 0 0   0     my $self = shift if ref $_[0];
523 0 0         my $tth = shift or return;
524 0   0       my $field = shift || 'hit';
525 0 0         my $updated = $self->{db}->do(
526             "UPDATE ${tq}filelist${tq} SET ${rq}$field${rq}=${rq}$field${rq}+${vq}1${vq} WHERE "
527             #$self->{db}->do( "UPDATE ${tq}filelist${tq} SET ${rq}$field${rq}=${rq}$field${rq}+1 WHERE "
528             #$self->{db}->do( "UPDATE ${tq}filelist${tq} SET $field=$field+1 WHERE "
529             . "${rq}tth${rq}=" . $self->{db}->quote($tth)
530             #. ( $self->{db}{no_update_limit} ? () : " LIMIT ${vq}2${vq}" ) );
531             . ( $self->{db}{no_update_limit} ? () : " LIMIT 1" )
532             );
533 0 0         $self->log( 'dev', "counter $field increased[$updated] on [$tth]" ) if $updated;
534 0           };
535             $self->{handler_int}{Search} //= sub {
536 0 0   0     my $self = shift if ref $_[0];
537             #$self->log ( 'dev', 'Search stat', Dumper @_) ;
538             #$self->log ( 'dev', 'Search stat', Dumper $_[1]{tth}) ;
539 0           $self->search_stat_update( $_[1]{tth}, 'sch' );
540 0   0       };
541             $self->{handler_int}{SCH} //= sub {
542 0 0   0     my $self = shift if ref $_[0];
543             #$self->log ( 'dev', 'SCH stat', Dumper @_) ;
544 0           $self->search_stat_update( $_[-1]{TR}, 'sch' );
545 0   0       };
546             $self->{'periodic'}{ __FILE__ . __LINE__ } = sub {
547 0 0   0     my $self = shift if ref $_[0];
548             #$self->log ( 'periodic in filelist', $self->{filelist_scan}, caller );
549             psmisc::schedule(
550             #[10, $self->{filelist_scan}],
551             $self->{filelist_scan},
552             our $sharescan_sub__ ||= sub {
553 0           my $self = shift;
554 0           $self->log(
555             'info',
556             'filelist actual age seconds:',
557             ( time - $^T + 86400 * -M $self->{files} ),
558             '<', $self->{filelist_scan}
559             );
560             return
561 0 0 0       if -e $self->{files}
      0        
562             and -s $self->{files} > 200
563             and $self->{filelist_scan} > time - $^T + 86400 * -M $self->{files};
564             #$self->log( 'starter==','$0=',$0, $INC{'Net/DirectConnect/filelist.pm'}, $^X, 'share=', @{ $self->{'share'} } );
565             #$0 !~ m{(.*\W)?share.pl$}
566 0           !$self->{'filelist_fork'}
567             ? $self->filelist_make()
568 0           : $self->{'filelist_builder'} ? psmisc::start $self->{'filelist_builder'}, @{ $self->{'share'} } : psmisc::start $^X,
569 0 0         $INC{'Net/DirectConnect/filelist.pm'}, @{ $self->{'share'} };
    0          
570             #: psmisc::startme( 'filelist', grep { -d } @ARGV );
571             },
572 0 0 0       $self
573             ) if $self->{filelist_scan};
574             #Net::DirectConnect::
575             psmisc::schedule(
576             #10, #dev! 300!
577             $self->{filelist_reload},
578             #our $filelist_load_sub__ ||=
579             sub {
580 0           my $self = shift;
581             #psmisc::startme( 'filelist', grep { -d } @ARGV );
582             #my($sharesize,$sharefiles) =
583 0           $self->filelist_load(
584             #sub {
585             #my ( $sharesize, $sharefiles ) = @_;
586             #$dc->{INF}{SS} = $sharesize, $dc->{INF}{SF} = $sharefiles, $dc->{sharesize} = $sharesize, if $sharesize;
587             ##todo! change INF cmd or myinfo
588             #}
589             );
590             },
591 0 0         $self
592             ) if $self->{filelist_scan};
593             },
594             #psmisc::startme( 'filelist', grep { -d } @ARGV ) if !-e $config{files} or !-e $config{files}.'.bz2';
595             $self->{handler_int}{file_recieved} = sub {
596 0 0   0     my $self = shift if ref $_[0];
597 0           my ( $full, $filename ) = @_;
598             #$self->{'file_recv_tth'} =
599 0           my ($tth) = $filename =~ m{^TTH/(\w+)};
600              
601             =z
602             return unless $tth;
603             $self->{share_full}{$tth} = $as;
604             my ($name) = $as =~ m{^([^/\\]+)$};
605             return unless $name;
606              
607             $self->{share_full}{$tth} = $full_local, $self->{share_tth}{$full_local} = $tth, $self->{share_tth}{$file} = $tth,
608             if $tth;
609             $self->{share_full}{$file} ||= $full_local;
610             =cut
611              
612 0 0 0       $self->log( 'dev', 'adding downloaded file to share', $full, $tth ),
613             $self->share_add_file( $full, $tth ), $self->share_changed()
614             if !$self->{'file_recv_filelist'} and !$self->{'no_auto_share_downloaded'}; # unless $self->{'no_auto_share_downloaded'};
615             #TODO $self->{db}->insert_hash( 'filelist', $f ) if !$self->{no_sql} and $f->{tth};
616             ;
617 0           };
618 0 0         $self->filelist_load() unless $standalone; # (caller)[0] ~~ __PACKAGE__;
619             #$self->log('initok');
620 0           return $self;
621             }
622             eval q{ #do
623             use lib '../..';
624             use Net::DirectConnect;
625             print "making\n";
626             __PACKAGE__->new(@ARGV)->{db}->upgrade(), exit if $ARGV[0] eq 'upgrade';
627             __PACKAGE__->new(@ARGV)->filelist_make(@ARGV),;
628             }, print $@ unless caller;
629             1;