#!/usr/bin/perl
# receive uploaded images

use CGI;
use CGI::Carp qw(fatalsToBrowser);
use POSIX;
use strict;

$CGI::POST_MAX = 1024 * 5000;

my %cfg = get_cfg('/etc/eyesee/eyesee.cfg',
                  ('RCVIMG_DEST_BASEDIR', '/var/eyesee/img',
                   'RCVIMG_URL_BASE', '/img',
                   # log configuration
                   'RCVIMG_LOGDIR', '/var/log/eyesee',
                   'RCVIMG_LOGFILE', 'rcvimg',
                   # mqtt configuration
                   'RCVIMG_MQTT_TELEMETRY_BROKER', 'localhost',
                   'RCVIMG_MQTT_PORT', '1883',
                   'RCVIMG_MQTT_SEND', 1,
                  ));

# format for date/time in the log messages
my $DATE_FORMAT = "%Y.%m.%d %H:%M:%S";

# where to put the log file
my $LOGFN = "$cfg{RCVIMG_LOGDIR}/$cfg{RCVIMG_LOGFILE}";

my $safe_chars = 'ea-zA-Z0-9_.-';
my $dstdir_base = $cfg{RCVIMG_DEST_BASEDIR};

my $code = '200';
my $msg = 'OK';
my $query = new CGI;
my $label = $query->param('label'); # e.g., hostname
my $name = $query->param('filename'); # e.g., YYmmddHHMMSS
my $path = q();

$label =~ tr/ /_/;
$label =~ s/[^$safe_chars]//g;
$label = lc $label;
$name =~ tr/ /_/;
$name =~ s/[^$safe_chars]//g;
if (length($label) == 0) {
    $code = 400;
    $msg = "bad value for label: '$label'";
    logmsg($msg);
} elsif ($name !~ /^\d\d\d\d\d\d\d\d/) {
    $code = 400;
    $msg = "bad format for name: '$name'";
    logmsg($msg);
} else {
    my ($subdir) = $name =~ /(\d\d\d\d\d\d\d\d)/;
    `mkdir -p $dstdir_base/$label/$subdir`;
    $path = "$label/$subdir/$name";
    my $fn = "$dstdir_base/$path";
    my $fh = $query->upload('thumbnail');
    if (open(FILE, ">$fn")) {
        binmode FILE;
        while(<$fh>) {
            print FILE;
        }
        close(FILE);
    } else {
        $code = 500;
        $msg = "cannot write to $fn: $!";
        logmsg($msg);
    }
}

if ($cfg{RCVIMG_MQTT_SEND}) {
    my $now = time;
    my $url = $cfg{RCVIMG_URL_BASE} . q(/) . $path;
    my $topic = "telemetry/${label}/cam/img";
    # must fake fail and rc since the image handler expects those
    my $msg = "{\"ts\":$now, \"url\":\"$url\", \"fail\":0, \"rc\":0, \"code\":$code}";
    send_mqtt($msg, $topic);
}

print $query->header(-type=>'text/plain', -status=>"$code $msg");

exit 0;


sub logmsg {
    my ($msg) = @_;
    my $src = $ENV{REMOTE_ADDR};
    my $tstr = strftime $DATE_FORMAT, localtime time;
    if (open(LOGFILE, ">>$LOGFN")) {
        print LOGFILE "$tstr $src $msg\n";
        close(LOGFILE);
    } else {
        print STDOUT "$tstr $src $msg\n";
    }
}

# send an mqtt message about the transfer state
# ts is the name of the image (the time it was captured)
# fail, rc, sig is the status of the upload attempt
sub send_mqtt {
    my ($msg, $topic) = @_;

    my $rval = eval "{ require Net::MQTT::Simple; }"; ## no critic (ProhibitStringyEval)
    if (! $rval) {
        my $msg = 'Net::MQTT::Simple is not installed';
        logmsg($msg);
        return;
    }

    my $s = $cfg{RCVIMG_MQTT_TELEMETRY_BROKER} . q(:) . $cfg{RCVIMG_MQTT_PORT};
    logmsg("mqtt msg '$msg' as topic $topic at broker $s");
    my $c = Net::MQTT::Simple->new($s);
    $c->retain("$topic", $msg);
}

sub get_cfg {
    my($cfgfn, %cfg) = @_;

    for(my $i=0; $i<scalar @ARGV; $i++) {
        if ($ARGV[$i] eq '--config') {
            $i += 1;
            $cfgfn = $ARGV[$i];
        }
    }

    if (open(CFG, "<$cfgfn")) {
        while(<CFG>) {
            my $line = $_;
            next if $line =~ /^\s*\#/;
            chomp($line);
            my ($n,$v) = split('=', $line);
            $n =~ s/^\s+//g;
            $n =~ s/\s+$//g;
            $v =~ s/^\s+//g;
            $v =~ s/\s+$//g;
            $cfg{$n} = $v;
        }
        close(CFG);
    }
    return %cfg;
}
