# # Copyright (c) 2004-2007 - Consultas, PKG.fr # # This file is part of A2P. # # A2P is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # A2P is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with A2P; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # $Id: Converter.pm 3 2007-10-18 16:20:19Z guillaume $ # package A2P::Converter; # Derived class from Thread.pm use base qw(A2P::Thread AFPDS::afpds2tex); use strict ; use integer ; use Fcntl ':flock'; use A2P::Globals ; use A2P::Syslog ; use AFPDS::afpds2tex ; use A2P::Com qw( IsCom GetCom comJOB comREQ ); use A2P::Tools qw( ShortID ) ; BEGIN { our $VERSION = sprintf "%s", q$Rev: 717 $ =~ /(\d[0-9.]+)\s+/ ; } our $VERSION ; my $LCK ; my $self ; ################################################################################ ## Converter code ## ################################################################################ sub Do { $self = shift ; my $ref = shift ; my $Ret = 0 ; my @Job = &IsCom( comJOB , $$ref ); if ( @Job == 2 ) { my ( $Job , $file ) = @Job ; # Keep internal stats &UPSTAT('CONV_REQ'); #-------------------------------------- # It's a file to convert by default #-------------------------------------- my $startpos = 0 ; # Check if we were ask to start an AFP file at a given position ( $file, $startpos ) = ( $1, $2 ) if ( $file =~ /^(.*):(\d+)$/ ); &Debug( "Requested to convert '$file' for Job $Job". ( $startpos ? ", beginning at pos $startpos" : "" ) ); # Get folder without trailing '/' my ( $jobfolder ) = $SHMDIR =~ m|(.*[^/]+)/?$| ; my ( $base ) = $file =~ m|([^/]+)$| ; # Get file basename $jobfolder .= "/$Job-$base" ; # Found a free folder to compute AFPDS file my ( $newfolder , $tries ) = ( $jobfolder , 10 ); while ( $tries-- ) { $! = 0 ; # Use standard Perl locking as we are working on our filesystem undef $LCK ; open($LCK, '>>', $newfolder.".LCK") or $self->ThisError("Can't open $newfolder.LCK lock file: $!"), $Ret ++, last ; # Try non blocking exclusive lock my $locked = flock($LCK, LOCK_EX | LOCK_NB); &Debug("Can't lock '$newfolder.LCK': $locked, $!") unless $locked ; # Don't use this folder name if folder exists or we don't have lock last unless ( ! $locked or -d $newfolder ); close($LCK); $newfolder = $jobfolder . '-' . &ShortID(5) ; } $jobfolder = $newfolder ; if ( ! -d $jobfolder ) { &Debug("Starting '$base' conversion in '$jobfolder' for Job $Job"); # self->{JOB} is necessary to return some informations to JobManager # when conversion thread failed abnormally # (see A2P/Thread.pm, DESTROY sub) $self->{JOB} = $Job ; $Ret = $self->ConvertFile( $jobfolder, $file, $Job, $startpos ); $self->{JOB} = "" ; &Debug("Conversion of '$base' returned with value $Ret") if $Ret ; # Keep internal stats $Ret ? &UPSTAT('BAD_CONV_REQ') : &UPSTAT('GOOD_CONV_REQ') ; # Check to handle splitting case if ( !$Ret and defined($self->{AFPDS}) and $self->{AFPDS}->issplitted() ) { # Set splitting event, JobManager handles it as also DONE answer $Ret = $self->{AFPDS}->getEnv ; # Freeing object delete $self->{AFPDS} ; } # Now return conversion status $Ret = DONE unless $Ret ; $self->Return( $Job , $Ret ); $self->AnswerDone( $Job ); # LCK file will be purge by JobManager during step 12 # This will release the lock on the folder } else { # Keep internal stats &UPSTAT('BAD_CONV_JOBFOLDER'); $Ret = 50 ; # Return an error status $self->Return( $Job , $Ret ); $self->AnswerDone( $Job ); } } else { # Keep internal stats &UPSTAT('BAD_CONV_REQFORMAT'); $self->ThisError("Got bad conversion request '$$ref'"); $Ret ++ ; if (@Job) { # Return exec status even for bad format to not break job processing $self->Return( $Job[0] , $Ret ); $self->AnswerDone( $Job[0] ); } } return $Ret == DONE ? 1 : 0 ; } sub ThreadInit { $self = shift ; # Initializes stat headers $self->{STATHEADERS} = [ qw( Date DayTime JobID Jobname DestId PageDef FormDef DocName PageFormats CopyGroups Logos NbPages Type LockId ) ]; $self->{HAVE_STATS} = 1 ; } sub END { return unless (defined($self) and defined($self->{JOB}) and $self->{JOB}); print $self->getName . ": END step: $self->{JOB}\n"; # Return an error status &Warn("Unexpected abort condition reached on '$self->{JOB}'"); $self->Return( $self->{JOB} , 254 ); $self->AnswerDone( $self->{JOB} ); } &Debug("Module " . __PACKAGE__ . " v$VERSION loaded"); 1;