0
Files
meow-irc-bot/lib/BotLib/Util.pm
2023-12-09 15:14:13 +03:00

426 lines
9.8 KiB
Perl

package BotLib::Util;
use 5.030; ## no critic (ProhibitImplicitImport)
use strict;
use warnings;
use utf8;
use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (cluck);
use CHI ();
use Digest::CRC qw (crc32_hex);
use Digest::SHA qw (sha1_base64 sha1_hex sha224_hex sha256_hex sha384_hex sha512_hex);
use Digest::MD5 qw (md5_base64 md5_hex);
use Digest::MurmurHash qw (murmur_hash);
use Encode qw (encode_utf8);
use Log::Any qw ($log);
use Math::Random::Secure qw (irand);
use MIME::Base64 qw (encode_base64);
use Time::HiRes qw (gettimeofday);
use URI::URL qw (url);
use BotLib::Conf qw (LoadConf);
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
our @EXPORT_OK = qw (timems trim urlencode utf2b64 utf2sha1 utf2md5 utf2sha1hex utf2sha224hex utf2sha256hex
utf2sha384hex utf2sha512hex utf2md5hex utf2crc32hex utf2murmurhash irandom runcmd storedata
cleanexpireddata rakedata deletedata PrintMsg);
local $OUTPUT_AUTOFLUSH = 1;
my $c = LoadConf ();
# Возвращает текущее время с точностью до миллисекунды
# $string timems()
sub timems {
my @time = gettimeofday ();
return join '', @time;
}
# Убирает пробельные символы с обоих концов даденной строки
# $str trim($str)
sub trim {
my $str = shift;
unless (defined $str) {
cluck '[ERROR] Str is undefined';
return '';
}
if ($str eq '') {
return $str;
}
while (substr ($str, 0, 1) =~ /^\s$/xms) {
$str = substr $str, 1;
}
while (substr ($str, -1, 1) =~ /^\s$/xms) {
chop $str;
}
return $str;
}
# Кодирует даденную строку согласно стандарту кодирования URL-ов
# $str urlencode($url)
sub urlencode {
my $str = shift;
unless (defined $str) {
cluck '[ERROR] Str is undefined';
return '';
}
my $urlobj = url $str;
return $urlobj->as_string;
}
# Кодирует даденную строку "по base64"
# $str utf2b64($str)
sub utf2b64 {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return encode_base64 '';
}
if ($string eq '') {
return encode_base64 '';
}
my $bytes = encode_utf8 $string;
my $str = encode_base64 $bytes;
chomp ($str);
return $str;
}
# Берёт от даденной строки sha1 и кодирует "по base64"
# Пример применения - имена файлов из каких-то unsafe(для файловой системы)-строк
# $str utf2sha1($str)
sub utf2sha1 {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha1_base64 '';
}
if ($string eq '') {
return sha1_base64 '';
}
my $bytes = encode_utf8 $string;
return sha1_base64 $bytes;
}
# Берёт от даденной строки sha1 и кодирует "по base64"
# Пример использования - имена файлов из unsafe(для файловой системы)-параметров
# $str utf2md5($str)
sub utf2md5 {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha1_base64 '';
}
if ($string eq '') {
return sha1_base64 '';
}
my $bytes = encode_utf8 $string;
return md5_base64 $bytes;
}
# Берёт от даденной строки sha224, как утилита sha224sum
# $str utf2sha224hex($str)
sub utf2sha1hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha1_hex '';
}
if ($string eq '') {
return sha1_hex '';
}
my $bytes = encode_utf8 $string;
return sha1_hex $bytes;
}
# Берёт от даденной строки sha224, как утилита sha224sum
# $str utf2sha224hex($str)
sub utf2sha224hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha224_hex '';
}
if ($string eq '') {
return sha224_hex '';
}
my $bytes = encode_utf8 $string;
return sha224_hex $bytes;
}
# Берёт от даденной строки sha256, как утилита sha1sum
# $str utf2sha256hex($str)
sub utf2sha256hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha256_hex '';
}
if ($string eq '') {
return sha256_hex '';
}
my $bytes = encode_utf8 $string;
return sha256_hex $bytes;
}
# Берёт от даденной строки sha1, как утилита sha384sum
# $str utf2sha384hex($str)
sub utf2sha384hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha384_hex '';
}
if ($string eq '') {
return sha384_hex '';
}
my $bytes = encode_utf8 $string;
return sha384_hex $bytes;
}
# Берёт от даденной строки sha1, как утилита sha512sum
# $str utf2sha512hex($str)
sub utf2sha512hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return sha512_hex '';
}
if ($string eq '') {
return sha512_hex '';
}
my $bytes = encode_utf8 $string;
return sha512_hex $bytes;
}
# Берёт от даденной строки md5, как утилита md5sum
# $str utf2md5hex($str)
sub utf2md5hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return md5_hex '';
}
if ($string eq '') {
return md5_hex '';
}
my $bytes = encode_utf8 $string;
return md5_hex $bytes;
}
# Берёт от даденной строки crc32
# $str utf2crc32hex($str)
sub utf2crc32hex {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return crc32_hex '';
}
if ($string eq '') {
return crc32_hex '';
}
my $bytes = encode_utf8 $string;
return crc32_hex $bytes;
}
# Берёт от даденной строки murmur_hash
# $str utf2murmurhash($str)
sub utf2murmurhash {
my $string = shift;
unless (defined $string) {
cluck '[ERROR] String is undefined';
return murmur_hash '';
}
if ($string eq '') {
return murmur_hash '';
}
my $bytes = encode_utf8 $string;
return murmur_hash $bytes;
}
# Возвращает рандомное целое число от 0 до даденного числа
# $num irand($num)
sub irandom {
my $num = shift;
return irand ($num);
}
# Execs command via backticks and handles errors in generic way
# Returns hashref
# $ret runcmd($cmd, @args)
sub runcmd {
my @cmd = @_;
my $out = '';
my $ret->{error} = 0;
$ret->{success} = 1;
my $err_msg = '';
$out = `@cmd`;
if ($CHILD_ERROR != 0) {
$err_msg = sprintf 'Unable to run %s', join (' ', @cmd);
$log->err ("[ERROR] $err_msg");
$ret->{error} = 1;
$ret->{success} = 0;
$ret->{err_msg} = $err_msg;
} else {
$ret->{text} = $out;
}
return $ret;
}
# Сохраняет данные в указанной БД с указанным expiration time. Expiration time может быть never, unixtimestamp, relative.
# Где unixtimestmp в секундах (с 1970 года), relative - это например 2 days.
# undef storedata($dbname, $key, $value, $time)
sub storedata {
my $dbname = shift;
my $key = shift;
my $value = shift;
my $time = shift;
cluck "[ERROR] datadir undefined in config" unless (defined $c->{datadir});
cluck "[ERROR] database not defined in config" unless (defined $c->{db}->{$dbname});
my $db_path = sprintf '%s/%s', $c->{datadir}, $c->{db}->{$dbname};
my $cache = CHI->new (
driver => 'BerkeleyDB',
root_dir => $db_path,
);
$cache->set ($key, $value, $time);
$log->debug ("[DEBUG] key $key with value $value and exp $time stored to $dbname");
return;
}
# Удаляет протухшие ключи из указанной бд
# undef cleanexpireddata($dbname)
sub cleanexpireddata {
my $dbname = shift;
# TODO: check that db defined in config
my $db_path = sprintf '%s/%s', $c->{datadir}, $c->{db}->{$dbname};
my $cache = CHI->new (
driver => 'BerkeleyDB',
root_dir => $db_path,
);
foreach my $entry ($cache->get_keys ()) {
unless ($cache->is_valid ($entry)) {
$cache->remove ($entry);
$log->debug ("[DEBUG] Expired key $entry removed from $dbname");
}
}
return;
}
# Выгребает ключ-значение из указанной БД в формате ссылочной структуры. Ключ гарантированно не протухший
# dataref rakedata($dbname)
sub rakedata {
my $dbname = shift;
# TODO: check if db exist
my $db_path = sprintf '%s/%s', $c->{datadir}, $c->{db}->{$dbname};
cluck unless defined $c->{db}->{$dbname};
cluck unless defined $c->{datadir};
my $cache = CHI->new (
driver => 'BerkeleyDB',
root_dir => $db_path,
);
my $hashref;
foreach ($cache->get_keys()) {
my $cache_object = $cache->get_object ($_);
$hashref->{$cache_object->key ()} = $cache_object->value ();
}
return $hashref;
}
# Удаляет ключ и ассоциированные с ним данные из указанной бд
# undef deletedata($dbname, $key)
sub deletedata {
my $dbname = shift;
my $key = shift;
cluck unless defined $c->{db}->{$dbname};
cluck unless defined $c->{datadir};
my $db_path = sprintf '%s/%s', $c->{datadir}, $c->{db}->{$dbname};
my $cache = CHI->new (
driver => 'BerkeleyDB',
root_dir => $db_path,
);
$cache->remove ($key);
$log->debug ("[DEBUG] Key $key removed from $dbname");
return;
}
# Пишет сообщение в чятик или юзеру
# undef PrintMsg($chatid, $text)
sub PrintMsg {
my $channel = shift;
my $message = shift;
$MAIN::IRC->send_long_message ('utf8', 0, 'PRIVMSG', $channel, $message); ## no critic (Modules::RequireExplicitInclusion)
$log->debug ("[DEBUG] message '$message' sent to $channel");
return;
}
1;
# vim: set ft=perl noet ai ts=4 sw=4 sts=4: