블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2008. 5. 21. 13:23

[ Perl ] IRC BOT을 만들어봅시다 :-) #2

 어제 저녁 엔트리에 이어서, 계속해서 써나갑니다.

  IRC BOT을 만들어봅시다 :-) #2

  - #1 에서는... ( 2008/05/20 - [IT/Perl] - IRC BOT을 만들어봅시다 :-) #1 )

   - IRC 를 구현한 모듈은 Net::IRC, PoCo::IRC 가 있다는 것을 알았습니다.
   - PoCo::IRC 모듈을 설치하는 법을 알았습니다.

  - #2 에서는

   - PoCo::IRC를 이용해서 실제로 IRC 서버 접속을 해봅니다.

  - Tutorial

   PoCo::IRC 의 CPAN Module 페이지로 들어가보면 자세한 예제가 나옵니다. 여기서는 이 예제를 바탕으로 시작해보고자 합니다.
 
use strict;
use warnings;
use POE qw(Component::IRC);

my $nickname = 'I_Like_Perl';
my $ircname = 'Bot-Likes-Perl';
my $server = 'irc.blahblahblah.irc';

my @channels = ('#perlbot_test', '#perlbot', '#perl');

my $irc = POE::Component::IRC->spawn(
nick => $nickname,
ircname => $ircname,
server => $server,
) or die "Oh noooo! $!";

POE::Session->create(
package_states => [
main => [ qw(_default _start irc_001 irc_public) ],
],
heap => { irc => $irc },
);

$poe_kernel->run();

sub _start {
my $heap = $_[HEAP];

my $irc = $heap->{irc};

$irc->yield( register => 'all' );
$irc->yield( connect => { } );
return;
}

sub irc_001 {
my $sender = $_[SENDER];

my $irc = $sender->get_heap();

print "Connected to ", $irc->server_name(), "\n";

$irc->yield( join => $_ ) for @channels;
return;
}

sub irc_public {
my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];

return;
}

sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ( "$event: " );

for my $arg (@$args) {
if ( ref $arg eq 'ARRAY' ) {
push( @output, '[' . join(' ,', @$arg ) . ']' );
}
else {
push ( @output, "'$arg'" );
}
}
print join ' ', @output, "\n";
return 0;
}
이와같은 코드를 뽑아왔습니다. 위의 코드를 "bot.pl"로 저장합니다.

그리고 한 부분씩 조심조심 설명 들어가겠습니다.
my $nickname = 'I_Like_Perl'; # 당연히 IRC 상에서의 닉입니다.
my $ircname = 'Bot-Likes-Perl'; # IRC 상에서의 이름입니다. 적당하게 대충쓰시면 됩니다 :-)
my $server = 'irc.hanirc.org'; # 접속할 IRC 서버입니다.
 - 국내의 대표적인 IRC 서버는 hanIRC(irc.hanirc.org)와 단군넷(irc.dankun.net) 이 있습니다.
 - 해외의 대표적인 IRC 서버는 Freenode(irc.freenode.net) 와 Perl IRC(irc.perl.org) 이외에 여럿 있습니다. :-)

 각자 자신이 사용하실 IRC 서버를 넣으시면 되겠습니다.
my @channels = ('#perlbot_test', '#perlbot', '#perl'); # 입장하실 채널을 정해주세요.
 @channels 라는 배열에 처음에 입장하실 IRC 채널을 넣으시면 됩니다. 이렇게 하시면 #perlbot_test, #perlbot, #perl 방에 입장하시게 되는 겁니다. (그 채널에 아무도 없다면 IRC 프로토콜의 정책 상 채널이 생기는 것이 됩니다)
my $irc = POE::Component::IRC->spawn(
nick => $nickname, # 위에서 설정한 닉
ircname => $ircname, # 위에서 설정한 이름
server => $server, # 위에서 설정한 IRC서버
) or die "Oh noooo! $!";
  PoCo::IRC 모듈에 적절한 인수를 맞춰서 호출합니다. 만약 여기서 문제가 생긴다면 "Oh noooo!" 를 외치면서 스크립트는 종료됩니다.

 POE::Session->create(
  package_states => [
  main => [ qw(_default _start irc_001 irc_public) ], # POE 상에서 어떤 상태별로 호출될 서브루틴입니다.
 ],
 heap => { irc => $irc },
 );
 $poe_kernel->run(); # POE Kernel 을 실행합니다.

 위의 _default, _start_ irc_001, irc_public 은 해당되는 상태정보에 따라 호출이 됩니다.
 이에 대해 하나하나 알아볼까요?
sub _start {
my $heap = $_[HEAP];

my $irc = $heap->{irc};

$irc->yield( register => 'all' );
$irc->yield( connect => { } );
return;
}
 _start 메소드의 구성입니다. 여기서는 시작할 때에 IRC 접속을 위한 초기화 작업을 수행합니다. IRC 접속 이전에 각종 플러그인을 여기에서 추가할 수 있습니다.
sub irc_001 {
my $sender = $_[SENDER];

my $irc = $sender->get_heap();

print "Connected to ", $irc->server_name(), "\n";

$irc->yield( join => $_ ) for @channels; # 위에서 정의한 @channels 변수에 담긴 채널에 입장합니다.
return;
}
  irc_001 의 구성입니다. 서버에 접속한 뒤에 한번 호출이 됩니다. IRC 서버에 접속하고서 가장 먼저 해야할 일들을 여기에서 정의해 줄 수 있습니다. 가장 기본적으로 해야할 것은 역시 채널에 접속하는 것입니다.
sub irc_public {
my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];

return;
}

irc_public 은 유난히도 받아들이는 인수가 많습니다. 이것은 일반적인 대화시에 호출이 됩니다. 대화시에 발생되는
어떤 이벤트들을 여기에서 구현해 줄 수 있습니다. (누가, 어디서, 무슨 말을 했는가)에 대한 인수를 얻게 됩니다.

sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ( "$event: " );

for my $arg (@$args) {
if ( ref $arg eq 'ARRAY' ) {
push( @output, '[' . join(' ,', @$arg ) . ']' );
}
else {
push ( @output, "'$arg'" );
}
}
print join ' ', @output, "\n";
return 0;
}

_default 는 어떤 이벤트 발생시의 기록을 남깁니다. 서버로 부터 ping을 받았을 때는 irc_ping, 서버접속시의
상태정보에 대한 것이거나, irc_353 등의 정보로 현재 채널에 입장한 사람이 누구인지 여부를 알 수 있습니다.
irc_join, irc_quit 등의 정보로 지금 막 입장한 사람에 대한 정보도 얻을 수 있구요.

모든 처리는 이런 정보를 기본으로 합니다.
누가 어떤 말을 했을 때, BOT에게 어떻게 하게 한다거나...
어떤 사람이 입장했을 때 그 사람에게 "안녕"이라고 말한다거나 말이죠.

이 부분의 처리에 대해서는 다음 포스트에 계속하겠습니다.

  - Summary

- PoCo::IRC를 이용해서 IRC 서버 접속할 수 있다.
- 해당 변수의 내용을 바꿔서 Bot의 Nick을 바꿀 수 있다.
- irc 상태에 따라 여러 메소드들을 호출 할 수 있다.
- _start, _default, irc_001, irc_public 등의 메소드에서 해당 이벤트들을 처리한다.

  - #3 에서는...

- IRC의 상태에 따른 이벤트 처리를 알아보겠습니다.
- euc-kr, UTF-8 등의 언어코드에 대한 내용을 알아보겠습니다.

  - PR
※ 현재 POE::Component::IRC를 사용한 Perl Bot 만들기 프로젝트가 진행중입니다.
- http://code.google.com/p/perl-irc-bot
※ 더불어 perldoc을 한글로 번역하기 위한 프로젝트도 진행중입니다.
- http://code.google.com/p/perldoc-kr
※ 거기에 덧붙여 me2day Perl API를 만드는 프로젝트도 진행중입니다.
- http://code.google.com/p/me2day-perl-api

 참여를 원하시면 댓글을 달아주시거나, email: aiatejin@gmail.com
 혹은 IRC(irc.hanirc.org, #perl)에서 JEEN에게 연락하시면 됩니다.
  • 궁금이 2010.01.21 13:45 ADDR 수정/삭제 답글

    http://code.google.com/p/perl-irc-bot에 있는 예제 코드를 다음과 같이 고치고 실행하면 에러가 나던데요... 에러가 잘 안잡히네요.

    - irc_join() 함수에 다음을 추가
    my $channel = $where->[0];

    # 채널 접속 시 인사말 출력
    $irc->yield( privmsg => $channel => "Hi, everyone!" );

    Can't use string ("#bottest";) as an ARRAY ref while "strict refs" in use at bot.pl line 81.

    81행은 위의 my $channel = $where->[0]; 코드가 있는 부분입니다.

    • BlogIcon JEEN 2010.01.21 13:54 신고 수정/삭제

      코드 전체를 보여주실 수 있으신가요? 어디서부터 문제인지 저것만 가지고는 잘 모르겠네요.

  • 궁금이 2010.01.21 14:03 ADDR 수정/삭제 답글

    http://pastebin.com/d1cbdb314 <-- 여기요.
    거의 고친거도 없는데...

    • BlogIcon JEEN 2010.01.21 15:14 신고 수정/삭제

      http://search.cpan.org/~hinrik/POE-Component-IRC-6.22/lib/POE/Component/IRC.pm#irc_join

      irc_join 의 경우는 두번째 인수로 Array Reference 가 아니라 Scalar 값을 가지고 있습니다.
      my $channel = $where->[0];
      이 아니라..
      그냥
      my $channel = $where;
      로 쓰세요.

TOTAL 531,435 TODAY 2