Определимся с задачей
Есть комната в irc, есть комната в xmpp. соответственно нужно, чтобы всё, что пишут в xmpp оказалось в irc, и наоборот.
xmpp и irc в данном случае имеют кодировку utf-8, поэтому перекодировать ничего не нужно будет.
Начнём
Для всего этого будем использовать Anyevent.
Пояснения буду сразу в коде писать — думаю, так будет удобней.
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode qw(decode encode);
use locale;
use open qw( :utf8 :std );
use AnyEvent::IRC::Client;
use AnyEvent::XMPP::Client;
use AnyEvent::Socket;
use AnyEvent::Handle;
use AnyEvent::XMPP::Ext::Disco;
use AnyEvent::XMPP::Client;
use AnyEvent::XMPP::Ext::MUC;
# xmpp коннектится дольше, поэтому плясать будем от него
my $xmpp_connected=0;
my $c = AE::cv;
my $xmpp=AnyEvent::XMPP::Client->new(debug=>0);
my $disco=AnyEvent::XMPP::Ext::Disco->new;
my $muc=AnyEvent::XMPP::Ext::MUC->new (disco => $disco);
# оставим глобальную переменную, из которой в последующем будем отправлять сообщения в xmpp
my $croom;
$xmpp->add_extension($disco);
$xmpp->add_extension($muc);
$xmpp->add_account('bot@server/res','password');
# callback's для xmpp
$xmpp->reg_cb(
session_ready => sub{
my($xmpp,$acc)=@_;
my $con=$acc->connection;
# Как только установили надёжную связь с xmpp - входим в комнату.
$muc->join_room ($acc->connection, "habr2014@conference.jabber.ru", "ibot435");
},
disconnect => sub {die "disconnectedn";},
error => sub { my ($xmpp,$acc,$err)=@_; die "error: ".$err->string."n"},
);
# callback's для xmpp muc (multi user conference)
$muc->reg_cb(
message=>sub{
my ($muc,$room,$msg,$echo)=@_;
# мы получили сообщение в xmpp-комнату. и если это сообщение отправили не мы - пересылаем его в irc
if ($msg->from_nick ne "ibot435"){
$irc->send_srv(PRIVMSG => '#habr2014ny', "(xmpp) ". encode("utf8",$msg->from_nick).": ".encode("utf8",$msg->body));
}
},
enter=>sub{ my ($muc,$room,$user)=@_;
#вошли в канал успешно - задаём значение глобальной переменной.
$croom=$room;
$xmpp_connected=1;
}
);
$xmpp->start;
# с xmpp закончили, теперь irc
my($server, $port, $nick, $channel) = ("irc.p2pchat.net",6667,"jbot435","#habr2014ny");
my $irc = AnyEvent::IRC::Client->new;
$irc->reg_cb (
connect => sub {
my ($irc, $err) = @_;
if (defined $err) {
die "connect error: $errn";
}
},
irc_privmsg=>sub {
my($irc,$msg)=@_;
# получили сообщение из irc - пересылаем в xmpp
my $nick=(split /!/,$msg->{'prefix'})[0];
my $to=$msg->{'params'}[0];
my $text=$msg->{'params'}[1];
$text=decode('utf8',$text);
if ($to eq "#habr2014ny" && $xmpp_connected==1)
{
my $new_msg=$croom->make_message();
$new_msg->add_body("(irc) ".$nick.': '.$text);
$new_msg->send();
}
}
);
$irc->connect ($server, $port, { nick => $nick });
$irc->send_srv( JOIN => $channel);
# запускаем loop
$c->recv;
Выглядеть это всё будет примерно так:
(в xmpp)
<ibot435> (irc) user1: текст
<ibot435> (irc) user2: текст
(в irc)
<jbot435> (xmpp) user3: текст
<jbot435> (xmpp) user4: текст
Подводные камни
Единственное, что оказалось нетривиальным — модуль AnyEvent::XMPP и AnyEvent::IRC по-разному работают с юникодом. Поэтому пришлось устанавливать флаг юникода при отправке в irc (encode(«utf8»,$msg->body), а при получении из irc снимать этот флаг ($text=decode('utf8',$text);)
Выводы
С виду громоздкая задача на перл может оказаться совсем тривиальной. главное найти хороший модуль.
PS: callback's не разносил в отдельные функции не разносил, чтобы компактней всё выглядело и не мешалось.
Автор: skovpen
