#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Path::Tiny;
use Time::Moment;
use JSON::MaybeXS qw( decode_json );
use Text::ASCIITable;
use OpenBSD::Unveil;
# Unveil @INC.
foreach my $path (@INC) {
unveil( $path, 'rx' ) or
die "Unable to unveil: $!";
}
# %unveil contains list of paths to unveil with their permissions.
my %unveil = (
"/" => "rx", # Unveil "/", remove this later after profiling with
# ktrace.
"/home" => "", # Veil "/home", we don't want to read it.
"/tmp" => "rwc",
"/dev/null" => "rw",
);
# Unveil each path from %unveil.
keys %unveil;
while( my( $path, $permission ) = each %unveil ) {
unveil( $path, $permission ) or
die "Unable to unveil: $!";
}
my $file = '/tmp/data.json';
my $file_mtime;
# If $file exists then get mtime.
if ( -e $file ) {
my $file_stat = path($file)->stat;
$file_mtime = Time::Moment->from_epoch( $file_stat->[9] );
}
# Fetch latest data only if the local data is older than 8 minutes or
# if the file doesn't exist.
if ( ( not -e $file ) or
( $file_mtime <
Time::Moment->now_utc->minus_minutes(8) ) ) {
require File::Fetch;
# Fetch latest data from api.
my $url = 'https://api.covid19india.org/data.json';
my $ff = File::Fetch->new(uri => $url);
# Save the api response under /tmp.
$file = $ff->fetch( to => '/tmp' ) or
die $ff->error;
}
# Slurp api response to $file_data.
my $file_data = path($file)->slurp;
# Block further unveil calls.
unveil() or
die "Unable to lock unveil: $!";
# Decode $file_data to $json_data.
my $json_data = decode_json($file_data);
# Get statewise information.
my $statewise = $json_data->{statewise};
# Map month number to Months.
my @months = qw( lol Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my $covid_19_data = Text::ASCIITable->new();
$covid_19_data->setCols( 'State',
'Confirmed',
'Active',
'Recovered',
'Deaths',
'Last Updated',
);
$covid_19_data->alignCol( { 'Confirmed' => 'left',
'Recovered' => 'left',
'Deaths' => 'left',
} );
my $state_notes = Text::ASCIITable->new( { drawRowLine => 1 } );
$state_notes->setCols( qw( State Notes ) );
$state_notes->setColWidth( 'Notes', 84 );
my $today = Time::Moment
->now_utc
->plus_hours(5)
->plus_minutes(30); # Current time in 'Asia/Kolkata' TimeZone.
# Add first 37 entries to $rows.
foreach my $i (0...37) {
my $update_info;
my $lastupdatedtime = $statewise->[$i]{lastupdatedtime};
my $last_update_dmy = substr( $lastupdatedtime, 0, 10 );
# Add $update_info.
if ( $last_update_dmy eq $today->strftime( "%d/%m/%Y" ) ) {
$update_info = "Today";
} elsif ( $last_update_dmy eq
$today->minus_days(1)->strftime( "%d/%m/%Y" ) ) {
$update_info = "Yesterday";
} elsif ( $last_update_dmy eq
$today->plus_days(1)->strftime( "%d/%m/%Y" ) ) {
$update_info = "Tomorrow"; # Hopefully we don't see this.
} else {
$update_info =
$months[substr( $lastupdatedtime, 3, 2 )] .
" " .
substr( $lastupdatedtime, 0, 2 );
}
my $state = $statewise->[$i]{state};
$state = "India" if
$state eq "Total";
$state = $statewise->[$i]{statecode} if
length($state) > 16;
my $confirmed = "$statewise->[$i]{confirmed}";
my $recovered = "$statewise->[$i]{recovered}";
my $deaths = "$statewise->[$i]{deaths}";
# Add delta only if it was updated Today.
if ( $update_info eq "Today" ) {
$confirmed .= " (+$statewise->[$i]{deltaconfirmed})";
$recovered .= " (+$statewise->[$i]{deltarecovered})";
$deaths .= " (+$statewise->[$i]{deltadeaths})";
}
$covid_19_data->addRow(
$state,
$confirmed,
$statewise->[$i]{active},
$recovered,
$deaths,
$update_info,
);
$state_notes->addRow(
$state,
$statewise->[$i]{statenotes},
) unless
length($statewise->[$i]{statenotes}) == 0;
}
# Generate tables.
print $covid_19_data;
print $state_notes;