LogNotes

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";
← Previous Next →
Back to list