package IPCFile; use strict; use FileHandle; sub new { my ($this, $file, $maxlog, $logno) = @_; my $class = ref($this) || $this; my $self = {}; bless($self, $class); $self->{"file"} = $file; ($maxlog=1024*1024) unless( $maxlog ); ($logno=7) unless( $logno ); $self->{"maxlog"} = $maxlog; $self->{"logno"} = $logno; $self->{"mintime"} = 30 * 60; $self->{"nexttime"} = time + ($self->{"mintime"}); return $self; } sub set_rotate_hook { my( $self, $callback ) = @_; $self->{"rotatehook"} = $callback; } sub log { my( $self, $text ) = @_; return unless( $text ); unless( $self->{"outfh"} ) { $self->_nextoutfile(); } return unless( $self->{"outfh"} ); $text = (time)." ".$text."\n"; my $fh = $self->{"outfh"}; print $fh $text; $self->{"size"} += length( $text ); if( ($self->{"size"} > $self->{"maxlog"}) && (time -$self->{"createtime"} > $self->{"mintime"} )) { $self->_nextoutfile(); } } sub _nextoutfile { my( $self ) = @_; if( $self->{"outfh"} ) { close $self->{"outfh"}; $self->{"outfh"} = undef; } my $nextname = ($self->{"file"}).(time)."."; for( my $index=0; ($index<100) && (-f $nextname.$index); $index++ ) {;} my $fh = new FileHandle(); unless( open( $fh, ">$nextname" ) ) { BigSister::common::log( "err", "could not create interprocess communication file $nextname" ); Platform::poll_sleep(10); } $self->{"size"} = 0; $self->{"createtime"} = time; $self->{"outfh"} = $fh; my $oldfh = select $fh; select $fh; $| = 1; select $oldfh; my $i=0; while( 1 ) { last if( open( _STAMP, ">".($self->{"file"}) ) && (print _STAMP ":$nextname:\n") && close( _STAMP ) ); select( undef,undef,undef, 0.5 ); if( $i++ == 10 ) { BigSister::common::log( "warning", "cannot create file $self->{'file'} - trying again but this is probably an error" ); } } my $dir = $self->{"file"}; my $file = $self->{"file"}; $file =~ s#.*/##; $dir =~ s#\Q$file\E$##; opendir( _DIR, $dir ); foreach my $name (readdir( _DIR )) { if( $name =~ /^\Q$file\E[\d\.]+$/ ) { my $candidate = $dir.$name; next if( $candidate eq $nextname ); my $mtime = ((stat($candidate))[9]); next if( time-$mtime < 1800 ); unlink( $candidate ); } } } sub read { my( $self ) = @_; unless( $self->{"readfh"} ) { $self->_nextinputfile(); } my $fh = $self->{"readfh"}; return( undef ) unless( $fh ); seek( $fh, $self->{"readpos"}, 0 ) || return undef; my $text = <$fh> if( $text ) { $text = $self->{"readbuffer"}.$text; $self->{"readbuffer"} = ""; $self->{"readpos"} = tell( $fh ); unless( $text =~ /[\r\n]$/ ) { $self->{"readbuffer"} = $text; return undef; } chomp $text; $text =~ /^(\d+) (.*)$/; return( $1, $2 ); } $self->_checkreadnext(); } sub skipread { my( $self ) = @_; return unless( $self->{"readfh"} ); seek( $self->{"readfh"}, 0, 2 ); $self->{"readpos"} = tell( $self->{"readfh"} ); } sub _nextinputfile { my( $self ) = @_; if( $self->{"readfh"} ) { close( $self->{"readfh"} ); $self->{"readfh"} = undef; } my $newfile; my $mtime = ((stat($self->{"file"}))[9]); unless( open( _FILEN, "<$self->{'file'}" ) && ($newfile=<_FILEN>) && ($newfile =~ /^:(.*):[\r\n]*$/) ) { close _FILEN; return; } close _FILEN; $newfile = $1; my $fh = new FileHandle(); unless( open( $fh, "<$newfile" ) ) { $self->{"readwarned"} || BigSister::common::log( "err", "cannot open interprocess communication file $newfile" ); $self->{"readwarned"} = 1; return; } $self->{"readwarned"} = 0; $self->{"readfh"} = $fh; $self->{"readstamp"} = $mtime; $self->{"readpos"} = 0; } sub _checkreadnext { my( $self ) = @_; if( $self->{"readfh"} ) { my $mtime = ((stat($self->{"file"}))[9]); return if( $mtime == $self->{"readstamp"} ); } $self->_nextinputfile(); } 1; |