The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/extlib/lib/perl5";
use lib "$FindBin::Bin/lib";
use File::Basename;
use Getopt::Long;
use Plack::Loader;
use Plack::Builder;
use Plack::Builder::Conditionals;
use Plack::Util;
use GrowthForecast;
use GrowthForecast::Web;
use GrowthForecast::Worker;
use Proclet;
use File::ShareDir qw/dist_dir/;
use Cwd;
use File::Path qw/mkpath/;
use Log::Minimal;
use Pod::Usage;

my $port = 5125;
my $host = 0;
my @front_proxy;
my @allow_from;
Getopt::Long::Configure ("no_ignore_case");
GetOptions(
    'port=s' => \$port,
    'host=s' => \$host,
    'front-proxy=s' => \@front_proxy,
    'allow-from=s' => \@allow_from,
    'disable-1min-metrics' => \my $disable_short,
    'with-mysql=s' => \my $mysql,
    'data-dir=s' => \my $data_dir,
    'log-format=s' => \my $log_format,
    'web-max-workers=i' => \my $web_max_workers,
    "h|help" => \my $help,
);

if ( $help ) {
    pod2usage(-verbose=>2,-exitval=>0);
}

if ( $mysql ) {
    eval { require  GrowthForecast::Data::MySQL };
    die "Cannot load MySQL: $@" if $@;
}

my $root_dir = File::Basename::dirname(__FILE__);
if ( ! -f "$root_dir/lib/GrowthForecast.pm" ) {
    $root_dir = dist_dir('GrowthForecast');
}
if ( !$data_dir ) {
    $data_dir = $root_dir . '/data';
}
else {
    $data_dir = Cwd::realpath($data_dir);
}

{
    if ( ! -d $data_dir ) {
        mkpath($data_dir) or die "cannot create data directory '$data_dir': $!";
    }
    open( my $fh, '>', "$data_dir/$$.tmp") or die "cannot create file in data_dir: $!";
    close($fh);
    unlink("$data_dir/$$.tmp");
}

my $proclet = Proclet->new;
$proclet->service(
    code => sub {
        local $0 = "$0 (GrowthForecast::Worker 1min)";
        my $worker = GrowthForecast::Worker->new(
            root_dir => $root_dir,
            data_dir => $data_dir,
            mysql => $mysql,
        );
        $worker->run('short');        
    }
) if !$disable_short;

$proclet->service(
    code => sub {
        local $0 = "$0 (GrowthForecast::Worker)";
        my $worker = GrowthForecast::Worker->new(
            root_dir => $root_dir,
            data_dir => $data_dir,
            mysql => $mysql
        );
        $worker->run;
    }
);

$proclet->service(
    code => sub {
        local $0 = "$0 (GrowthForecast::Web)";
        my $web = GrowthForecast::Web->new(
            root_dir => $root_dir,
            data_dir => $data_dir,
            short => !$disable_short,
            mysql => $mysql,
        );
        my $app = builder {
            enable 'Lint';
            enable 'StackTrace';
            if ( @front_proxy ) {
                enable match_if addr(\@front_proxy), 'ReverseProxy';
            }
            if ( @allow_from ) {
                enable match_if addr('!',\@allow_from), sub {
                    sub { [403,['Content-Type','text/plain'], ['Forbidden']] }
                };
            }
            enable sub {
                my $app = shift;
                sub {
                    my $env = shift;
                    my $res = $app->($env);
                    Plack::Util::response_cb($res, sub {
                                                 my $res = shift;
                                                 Plack::Util::header_set($res->[1], 'X-Powered-By', 
                                                                         'GrowthForecast/'.$GrowthForecast::VERSION);
                                             });
                }
            };
            enable 'Static',
                path => qr!^/(?:(?:css|js|images)/|favicon\.ico$)!,
                root => $root_dir . '/public';
            enable 'Scope::Container';
            if ($log_format) {
                my %args;
                if ($log_format eq 'combined') {
                    %args = (combined => 1);
                }
                elsif ($log_format eq 'ltsv') {
                    %args = (ltsv => 1);
                }
                else {
                    %args = (format => $log_format);
                }
                enable 'AxsLog', %args;
            }
            $web->psgi;
        };
        my $loader = Plack::Loader->load(
            'Starlet',
            port => $port,
            host => $host || 0,
            max_workers => $web_max_workers || 4,
        );
        infof( "GrowthForecast::Web starts listen on %s:%s", $host || 0, $port );
        $loader->run($app);
    }
);


$proclet->run;

__END__

=head1 NAME

growthforecast.pl - Lightning Fast Graphing/Visualization

=head1 SYNOPSIS

  % growthforecast.pl --data-dir=/path/to/dir

=head1 DESCRIPTION

GrowthForecast is graphing/visualization web tool built on RRDtool

=head1 INSTALL

=over 4

=item Install dependencies

To install growthforecast, these libraries are needed.

=over 4

=item * glib

=item * xml2

=item * pango

=item * cairo

=back

  (CentOS) $ sudo yum groupinstall "Development Tools"
           $ sudo yum install pkgconfig glib2-devel gettext libxml2-devel pango-devel cairo-devel
  
  (Ubuntu) $ sudo apt-get build-dep rrdtool

=item Install GrowthForecast

  $ cpanm GrowthForecast

It's recommended to using perlbrew

=back

=head1 OPTIONS

=over 4

=item --data-dir

A directory to store rrddata and metadata

=item --port

TCP port listen on. Default is 5125

=item --host

IP address to listen on

=item --front-proxy

IP addresses or CIDR of reverse proxy

=item --allow-from

IP addresses or CIDR to allow access from.
Default is empty (allow access from any remote ip address)

=item --disable-1min-metrics

don't generate 1min rrddata and graph
Default is "1" (enabled) 

=item --with-mysql

DB connection setting to store  metadata. format like dbi:mysql:[dbname];hostname=[hostnaem]
Default is no mysql setting. GrowthForecast save metadata to SQLite

=item --web-max-workers

Number of web server processes. Default is 4


=item -h --help

Display help

=back

=head1 MYSQL Setting

GrowthForecast uses SQLite as metadata by default. And also supports MySQL

GrowthForecast needs these MySQL privileges.

=over 4

=item * CREATE

=item * ALTER

=item * DELETE

=item * INSERT

=item * UPDATE

=item * SELECT

=back

Sample GRANT statement

  mysql> GRANT statement sample> GRANT  CREATE, ALTER, DELETE, INSERT, UPDATE, SELECT \\
           ON growthforecast.* TO 'www'\@'localhost' IDENTIFIED BY foobar;

Give USERNAME and PASSWORD to GrowthForecast by environment value

  $ MYSQL_USER=www MYSQL_PASSWORD=foobar growthforecast.pl \\
      --data-dir /home/user/growthforeacst \\
      -with-mysql dbi:mysql:growthforecast;hostname=localhost 

AUTHOR
    Masahiro Nagano <kazeburo {at} gmail.com>

LICENSE
    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.