#!/usr/bin/php
<?php

declare(strict_types=1);

$program = 'firewalld capnotify';
$version = '2024.11.30';
$vnstat_iface = 'red0';
$localstatedir = '/var/lib/firewalld';
$last_notified_file = "{$localstatedir}/cap_last_notified";
$last_notified = 0;
$multiplier = 1073741824;  // 1 gb
$cap = (isset($_SERVER['DATA_CAP']) ? intval($_SERVER['DATA_CAP']) : 1000)*$multiplier;
$notify_at = (isset($_SERVER['NOTIFY_AT']) ? intval($_SERVER['NOTIFY_AT']) : 800)*$multiplier;
$pushover_user = (isset($_SERVER['USER_TOKEN']) ? $_SERVER['USER_TOKEN'] : '');
$pushover_token = (isset($_SERVER['APP_TOKEN']) ? $_SERVER['APP_TOKEN'] : '');
$pushover_url = 'https://api.pushover.net/1/messages.json';
$is_term = (posix_isatty(STDOUT) ? true : false);

function format_bytes(mixed $bytes): string
{
    $bytes = intval($bytes);
    if ($bytes < 1024) {
        return sprintf('%d B', $bytes);
    } elseif ($bytes < 1048576) {
        return sprintf('%.2f KiB', round($bytes / 1024, 2));
    } elseif ($bytes < 1073741824) {
        return sprintf('%.2f MiB', round($bytes / 1048576, 2));
    } elseif ($bytes < 1099511627776) {
        return sprintf('%.2f GiB', round($bytes / 1073741824, 2));
    } elseif ($bytes < 1125899906842624) {
        return sprintf('%.2f TiB', round($bytes / 1099511627776, 2));
    } else {
        return sprintf('%.2f PiB', round($bytes / 1125899906842624, 2));
    }
}

error_reporting(E_ALL);

set_time_limit(0);

// Only run from the command line
if (php_sapi_name() !== 'cli') {
    fprintf(STDERR, "This script can only be ran from the command line\n");
    exit(1);
}

$force = ($argc == 2 && $argv[1] == '--force' ? true : false);

if ($is_term) {
    printf("%s version %s\n\n", $program, $version);
}

// Make locate state directory
@mkdir($localstatedir, 0775, true);

// Read last notified stamp
if (@file_exists($last_notified_file)) {
    $last_notified = intval(trim(@file_get_contents($last_notified_file)));
    if ($last_notified < 0) {
        $last_notified = 0;
    }
}

// Read data from vnstat
$descriptors = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe', 'w'],
];
$command = "vnstat -i {$vnstat_iface} --json m";
$process = proc_open($command, $descriptors, $pipes);
if (!is_resource($process)) {
    fprintf(STDERR, "Failed to open process\n");
    exit(1);
}
fclose($pipes[0]);
$json = stream_get_contents($pipes[1]);
fclose($pipes[2]);
$retval = proc_close($process);
if ($retval !== 0) {
    fprintf(STDERR, "Command failed\n");
    exit(1);
}
if ($json === false) {
    fprintf(STDERR, "Stream empty\n");
    exit(1);
}
$json = json_decode($json, true);
if (!is_array($json)) {
    fprintf(STDERR, "Failed to decode json data\n");
    exit(1);
}

// Grab current time stamp and date for comparison
$stamp = time();
$month = intval(date("n", $stamp));
$year = intval(date("Y", $stamp));

// Find current month in array
$rx = 0;
$tx = 0;
$total = 0;
$used = 0;
foreach ($json['interfaces'][0]['traffic']['month'] as $month_arr) {
    if (intval($month_arr['date']['month']) !== $month || intval($month_arr['date']['year']) !== $year) {
        continue;
    }
    $rx = intval($month_arr['rx']);
    $tx = intval($month_arr['tx']);
    $total = $rx+$tx;
    if ($cap > 0) {
        $used = $total/$cap*100;
    } else {
        $used = 0;
    }
    printf("rx %s, tx %s, total %s, cap %s, used %.2f%%\n",
        format_bytes($rx),
        format_bytes($tx),
        format_bytes($total),
        format_bytes($cap),
        $used
    );
    break;
}
unset($month_arr);
unset($json);

$message = sprintf("You have used %.2f%% (%s) of your data for %02d-%04d", $used, format_bytes($total), $month, $year);
if ($is_term) {
    echo $message."\n";
}

if ($force || $total >= $notify_at) {
    $last_month = intval(date('n', $last_notified));
    $last_year = intval(date('Y', $last_notified));
    if ($force || $last_month !== $month || $last_year !== $year) {
        if ($last_notified > 0) {
            printf("Last notified %s\n", date('r', $last_notified));
        }
        if (strlen($pushover_user) > 0 && strlen($pushover_token) > 0) {
            $ch = curl_init();
            if ($ch === false) {
                fprintf(STDERR, "Failed to initialize curl\n");
                exit(1);
            }
            $cv = curl_version();
            $useragent = sprintf("curl/%s (%s %s)", $cv['version'], $program, $version);
            $opts = [
                'token' => $pushover_token,
                'user' => $pushover_user,
                'title' => $program,
                'message' => $message,
            ];
            curl_setopt_array($ch, [
                CURLOPT_URL => $pushover_url,
                CURLOPT_POSTFIELDS => $opts,
                CURLOPT_HEADER => false,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_CONNECTTIMEOUT => 5,
                CURLOPT_USERAGENT => $useragent,
            ]);
            $result = curl_exec($ch);
            curl_close($ch);
            printf("Result: %s\n", $result);
        } else {
            fprintf(STDERR, "Pushover user or token missing\n");
        }

        if (!$force) {
            // Save last notified timestamp
            @file_put_contents($last_notified_file, sprintf("%d\n", $stamp));
        }
    }
}

exit(0);
