2025-07-30 06:06:38
#ok transferred the log file to the IRC
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use POSIX qw(strftime);
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
use File::stat;
use Time::HiRes qw(sleep);
# Параметры IRC-сервера
my $server = 'chat.example.net';
my $port = 6667;
my $channel = '#example';
my $logfile = '/log/my.log';
# Генерация случайного ника из 8 букв
my @chars = ('a'..'z');
my $nick = join '', map { $chars[rand @chars] } 1..8;
print "DEBUG: Generated nick: $nick\n";
# Создание сокета
print "DEBUG: Connecting to $server:$port...\n";
my $socket = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => 'tcp',
Timeout => 10
) or die "ERROR: Cannot connect to $server:$port: $!\n";
print "DEBUG: Connected to $server:$port\n";
# Сделать сокет неблокирующим
my $flags = fcntl($socket, F_GETFL, 0) or die "Can't get flags for socket: $!\n";
fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or die "Can't set socket to non-blocking: $!\n";
# Отправка IRC-команд для авторизации
send_line($socket, "NICK $nick");
send_line($socket, "USER $nick 0 * :Random Perl Bot");
# Открытие файла лога и перевод в неблокирующий режим
open my $fh, '<', $logfile or die "ERROR: Cannot open $logfile: $!\n";
$flags = fcntl($fh, F_GETFL, 0) or die "Can't get flags for log file: $!\n";
fcntl($fh, F_SETFL, $flags | O_NONBLOCK) or die "Can't set log file to non-blocking: $!\n";
# Переместиться в конец файла, чтобы читать только новые добавления
seek($fh, 0, 2);
my $file_buffer = '';
my $socket_buffer = '';
my $last_line = '';
my $joined = 0;
my $timestamp; # Объявляем для использования внутри цикла и после
sub send_line {
my ($sock, $line) = @_;
print "DEBUG: Sending: $line\n";
print $sock "$line\r\n" or die "ERROR: Failed to send to socket: $!\n";
}
while (1) {
sleep(0.5);
$timestamp = strftime("[%Y-%m-%d %H:%M:%S]", localtime);
# Настраиваем select для прослушивания сокета и файла
my $rin = '';
vec($rin, fileno($socket), 1) = 1;
vec($rin, fileno($fh), 1) = 1;
my $timeout = 0.1; # 100 мс
my $nfound = select(my $rout = $rin, undef, undef, $timeout);
# --- Чтение из файла ---
if ($nfound && vec($rout, fileno($fh), 1)) {
my $buf;
while (1) {
my $bytes_read = sysread($fh, $buf, 1024);
last unless defined $bytes_read && $bytes_read > 0;
$file_buffer .= $buf;
}
while ($file_buffer =~ s/^(.*\n)//) {
my $line = $1;
$line =~ s/\n$//;
next unless $line =~ /\S/;
print "DEBUG: [$timestamp] Read line from file: '$line'\n";
next if $line eq $last_line;
$last_line = $line;
if ($joined) {
send_line($socket, "PRIVMSG $channel :$line");
print "DEBUG: [$timestamp] Sent to IRC at: ", strftime("%H:%M:%S", localtime), "\n";
} else {
print "DEBUG: [$timestamp] Not joined yet, holding line: $line\n";
}
}
# Проверка ротации файла
my $filestat = stat($logfile);
if (!$filestat) {
warn "WARNING: Cannot stat log file $logfile\n";
} else {
my $curr_size = $filestat->size // 0;
my $pos = tell($fh) // 0;
if ($curr_size < $pos) {
print "DEBUG: [$timestamp] Log file rotated, reopening\n";
close $fh;
open $fh, '<', $logfile or die "ERROR: Cannot reopen $logfile: $!\n";
$flags = fcntl($fh, F_GETFL, 0) or die "Can't get flags for log file: $!\n";
fcntl($fh, F_SETFL, $flags | O_NONBLOCK) or die "Can't set log file to non-blocking after reopen: $!\n";
seek($fh, 0, 2);
$file_buffer = '';
$last_line = '';
print "DEBUG: [$timestamp] Reopened file after rotation\n";
}
}
}
# --- Чтение из сокета ---
if ($nfound && vec($rout, fileno($socket), 1)) {
my $buf;
while (1) {
my $bytes = sysread($socket, $buf, 4096);
last unless defined $bytes && $bytes > 0;
$socket_buffer .= $buf;
}
while ($socket_buffer =~ s/^(.*\r\n)//) {
my $line = $1;
$line =~ s/\r\n$//;
print "DEBUG: [$timestamp] Received from IRC: $line\n";
if ($line =~ /^PING :(.+)/) {
send_line($socket, "PONG :$1");
}
elsif ($line =~ /:.* 001/) {
print "DEBUG: [$timestamp] Registration successful, joining $channel\n";
send_line($socket, "JOIN $channel");
$joined = 1;
send_line($socket, "PRIVMSG $channel :Test message from $nick");
}
elsif ($line =~ /:.* 433/) {
print "DEBUG: [$timestamp] Nick $nick in use, generating new one\n";
$nick = join '', map { $chars[rand @chars] } 1..8;
send_line($socket, "NICK $nick");
}
elsif ($line =~ /:.* (4\d\d|5\d\d)/) {
print "ERROR: [$timestamp] IRC server error: $line\n";
}
}
}
die "select failed: $!" if $nfound < 0;
# Если select == 0 (таймаут), продолжим цикл
}
# В нормальной работе сюда не доходим, но для закрытия ресурсов:
$socket->close();
close $fh;
$timestamp = strftime("[%Y-%m-%d %H:%M:%S]", localtime);
print "DEBUG: [$timestamp] Connection and file closed\n";
Back to list