Apache-UploadMeter

 view release on metacpan or  search on metacpan

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    # of the users are going to be using the bundled JS code, or forking from
    # it, meaning they already have what they need.
    # The other 5% are writing from scratch; hopefully embedding into some non-
    # browser based application.  They most likely want XML anyway, and its
    # their life that I want to make easier :-)
    my $format = $req->param("format") || "XML";

    my $currenttime = time();
    my $starttime=$hook_cache->get($hook_id."starttime") || $currenttime;
  
    # JSON response
    if ($format=~/^json$/i) {
        # Hardcode object for now.  No need to require YAML or YAML::Syck as prereq
        my $json=sprintf('{"meter_id":"%s","filename":"%s","finished":%d,"status":{"timestamp":%d,"start":%d,"received":%d,"total":%d}}',
                         $hook_id, $fname, $finished, $currenttime, $starttime, $len, $size);
        $r->content_type("application/json");
        $r->set_content_length(length($json));
        $r->print($json) unless $r->header_only;
        return Apache2::Const::OK;
    }
    # XML response (legacy)

    # This is better done in the XSL, I think.  I want to minimize Apache's work here and leave the browser to calculate the stuff.  What I may eventually do is create a second XSL stylesheet which translates the "minimal" formatting into this format...
    # Calculate total rate and current rate
    my $lastupdatetime = $hook_cache->get($hook_id."lastupdatetime");
    my $lastupdatelen = $hook_cache->get($hook_id."lastupdatelen");
    my $currentrate = int (($len - $lastupdatelen) / ($currenttime - $lastupdatetime)) if ($currenttime != $lastupdatetime);
    my $rate = int ($len / ($currenttime - $starttime)) if ($currenttime != $starttime);
    $hook_cache->set($hook_id."lastupdatetime", $currenttime);
    $hook_cache->set($hook_id."lastupdatelen", $len);
    
    # Calculate elapsed and remaining time
    my $etime = $currenttime - $starttime;
    my $rtime = ($finished) ? 0 : int ($etime / $len * $size) - $etime;

    # Format values for easy display
    my $fsize = Number::Format::format_bytes($size, 2);
    my $flen = Number::Format::format_bytes($len, 2);
    my $fetime = Date::Format::time2str('%H:%M:%S', $etime, 'GMT');
    my $frtime = Date::Format::time2str('%H:%M:%S', $rtime, 'GMT');
    my $fcurrentrate = Number::Format::format_bytes($currentrate, 2).'/s';
    my $frate = Number::Format::format_bytes($rate, 2).'/s';

    # build the Refresh url
    my $args=$r->args;
    if ($initial_request) { $args=$args.(defined($args)?"&":"")."returned=1";}
    if ($finished) {
    	# Cleanup the cache since we are finished
# Not needed.  The hook automatically dumps values every 15 minutes for this reason.  - Issac.  But a purge is probably needed somewhere else for a global scale

        $hook_cache->remove($hook_id."finished");
        $hook_cache->remove($hook_id."len");
        $hook_cache->remove($hook_id."name");
        $hook_cache->remove($hook_id."size");
        $hook_cache->remove($hook_id."starttime");
        $hook_cache->remove($hook_id."lastupdaterate");
        $hook_cache->remove($hook_id."lastupdatelen");
	$hook_cache->clear;
	$hook_cache->purge; #best I can do for now...
    } else {
    	# Set a refresh header so the meter gets updated
	my $uri = APR::URI->parse($r->pool, $r->uri);
	$uri->scheme($ENV{HTTPS}?"https":"http");
	$uri->port($r->server->port ? $r->server->port : APR::URI::port_of_scheme($uri->scheme));
	$uri->path($r->uri);
	$uri->hostname($r->server->server_hostname);
	$uri->query($args);
        $r->headers_out->add("Refresh"=>"5;url=".$uri->unparse());
    }
    $r->content_type('text/xml');
    return Apache2::Const::OK if $r->header_only;
    my $config = $r->pnotes("Apache::UploadMeter::Config");
    my $meter = $config->("UploadMeter") || $r->uri;
    my $xsl="$meter/styles/xml/aum.xsl";
    my $xsd="$meter/styles/xml/aum.xsl";
    my $out= <<EOF;
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="$xsl"?>
<APACHE_UPLOADMETER METER_ID="$hook_id" FILE="$fname" FINISHED="$finished" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="$xsd">
    <RECEIVED VALUE="$len">$flen</RECEIVED>
    <TOTAL VALUE="$size">$fsize</TOTAL>
    <ELAPSEDTIME VALUE="$etime">$fetime</ELAPSEDTIME>
    <REMAININGTIME VALUE="$rtime">$frtime</REMAININGTIME>
    <RATE VALUE="$rate">$frate</RATE>
    <CURRENTRATE VALUE="$currentrate">$fcurrentrate</CURRENTRATE>
</APACHE_UPLOADMETER>
EOF

    $r->print($out);
    return Apache2::Const::OK;
}

# Form fixup
sub uf_handler
{
    my $r=shift;
    $r->no_cache(1); # CRITICAL!  No caching allowed!
    $r->set_last_modified(time());
    $r->err_headers_out->add("Expires" => Apache2::Util::ht_time($r->pool));
    my $digest=Digest::SHA1::sha1_hex(time,(defined $r->subprocess_env('HTTP_HOST') ? $r->subprocess_env('HTTP_HOST') : 0),(defined $r->subprocess_env('HTTP_X_FORWARDED_FOR') ?$r->subprocess_env('HTTP_X_FORWARDED_FOR') : 0 ));
    $r->pnotes("u_id"=>$digest);
    return Apache2::Const::OK;
}

### Support handlers (for debugging)

# Simple response handler for displaying upload information
sub r_handler
{
    my $r=shift;
    my $req = APR::Request::Apache2->handle($r);
    $r->no_cache(1);
    my $uploads=$req->upload;
    $r->content_type('text/plain');
    return Apache2::Const::OK if $r->header_only;
    $r->print("Results:\n");
    while (my ($field, $upload) = each %$uploads) {
	$r->print("Parsed upload field $field:\n\tFilename: ".$upload->upload_filename());
	$r->print("\n\tSize: ".$upload->upload_size()."\n\n");
    }
    $r->print("Done\n");



( run in 2.185 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )