Mini Shell

Direktori : /opt/sharedrads/perl/IMH/ShowConns/
Upload File :
Current File : //opt/sharedrads/perl/IMH/ShowConns/Formatters.pm

#!/usr/bin/perl
# encoding: utf-8
#
# author: Kyle Yetter
#

package IMH::ShowConns::Formatters;

our $VERSION = "1.1";

use strict;
use warnings;
use IMH::Terminal;

require Exporter;

our @ISA = qw(Exporter);


our %EXPORT_TAGS = ( 'all' => [ qw(
  tabular_report flat_report
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw( tabular_report flat_report );

sub hjoin;
sub vjoin;
sub flow;
sub build_table_cell;
sub build_group;


our %PORT_NAMES = (
  80   => 'HTTP',
  443  => 'HTTPS',
  2286 => 'WHM',
  2287 => 'WHM(S)',
  2082 => 'cPanel',
  2083 => 'cPanel(S)',
  2095 => 'Webmail',
  2096 => 'Webmail(S)',
  20   => 'FTP (Data)',
  21   => 'FTP',
  783  => 'spamd',
  143  => 'IMAP',
  993  => 'IMAPS',
  110  => 'POP3',
  995  => 'POP3S',
  25   => 'SMTP',
  587  => 'SMTP (Alt)',
  465  => 'SMTPS',
  22   => 'SSH',
  3306 => "MySQL"
);

our %PORT_GROUPS = (
  "HTTP"     => [ 80, 443 ],
  "cPanel"   => [ 2082, 2083 ],
  "WHM"      => [ 2086, 2087 ],
  "Webmail"  => [ 2095, 2096 ],
  "FTP"      => [ 20, 21 ],
  "IMAP"     => [ 143, 993 ],
  "POP3"     => [ 110, 995 ],
  "SMTP"     => [ 25, 587, 465 ],
  "Misc"     => [ 22, 783, 3306 ],
);

our @GROUP_NAMES = qw( HTTP cPanel WHM Webmail IMAP POP3 SMTP FTP Misc );

our %SECTIONS = (
  "WWW"    => [ qw( HTTP cPanel WHM Webmail ) ],
  "Email"  => [ qw( IMAP POP3 SMTP ) ],
  "Other"  => [ qw( FTP Misc ) ]
);

our @SECTION_NAMES = qw( WWW Email Other );

our $screen_width = screen_width - 10;

sub flat_report {
  my ( $data, %options ) = @_;

  my $display_count = $options{ display_count } || 0;

  for my $port ( sort { 0 + $a <=> 0 + $b } keys %$data ) {
    my $port_data = $data->{ $port };
    my $total     = $port_data->{total};
    my $ip_stats  = $port_data->{ips};

    #
    # now, for this port's stat table, extract a list all IP addresses recorded and sort it
    # in ascending order by the number of connections each IP has
    #
    my @ips = sort { $ip_stats->{ $a } <=> $ip_stats->{ $b } } keys %$ip_stats;

    if ( $display_count ) {
      #
      # Select the last 10 entries of the last, which corresponds to the top 10 IPs by number
      # of connections on this port
      #
      my $start = $#ips - $display_count + 1;
      if ( $start > 0 ) {
        @ips = @ips[ $start ... $#ips ];
      }
    }

    for my $ip ( @ips ) {
      printf "%i\t%s\t%i\n", $port, $ip, $ip_stats->{ $ip };
    }
  }
}

sub tabular_report {
  my ( $data, %options ) = @_;

  my $display_count = $options{ display_count } || 10;

  my %tables;

  for my $port ( sort { 0 + $a <=> 0 + $b } keys %$data ) {
    my $port_data = $data->{ $port };
    my $total     = $port_data->{total};
    my $ip_stats  = $port_data->{ips};

    #
    # now, for this port's stat table, extract a list all IP addresses recorded and sort it
    # in ascending order by the number of connections each IP has
    #
    my @ips = sort { $ip_stats->{ $a } <=> $ip_stats->{ $b } } keys %$ip_stats;

    #
    # Select the last 10 entries of the last, which corresponds to the top 10 IPs by number
    # of connections on this port
    #
    my $start = $#ips - $display_count + 1;
    if ( $start > 0 ) {
      @ips = @ips[ $start ... $#ips ];
    }

    my $title = "$port";
    $title .= " - $PORT_NAMES{$port}" if $PORT_NAMES{$port};
    $title .= " ($total)";

    my $table = build_table_cell( $title, map { [ $_, $ip_stats->{ $_ } ] } @ips );
    $table->{total}  = $total;
    $tables{ $port } = $table;
  }

  my %groups;
  for my $name ( @GROUP_NAMES ) {
    my @ports = grep { $tables{ $_ } } @{$PORT_GROUPS{ $name }};
    if ( @ports ) {
      my @group_tables = @tables{ @ports };
      delete @tables{ @ports };
      $groups{$name} = build_group( $name, @group_tables );
    }
  }

  if ( keys %tables ) {
    my @other_ports = sort keys %tables;
    $groups{ "Other" } = build_group( "Other", @tables{@other_ports} );
    push @{ $SECTIONS{ "Other" } }, "Other";
    #push @SECTION_NAMES, "Other";
  }

  for my $name ( @SECTION_NAMES ) {
    my @group_names = grep { $groups{$_} } @{ $SECTIONS{ $name } };
    my @groups      = @groups{ @group_names };
    local $\ = "\n";

    my @section;

    if ( @groups ) {

      while ( @groups ) {
        my $first_group = shift @groups;
        my @row         = ( $first_group );
        my $slack       = $screen_width - $first_group->{width};

        while ( $groups[ 0 ] and $groups[ 0 ]->{width} < $slack ) {
          my $group   = shift @groups;
          $slack     -= $group->{width} + 3;
          push @row, $group;
        }

        my $r = hjoin( '   ', @row );
        push @section, $r;
      }

      my $section_block = vjoin( "\n \n", @section );
      my @section_label_lines = split( //, " $name" );
      my $section_label = {
        lines  => \@section_label_lines,
        height => scalar( @section_label_lines ),
        width  => 1
      };

      my $out = hjoin( ' ', $section_label, $section_block );
      for ( @{ $out->{lines} } ) {
        s<^(\S)> <c( $1, "red" )>e;
        s/[ \t]+$//;
        print;
      }
      print "\n";
    }
  }
}


sub hjoin {
  my ( $joint, @blocks ) = @_;
  my $width  = clen( $joint ) * @blocks;
  my $height = 0;
  my @joined_lines;

  for my $block ( @blocks ) {
    my $h = $block->{height};
    $width += $block->{width};
    $height = $h if $h > $height;
  }

  for my $block ( @blocks ) {
    my $lines = $block->{lines};
    if ( $height > @$lines ) {
      my $pad = ' ' x $block->{width};
      push( @$lines, $pad ) for ( 1 ... $height - @$lines );
    }
  }

  for my $i ( 0 ... $height - 1 ) {
    $joined_lines[ $i ] = join( $joint, map { $_->{lines}->[ $i ] } @blocks );
  }

  return(
    {
      lines  => \@joined_lines,
      width  => $width,
      height => $height
    }
  );
}

sub vjoin {
  my ( $spacer, @blocks ) = @_;

  my @spacer_lines = split( "\n", $spacer );
  my @joined_lines;
  my $width = 0;

  for my $block ( @blocks ) {
    my $w = $block->{width};
    if ( $w > $width ) { $width = $w; }
  }

  for my $i ( 0 ... $#blocks ) {
    my $block = $blocks[ $i ];
    my $lines = $block->{lines};

    if ( $i > 0 ) {
      push @joined_lines, @spacer_lines;
    }

    push( @joined_lines, map { ljust( $_, $width ) } @$lines );
  }

  return(
    {
      lines  => \@joined_lines,
      width  => $width,
      height => scalar( @joined_lines )
    }
  );
}


sub flow {
  my ( $hspacer, $vspacer, @blocks ) = @_;
  my $hspacer_width = clen( $hspacer );

  my @rows;

  while ( @blocks ) {
    my $first_block = shift @blocks;
    my @row         = ( $first_block );
    my $slack       = $screen_width - $first_block->{width};

    while ( $blocks[ 0 ] and $blocks[ 0 ]->{width} < $slack ) {
      my $block   = shift @blocks;
      $slack     -= $block->{width} + $hspacer_width;
      push @row, $block;
    }

    push @rows, hjoin( $hspacer, @row );
  }

  return vjoin( $vspacer, @rows );
}

sub build_table_cell {
  local $\ = "\n";

  my $string = '';
  my @rows = @_;
  my @arrays;
  my @titles;
  my @header_row;
  my @lines;
  my $title = undef;

  for my $item ( @rows ) {
    if ( ref( $item ) eq 'ARRAY' ) {
      push( @arrays, $item );
    } elsif ( ref( \$item ) eq "SCALAR" ) {
      push( @titles, $item );
    }
  }

  unless ( @arrays ) {
    $@ = "build_table_cell: no rows provided";
    return;
  }

  my $ncols = scalar( @{$arrays[ 0 ]} );
  my @widths;

  for my $c ( 0 .. ( $ncols - 1 ) ) {
    my $w = 0;
    for my $row ( @arrays ) {
      my $col = $row->[$c];
      my $col_width = clen( $col );
      if ( $w < $col_width ) { $w = $col_width; }
    }
    $widths[ $c ] = $w;
  }

  my $inner_width = ( $ncols - 1 ) * 3;
  $inner_width += $_ for @widths;

  if ( @titles ) {
    my $title_width = 0;
    for my $t ( @titles ) {
      my $l = clen( $t );
      $title_width = $l if $l > $title_width;
    }

    if ( $title_width > $inner_width ) {
      $widths[-1] += $title_width - $inner_width;
      $inner_width = $title_width;
    }
  }

  if ( ref( \$rows[0] ) eq "SCALAR" ) {
    $title = shift( @rows );

    push @lines, '+-' . ( '-' x $inner_width ) . '-+';
    push @lines, '| ' . center( $title, $inner_width ) . ' |';
  }

  my $mask    = '| ' . join( " | ", map { "%-${_}s" } @widths ) . ' |';
  my $border  = '+-' . join( "-+-", map { '-' x $_  } @widths ) . '-+';
  my $outline = '+-' . ( '-' x $inner_width ) . '-+';

  my $after_title = 1;


  #my @title_row = @{ shift( @rows ) };
  #push @lines, $border;
  #push @lines, '| ' . join( ' | ', map { center( $title_row[ $_ ], $widths[ $_ ] ) } ( 0 ... $#title_row ) ) . ' |';
  #push @lines, $border;
  #$after_title = 0;

  for my $row ( @rows ) {
    if ( ref( $row ) eq 'ARRAY' ) {
      if ( $after_title ) {
        push @lines, $border;
      }
      push @lines, '| ' . join( ' | ', map { ljust( $row->[ $_ ], $widths[ $_ ] ); } (0 ... $#widths) ) . ' |';
      #print( sprintf( $mask, @{ $row } ) );
      $after_title = 0;
    } elsif ( ref( \$row ) eq 'SCALAR' ) {
      if ( $row eq '-' ) {
        push @lines, $after_title ? $outline : $border;
        $after_title = 0;
      } else {
        push @lines, $after_title ? $outline : $border;
        push @lines, '| ' . center( $row, $inner_width ) . ' |';
        $after_title = 1;
      }
    }
  }

  push @lines, $after_title ? $outline : $border;

  return(
    {
      lines  => \@lines,
      width  => $inner_width + 4,
      height => scalar( @lines )
    }
  );
}


sub build_group {
  my ( $title, @tables ) = @_;
  my @rows;
  my $group_total = 0;

  while ( @tables ) {
    my $first_cell = shift @tables;
    my @row        = ( $first_cell );
    my $slack      = $screen_width - $first_cell->{width};

    $group_total += $first_cell->{total};

    while ( $tables[ 0 ] and $tables[ 0 ]->{width} < $slack ) {
      my $cell      = shift @tables;
      $group_total += $cell->{total};
      $slack       -= $cell->{width} + 2;
      push @row, $cell;
    }

    push @rows, hjoin( '  ', @row );
  }

  my $group_block = vjoin( "\n \n", @rows );
  $title = center( "\e[4m$title ($group_total)\e[0m", $group_block->{width} );
  unshift @{$group_block->{lines}}, $title;
  $group_block->{height}++;
  return $group_block;
}


1;
__END__

Zerion Mini Shell 1.0