package EnsEMBL::Web::TmpFile;
## EnsEMBL::Web::TmpFile - base module to work with temporary files:
## e.g. save them to the tmp storage using driver(s) - either disk or memcached
## see EnsEMBL::Web::TmpFile::* and EnsEMBL::Web::TmpFile::Drivers::* for more info
use strict;
use IO::String;
use HTTP::Request;
use HTTP::Response;
use LWP::UserAgent;
use Digest::MD5 qw(md5_hex);
use EnsEMBL::Web::SpeciesDefs;
use EnsEMBL::Web::TmpFile::Driver::Disk;
use EnsEMBL::Web::TmpFile::Driver::Memcached;
use base qw(Class::Accessor EnsEMBL::Web::Root);
use overload (
'*{}' => '_glob',
'bool' => '_bool',
);
__PACKAGE__->mk_accessors(qw(species_defs content_type format compress drivers exptime));
__PACKAGE__->mk_ro_accessors(qw(full_path prefix extension file_root path_format URL_root URL shortname token));
sub new {
my $class = shift;
my %args = @_;
my $species_defs = delete $args{species_defs} || EnsEMBL::Web::SpeciesDefs->new();
my $drivers = delete $args{drivers}
|| [
EnsEMBL::Web::TmpFile::Driver::Memcached->new,
EnsEMBL::Web::TmpFile::Driver::Disk->new
];
my $self = {
species_defs => $species_defs,
prefix => undef,
filename => undef,
shortname => undef,
extension => undef,
content_type => undef,
content => '',
path_format => 'XXX/X/X/XXXXXXXXXXXXXXX',
full_path => '',
compress => 0,
file_root => $species_defs->ENSEMBL_TMP_DIR,
URL_root => $species_defs->ENSEMBL_TMP_URL,
md5 => '',
URL => '',
drivers => (ref($drivers) eq 'ARRAY') ? $drivers : [ $drivers ],
%args,
};
bless $self, $class;
if ($args{filename}) {
$self->filename($args{filename});
} else {
$self->make_up_filename;
}
return $self;
}
sub _glob {
my $self = shift;
$self->{_glob} ||= IO::String->new($self->{content});
return $self->{_glob};
}
sub _bool {
shift;
}
## Get/Set filename
## -> list of drivers to set - optional
## <- returns list of available drivers
sub filename {
my $self = shift;
if (my $filename = shift) {
my $extension = $self->{extension};
my $prefix = $self->{prefix};
my $file_root = $self->{file_root};
my $URL_root = $self->{URL_root};
## SET extension
if ($extension) {
$filename =~ s/\.\w{1,4}$//g;
$filename .= ".$extension";
}
## Fix file root
$file_root .= "/$prefix"
if $prefix && $file_root !~ m!/$prefix$!;
## Fix URL root
$URL_root .= "/$prefix"
if $prefix && $URL_root !~ m!/$prefix$!;
## Split filename if full path given
if ($filename =~ m!^$file_root/(.*)!) {
$filename = $1;
}
$self->{full_path} = "$file_root/$filename";
$self->{URL} = "$URL_root/$filename";
$self->{filename} = $filename;
$self->{shortname} = $filename;
$self->{shortname} =~ s!^.*/([^/]+)$!$1!g;
}
return $self->{filename};
}
## Creates unique random filename and fixes it's path
## -> $filename /string, optional/
## <- always true
sub make_up_filename {
my $self = shift;
my $filename = shift || $self->{'token'} || $self->ticket;
$self->{'cache'} = 0;
$self->{'token'} = $filename;
$self->filename($self->templatize( $filename, $self->{path_format} ));
}
## Get/Set drivers
## -> list of drivers to set - optional
## <- returns list of available drivers
sub drivers {
my $self = shift;
$self->{drivers} = [ @_ ] if @_;
return @{ $self->{drivers} };
}
## Read-only
## Returns md5 checksum of the file content
sub md5 {
my $self = shift;
$self->{md5} ||= md5_hex($self->content);
return $self->{md5};
}
## Prints to our file
## -> $string /string, mandatory/, prints to our
## (adds string to content and saves)
## <- returns true on success (could die in some cases on failure, depends on driver)
sub print {
my $self = shift;
$self->content(join('', $self->content, @_));
return $self->save;
}
## Saves our file content /$self->content/ to the storage via driver(s)
## -> $content /string, optional/ if specified, replaces $self->content with it and saves
## -> $pararms /hashref, optional/ if specified, uses them for the driver
## uses some default params $pararms if no $pararms given (e.g. 'compress')
## <- returns true on success (could die in some cases on failure, depends on driver)
sub save {
my $self = shift;
my $content = $self->content(shift);
my $params = shift || {};
foreach my $driver ($self->drivers) {
return 1
if $driver && $driver->save($self);
}
return 0;
}
## Sets the content if passed and returns it
sub content {
my $self = shift;
if (@_ && defined $_[0]) {
$self->{'content'} = $_[0];
} else {
$self->retrieve unless $self->{'content'};
}
return $self->{'content'};
}
## Checks if the file exists
sub exists {
my $self = shift;
$self->filename($_[0])
if $_[0];
for my $driver ($self->drivers) {
return 1
if $driver && $driver->exists($self);
}
return 0;
}
## Deletes the file exists
sub delete {
my $self = shift;
$self->filename($_[0])
if $_[0];
for my $driver ($self->drivers) {
return 1
if $driver && $driver->delete($self);
}
return 0;
}
## Retrieves file contents
sub retrieve {
my $self = shift;
my $filename = shift;
$self->filename($filename)
if $filename;
for my $driver ($self->drivers) {
if ($driver && (my $result = $driver->get($self))) {
if (ref($result) eq 'HASH') {
$self->{$_} = $result->{$_} for keys %$result;
return $self->{'content'};
} else {
$self->{'content'} = $result;
return $self->{'content'};
}
}
}
return undef;
}
1;