Socket Service:
#!/usr/bin/perl
use strict;
use warnings;
use Net::WebSocket::Server;
use JSON;
# Store previous network stats
my %prev_net_stats = get_network_usage();
# Start WebSocket server
Net::WebSocket::Server->new(
listen => 3000,
on_connect => sub {
my ($conn) = @_;
my %last_check = (
cpu => time(),
memory => time(),
network => time(),
connections => time(),
disk => time()
);
my %intervals = (
cpu => 2,
memory => 5,
network => 3,
connections => 10,
disk => 10
);
$conn->on(utf8 => sub {
my $msg = shift;
my $config = eval { decode_json($msg) };
return unless ref $config eq 'HASH';
# Set custom intervals from the client
$intervals{cpu} = $config->{cpu} if exists $config->{cpu};
$intervals{memory} = $config->{memory} if exists $config->{memory};
$intervals{network} = $config->{network} if exists $config->{network};
$intervals{connections}= $config->{connections} if exists $config->{connections};
$intervals{disk} = $config->{disk} if exists $config->{disk};
});
while ($conn->is_open) {
my $now = time();
# Check and send updates based on intervals
if ($now - $last_check{cpu} >= $intervals{cpu}) {
$conn->send(encode_json({ cpu => get_cpu_usage() }));
$last_check{cpu} = $now;
}
if ($now - $last_check{memory} >= $intervals{memory}) {
$conn->send(encode_json({ memory => get_memory_usage() }));
$last_check{memory} = $now;
}
if ($now - $last_check{network} >= $intervals{network}) {
$conn->send(encode_json({ network => get_network_stats() }));
$last_check{network} = $now;
}
if ($now - $last_check{connections} >= $intervals{connections}) {
$conn->send(encode_json({ connections => get_network_connections() }));
$last_check{connections} = $now;
}
if ($now - $last_check{disk} >= $intervals{disk}) {
$conn->send(encode_json({ disk => get_disk_usage() }));
$last_check{disk} = $now;
}
# Sleep for a short time to prevent high CPU usage
select(undef, undef, undef, 0.5);
}
}
)->start;
### **Helper Functions**
sub get_cpu_usage {
open my $fh, '<', "/proc/stat" or return;
my $line = <$fh>;
close $fh;
my @cpu_data = (split /\s+/, $line)[1..8];
my $total = 0;
my $idle = $cpu_data[3];
$total += $_ for @cpu_data;
state $prev_total = $total;
state $prev_idle = $idle;
my $diff_total = $total - $prev_total;
my $diff_idle = $idle - $prev_idle;
$prev_total = $total;
$prev_idle = $idle;
return sprintf("%.2f", 100 * (1 - $diff_idle / $diff_total));
}
sub get_memory_usage {
open my $fh, '<', "/proc/meminfo" or return;
my %mem;
while (<$fh>) {
if (/^(MemTotal|MemAvailable):\s+(\d+)/) {
$mem{$1} = $2;
}
}
close $fh;
return sprintf("%.2f", 100 * (1 - $mem{MemAvailable} / $mem{MemTotal}));
}
sub get_network_usage {
open my $fh, '<', "/proc/net/dev" or return;
my %stats;
while (<$fh>) {
if (/^\s*(\w+):\s*(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)/) {
my ($iface, $rx_bytes, $tx_bytes) = ($1, $2, $3);
$stats{$iface} = { download => $rx_bytes, upload => $tx_bytes };
}
}
close $fh;
return %stats;
}
sub get_network_stats {
my %current = get_network_usage();
my %stats_diff;
foreach my $iface (keys %current) {
if (exists $prev_net_stats{$iface}) {
$stats_diff{$iface} = {
download => $current{$iface}{download} - $prev_net_stats{$iface}{download},
upload => $current{$iface}{upload} - $prev_net_stats{$iface}{upload},
};
} else {
$stats_diff{$iface} = { download => 0, upload => 0 };
}
}
%prev_net_stats = %current;
return \%stats_diff;
}
sub get_network_connections {
my @connections;
my $cmd = `ss -tan 2>/dev/null` || `netstat -tan 2>/dev/null`;
foreach my $line (split /\n/, $cmd) {
if ($line =~ /\b(LISTEN|ESTABLISHED|TIME_WAIT|CLOSE_WAIT|SYN_SENT)\b/) {
push @connections, $line;
}
}
return \@connections;
}
sub get_disk_usage {
my @disks;
my $cmd = `df -h --output=source,pcent,target | tail -n +2`;
foreach my $line (split /\n/, $cmd) {
if ($line =~ /^(\S+)\s+(\d+%)\s+(\S+)/) {
push @disks, { filesystem => $1, used => $2, mount => $3 };
}
}
return \@disks;
}