App-Chart

 view release on metacpan or  search on metacpan

lib/App/Chart/DownloadCost.pm  view on Meta::CPAN

# Download cost recording and calculations.

# Copyright 2007, 2008, 2009, 2010, 2011 Kevin Ryde

# This file is part of Chart.
#
# Chart 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 3, or (at your option) any later version.
#
# Chart 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 Chart.  If not, see <http://www.gnu.org/licenses/>.


package App::Chart::DownloadCost;
use 5.010;
use strict;
use warnings;
use Carp;
use List::Util qw(min max);

use App::Chart;
use App::Chart::Database;
use App::Chart::Download;


sub cost_store_h {
  my ($h) = @_;
  my $key = $h->{'cost_key'};
  my $value = $h->{'cost_value'};
  if (! defined $value && defined $h->{'resp'}) {
    $value = length ($h->{'resp'}->content);
  }
  if (! defined $value) {
    croak "DownloadCost: missing cost_value or resp for cost_key '$key'";
  }
  cost_store ($key, $value);
}

sub cost_store {
  my ($key, $value) = @_;
  App::Chart::Database->write_extra ('', $key, $value);
}

sub cost_get {
  my ($key, $default) = @_;
  my $cost = App::Chart::Database->read_extra ('', $key);
  return (defined $cost ? $cost : $default);
}


# going by day or by symbol
#
# Decide whether to use daily downloads or individual symbol downloads to
# update all of SYMBOL-LIST.  Download will be from the
# `download-start-tdate' of each symbol, up to AVAIL-TDATE.
#
# DAILY-COST is the cost (in bytes) to download a day.
# (SYMBOL-COST-PROC tdate) should return the cost of downloading from TDATE
# to now (ie. AVAIL-TDATE) for a symbol.
# Both costs will get `http-get-cost' added to them automatically.
#
# The return is two values (USE-SYMBOL-LIST TDATE), which is a list of
# symbols to do individually, and a tdate to start from for daily
# downloads.  That tdate is (1+ avail-tdate) when no dailies should be
# done.
#
# As an example, if there's a few symbols quite a bit behind but the rest
# needing just a day or two then the result can be to do the laggards
# individually, then whole days for the most recent.
#

sub by_day_or_by_symbol {
  my (%param) = @_;

  if (! exists $param{'available_tdate'}) { croak 'missing available_tdate'; }
  my $avail = $param{'available_tdate'};

  if (! exists $param{'symbol_list'})     { croak 'missing symbol_list'; }
  my $symbol_list = $param{'symbol_list'};

  my $whole_cost;
  if (exists $param{'whole_cost'}) {
    $whole_cost = $param{'whole_cost'};
  } elsif (exists $param{'whole_cost_key'}) {
    $whole_cost = cost_get ($param{'whole_cost_key'},
                            $param{'whole_cost_default'});
  } else {
    croak 'no whole day cost method';
  }

  my $indiv_cost_proc;
  if (exists $param{'indiv_cost_proc'}) {
    $indiv_cost_proc = $param{'indiv_cost_proc'};
  } elsif (exists $param{'indiv_cost_key'}) {
    my $cost = cost_get ($param{'indiv_cost_key'},
                         $param{'indiv_cost_default'});
    $indiv_cost_proc = sub { return $cost; };
  } elsif (exists $param{'indiv_cost_fixed'}) {
    my $cost = $param{'indiv_cost_fixed'};
    $indiv_cost_proc = sub { return $cost; };
  } elsif (exists $param{'indiv_cost_daily'}) {
    my $indiv_cost_daily = $param{'indiv_cost_daily'};
    $indiv_cost_proc = sub { my ($lo) = @_;
                             return $indiv_cost_daily * ($avail - $lo + 1); };
  } else {
    croak 'no indiv cost method';
  }

  $whole_cost += $App::Chart::option{http_get_cost};

  # tdate => [ symbol, symbol, ... ]
  my %hash = ();
  foreach my $symbol (@$symbol_list) {



( run in 1.703 second using v1.01-cache-2.11-cpan-39bf76dae61 )