블로그 이미지
JEEN

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

Rss feed Tistory
IT/Perl 2009.11.26 18:31

[ Perl ] IRC + AnyEvent + Moose -> Morris

2008/05/20 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #1
2008/05/21 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #2
2008/05/23 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #3
2008/05/27 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #4
2008/05/27 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #5
2008/05/29 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #6
2008/06/18 - [IT/Perl] - [ Perl ] IRC BOT을 만들어봅시다 :-) #번외편


그러고보니 1년이 지났군요. PoCo::IRC 로 IRC 봇 설레발을 작년에 7개넘게 포스팅한 걸로 압니다. 다시 뒤져보면 결국은 문서에 있는 코드 그대로 붙여쓰기 한 것 밖에 지나지 않는 군요.

  올해는 이벤트처리, 비동기처리 등에 관한 이슈가 빈번하게 들려오고 있습니다. AnyEvent 붐이라고 할 정도로 많은 새로운 모듈이 AnyEvent 의 네임스페이스를 차지하면서 올라가고 있습니다. 저도 공부의 필요성을 느끼고 문서를 읽어보고자 했으나, 대략 멍~ 한 상태는 어찌할 수 없었습니다.
  결론은 직접 써보고, 만들어보는 수 밖에 없었습니다.
 
  Perl 을 나름 제대로 쓰고자 했던 출발점이 IRC 봇 만들면서 그랬듯, AnyEvent 도 그렇게 시작하려고 했었습니다.
  그런데!! 일본의 Perl 해커 Maki 씨가  Morris 라는 봇을 만든 것을 봤습니다. Morris 는 AnyEvent + Moose 를 뼈대로 만들어졌으며, 매우 현대적인 펄 프로그래밍 스타일을 엿볼 수 있었습니다.
 
  특징으로는, 설정파일 기반으로 여러개의 IRC 서버에 접근할 수 있으며, 각 네트워크별로 Plugin 을 할당해줄 수 있고, 쉽게 Plugin 을 확장할 수 있습니다.

  http://github.com/lestrrat/Morris

  그래서 기존에 쓰고 있던 PoCo::IRC 로 깨작거렸던 것도 Morris 로 바꿨습니다. 뭐 추가로 이래저래 작업해야할 것들도 많겠지만... 일단은 너무 만족스럽습니다. :-)

  지난번 PoCo::IRC 프로세스 두개 띄워서 서로 IKC 로 묶어줬던 부분은 AnyEvent::MP 를 이용해서 같은 기능을 구현할 수 있습니다. AEMP는 Erlang Style 의 Multi-Processing/Message-Passing Framework 입니다. 기존의 PoCo::IKC 를 사용했던 경우는 두개의 프로세스에 각자 IKC 서버/클라이언트를 띄웠지만, Morris 가 사용하는 AEMP 의 경우는 Seed 역할을 하는 Process 가 필요합니다. 그 Seed 프로세스가 중간에서 중계역할을 해주는 것이죠.
 
  http://search.cpan.org/perldoc?AnyEvent::MP
 
  Intro 문서를 참고로 하시면 도움이 되실 겁니다. (아니 그보다 Intro 를 이해하지 않으면 뭐가 뭔지 알 수 없었습니다) 아무튼 AnyEvent::MP 모듈을 설치하면 aemp 라는 커맨드파일이 생성됩니다.

  $ aemp gensecret
  $ aemp profile seed binds "*:4040"
  $ aemp seeds "*:4040" nodeid anon/
  $ aemp run profile seed
 
 그 aemp 커맨드를 이용해서 위의 명령을 실행합니다. (Intro 에서 순서대로 따라하면 자연스레 입력하게 됩니다) 뭐 통신시 필요한 비밀키를 생성하고 시드를 4040포트로 붙여서 띄운다 라는 그런 내용입니다.

  IKC 대신에 AEMP를 사용하기로 했으니... 기본 플러그인인  Morris::Plugin::MP 를 사용하는 전제에서 아래의 Relay 플러그인을 그냥 냅다 써봤습니다.



  뭐 사실 hanirc <-> freenode 간에는 인코딩 타입등의 설정도 필요하겠지만... 그건 필요하신 분의 숙제로 남겨두도록 하겠습니다. :-)

  현재 irc.freenode.org #perl-kr <-> irc.hanirc.org #perl 은 이렇게 각 채널간의 메시지를 서로 릴레이하고 있습니다.

  그외 Plagger 같은 것들을 사용해서 RSS 를 긁어준다느니 등등도... AEMP 를 사용하는 플러그인 하나만 추가해주면 간단할 겁니다. 그냥 편히 쓰던 거 마저 써도 되지만... 그게 관리상에 이런저런 문제가 좀 있어서요.
  모두 AnyEvent!
신고
IT/Perl 2008.05.29 11:48

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


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

 - #5 에서는

  - Encode 모듈을 사용한 한글 취급에 대해서 알아보았습니다.
  - 실제 사용중인 Bot Command 를 예로 하여, 봇 커맨드 추가/사용 법을 알아보았습니다.

 - #6 에서는

  - IKC를 이용해서 외부 이벤트를 IRC에 알리는 방법에 대해서 알아보겠습니다.


 - IKC

  IKC - Inter-Kernel Communication
  자세한 내용은 PoCo::IKC 페이지를 참조해주세요.
 사실 PoCo::IRC 도 그렇지만, PoCo::IKC 도 제대로는 알지 못합니다. 단지 어디서 이런 것을 써서 구현하고 있다는 것만 보고 단순히 따라하기 수준에만 그친 형편이라서요. CPAN 에는 *::Notify::IRC 모듈이 있는데, 그 중에 Plagger::Plugin::Notify::IRC 와 Kwiki::Notify::IRC 를 참조해서 만들었습니다. Plagger 의 경우에는 Plagger 봇 스크립트를  제공해주고 있으니.. 그것을 대충 수정하면 쓸만하게 됩니다. :-)


 - Tutorial

  우선 적절한 사용예제를 Google 에서 찾고는 긁어와 봤습니다.

use warnings;
use strict;
use POE qw(Session);
use POE::Component::IKC::Server;
use POE::Component::IKC::Specifier;

POE::Component::IKC::Server->spawn(
    port => 31338,               # 포트
    name => 'AppServer',      # 서버이름
);

POE::Session->create(
    inline_states => {
        _start        => \&service_start,     # 초기화 작업 정의
        calc_sum      => \&service_calc_sum, # 작업내용 구현
        did_something => \&service_response, # 작업내용을 클라이언트에 전달
      }
);

POE::Kernel->run();
exit 0;

sub service_start {
    my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];

    my $service_name = "application";
    $kernel->alias_set($service_name); #서비스 이름을 정의해 줍니다.
    $kernel->call( IKC => publish => $service_name, ["calc_sum"] );
     # 해당 서비스이름과 작업을 공표합니다.
     # 이로써 client 에서는 해당 서비스 이름을 통해서 공표된 작업에만 접근할 수 있습니다.
     # calc_sum 이라고 공표된 작업은 위의 POE::Session안에서 inline_states 안에 기술합니다.
     # 고로 calc_sum 이라는 작업이 클라이언트에서 넘어왔을 때, service_calc_sum 을 호출하게 됩니다.
}

sub service_calc_sum {
    my ( $kernel, $heap, $request ) = @_[ KERNEL, HEAP, ARG0 ];
    my ( $data, $rsvp ) = @$request;

    my $sum = 0;
    if ( ref($data) eq "ARRAY" ) {
        $sum += $_ foreach @$data;
    }

    $kernel->delay_set( did_something => 1, $rsvp, $sum );
}

sub service_response {
    my ( $kernel, $heap, $rsvp, $sum ) = @_[ KERNEL, HEAP, ARG0, ARG1 ];
    $kernel->call( IKC => post => $rsvp, $sum );
    # 작업 결과를 넘겨받아 client 로 넘겨줍니다.
}

 이것은 IKC 서버의 구현입니다. 이것을 적당한 이름( ikc-server.pl )으로 저장합니다.
 다음은 클라이언트의 구현입니다.
 
use warnings;
use strict;

use POE::Component::IKC::ClientLite;

my $remote = create_ikc_client(
    port    => 31338,
    name    => "blahblah",
    timeout => 1,
);
die $POE::Component::IKC::ClientLite::error unless $remote;


my $return_value = $remote->post_respond( 'application/calc_sum', [1,2,3,4,5] );
 # 서버에서 지정한 서비스 이름과, 작업을 여기에서 호출됩니다.
die $POE::Component::IKC::ClientLite::error unless defined $return_value;

print "The sum is: $return_value\n";
exit 0;

 이것 역시나 적당한 이름 ( ikc-client.pl ) 로 저장합니다.
 우선 ikc-server.pl 을 실행한 다음에... 다른 터미널을 열어서 ikc-client.pl 를 실행합니다.
 그러면 해당 ikc-client.pl 을 실행한 터미널에서는
 
The sum is: 15

이라는 결과가 뜨게됩니다.

 Client 에서 1,2,3,4,5 라는 배열값(배열의 리퍼런스)을 서버에서 지정한 서비스 이름과 작업에 보내고, Server에서는 그것들을 전부 더해서 그 값을 클라이언트로 보내주는 겁니다.

 이를 응용하면 어떤 것이 가능할까요?

사용자 삽입 이미지
현재 #perl-kr@irc.freenode.org 에서는 CPAN 에 새로 등록된 모듈,
 perlmania 의 새로운 글들, perldoc-kr 에서의 새로운 커밋에 대해서 통보를 받고 있으며,
 #perl@irc.hanIRC.org  <=> #perl-kr@irc.freenode.org 간의 메시지 전달도 가능하게 되었습니다.
 
사용자 삽입 이미지
사용자 삽입 이미지

 [freenode] 라고 붙은 건 freenode 의 대화를 hanIRC에서 받은 것이고,
 [hanIRC] 라고 붙은 건 hanIRC 에서 freenode 의 대화를 받은 것입니다.

 그외에도 CodePad를 도입하고 있습니다. 특정 언어 코드를 웹페이지에 갖다 붙이면,
 그것을 적절하게 컴파일/인터프리트 해서 그 결과를 웹페이지에 보여주게 됩니다.
 모듈 의존성이 있는 코드들에 대한 결과를 자세하게 보지는 못하지만, 그래도 깨끗하게 코드를 볼 수 있습니다.
 
사용자 삽입 이미지

 (1) codepad 에 코드를 넣어서
 (2) 그 결과가 담긴 URL 을 복사해서
 (3) IRC에 붙여넣는다.

 라는 과정을

  (1) codepad 에 코드만 넣으면 끝

으로 축약했습니다.

  CodePad 의 구성을 그대로 빌려와서, WWW::Mechanize 를 통해서 해당 폼 값을 CodePad 로 날려서
그 결과가 되는 URL 을 받아, 그 결과값을 IKC를 통해서 IRC에 자동으로 통보해주는 것입니다.
(이는 saillinux님과 pung96님께서 수고해주셨습니다.)

 위에서 언급한 이런 것들은 모두 perl-irc-bot 에서 구현되어 있습니다. 정리되지 않은 코드라 더럽기도 하지만, "이따위 코드 눈뜨고 봐줄 수 없어! 내가 수정해주겠어!" 라면서 수정펀치 날려주실 분들과 커미터 분들을 모집하고 있습니다. 물론 사용하실 분들은 그냥 사용하셔도 됩니다. :-)

 - THE &

 이상으로 장장 6편에 걸친 그다지 도움되지 않는 IRC BOT 만들기를 마치겠습니다. :-)
 6편 모두는 IRCBOT만들기 라는 태그로 묶어놨습니다.

 제 자신도 공부가 부족한 편이라 깊숙한 계층에서 어떤 일들이 벌어지는 가 자세히 모르기 때문에, 공부하는 입장에서 이렇게 적어봤습니다. 보다 나은 코드와 보다 나은 기능, 보다 편리한 방법, 그리고 보다 깊은 계층에서의 움직임에 대한 격렬한 논의는 아래에 언급된 IRC나 email 로 부탁드리겠습니다. :-)

- 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, irc.freenode.org, #perl-kr)에서 JEEN에게 연락하시면 됩니다.


신고
IT/Perl 2008.05.27 16:12

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


 흡, 휴가라서 그런지 시간이 남네요. 그러면 시작해 보겠습니다.


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

- #4 에서는...

  - 간단하게 CPAN 상에 올려진 PoCo::IRC::Plugin::(.+) 에 대해서 알아봤습니다.
  - Plugin 추가/사용에 대해서 간단하게 알아봤습니다.

 - #5 에서는

  - Encode 모듈을 사용한 한글 취급에 대해서 알아보겠습니다.
  - 실제 사용중인 Bot Command 에 대한 사용예제를 보여드리겠습니다.
 
 - IRC에서의 한글 사용

 현재 hanIRC는 cp949 라는 문자인코딩을 사용하고 있습니다. freenode 같은 경우는 utf-8 이죠. 최근에 한국 펄 커뮤니티(이러면 뭔가 거창해 보임..) 쪽에서 freenode 와 hanIRC 병행체제로 가게 되어서, BOT도 이에 맞춰서 기존의 인코딩 방식을 바꿔줘야 했습니다.
 그리고 Perl 에서의 이런 Encode 관련된 모듈은 이름 그대로 Encode 입니다. 일본의 Dan Kogai 씨가 이 Encode 모듈의 저자입니다.
사용자 삽입 이미지

 흠.. 사실은 지난 YAPC 에서 사인 받았더랬습니다.

 Encode::KR 페이지에서도 간단하게 사용예제를 볼 수 있습니다. 말 그대로 간단합니다! :-)

   use Encode qw/encode decode/; 
$cp949 = encode("cp949", $utf8); # loads Encode::KR implicitly
$utf8 = decode("cp949", $cp949); # ditto

 Encode::KR 페이지의 SYNOPSIS 부분을 그대로 따왔습니다.

 위의 예제 그대로, 일단은 use Encode; 해주시고...
  cp949 문자열을 utf-8으로 바꾸기 위해서는 cp949 문자열을 cp949 로 decode 해주시면 됩니다. 거꾸로 utf8을 cp949 문자열로 바꾸기 위해서는 utf-8 문자열을 cp949로 encode 해주시면 끝입니다.

 어때요? 참 쉽죠? 간단하죠?
 
 - Tutorial

 그러면 간단한 사용예제를 참고해보겠습니다. #4 플러그인 예제를 축약한 것은 여기서 사용하기 위해서 였습니다. :-)

 # URL Find : Title Notify                                                                                                                                  
sub irc_urifind_uri {
    my ($who, $channel, $url, $obj, $msg) = @_[ARG0 .. ARG4];
   
        my $html = scraper {
            process 'title', title => 'TEXT';
        };
        my $data = $html->scrape(URI->new($url));
        return 0 unless $data->{title};
        my $title = $data->{title}; # Web::Scraper 에서 나온 결과물은 UTF-8으로 반환
        $title = encode('cp949', $title); # UTF-8 인 title 내용을 cp949 로 변경
        $irc->yield( privmsg => $channel => $title ); # 해당 채널에 title을 알려줍니다.
   
}

 대화중에서 URL 이 포함되었을 경우에는 그 URL의 title을 얻어내는 코드입니다. 여기에는 Web::Scraper 라는 모듈을 사용해서 간단하게 title을 뽑아낼 수 있습니다. (물론 use Web::Scraper; 해주세요) LWP::Simple 등을 이용해서 간단히 정규표현 써서  얻는 방법도 있지만... 그거야 쓰시는 분 맘대로 이기 때문에... :-)
 아무튼 Web::Scraper 에서 긁힌 결과는 UTF-8 문자열로 반환됩니다.
 이것을 cp949 로 인코딩하구요. 그리고 그 값을 채널에다가 뿌려줍니다.

사용자 삽입 이미지

그럼 이렇게 나오겠죠?



  그럼 다른 예제를 보여드리겠습니다. 물론 perl-irc-bot 에서 사용하고 있는 예제중에서 긁어오겠습니다.

 최근에 perl-irc-bot 프로젝트에 처음으로 커밋해주신 하얀_고양이 님의 네이버 지도 예제입니다.

  !map [지역] 을 입력하면.. 해당 지역의 지도를 나타내는 그런 기능입니다.
 
사용자 삽입 이미지

이같이 사용합니다.


 그러면...

사용자 삽입 이미지

 이렇게 울릉군의 중심을 나타내게 됩니다. :-)
 코드는 아래와 같습니다.

use URI::Escpae;
my $naver_map_url = 'http://map.naver.com/?query=';

sub irc_public {
    my ($sender, $who, $where, $what) = @_[SENDER, ARG0 .. ARG2];
    my $nick = ( split /!/, $who )[0];
    my $channel = $where->[0];

   if ($what =~ /^!([a-z0-9]+)\s?(.*?)?$/) {
        my ($command, $desc) = ($1, $2);
 
        if ($command eq 'map') {
                my $address = $naver_map_url . URI::Escape::uri_escape($desc);
                $irc->yield(privmsg=>$channel=>$address);
        }
   }
}

 여기서는 URI::Escape 모듈을 use 합니다. 2바이트 문자가 URL 에 그대로 들어가면, 어떤 브라우저에서는 자동으로 바꿔서 보내주기도 하지만, 어떤 브라우저는 그것을 인식하지 못하고 글자가 깨지는 경우가 발생합니다.
사용자 삽입 이미지

 보시다 시피 "서울시"라고 2바이트 문자가 query 의 값으로 직접 넣었을 경우의 결과입니다. 뭐 서울 주변이기는 하지만, 제대로 된 값이 아닐경우의 기본 표시가 이곳인 듯 합니다. :-) 검색창의 서울시라는 글씨도 막 깨져있죠?

 그래서 URI::Escape 모듈로 해당 문자열을 uri_escape 해줍니다.

 그외 여러가지 아이디어가 있으시다면, Plugin 모듈을 직접 만들어서 많은 사람들이 사용할 수 있게 만들어도 좋을 것이고... 아니면 자신만 필요한 기능이 있다면 직접 이렇게 Bot Command 를 만들어 주고 쓰셔도 됩니다.
 
  - Summary

   - Encode 모듈을 사용해서 UTF-8 => cp949 의 경우에는 encode("cp949", $utf8),
     cp949 => UTF-8 의 경우에는 decode("cp949", $cp949) 를 하면 됩니다.
   - Web::Scraper 를 통해 간단하게 HTML의 내용중의 일부를 긁어올 수 있습니다.
   - 2바이트 문자의 경우는 URI::Escape 모듈을 이용해서 URL을 Escape 시켜줘야 해당 결과를 제대로 파악할 수 있습니다.

 
 - #6 에서는

  - IKC를 통해서 외부 이벤트를 IRC에 넘겨주는 방법에 대해서 이야기 해보겠습니다.

- 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에게 연락하시면 됩니다.

신고
IT/Perl 2008.05.27 12:57

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

 웃하, 주말 합쳐서 나흘간의 휴가를 받았었는데, 그동안 좀 나태한 모습도 있었고, 그동안 perl-irc-bot 플젝에도 여러개의 새로운 리비젼이 올라오게 되었습니다. [미투데이라든가, 트위터라든가...] 그러는 중에 처음으로 하얀_고양이 님께서도 커밋을 해주시면서 점점 불타오르기 시작했습니다.

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

  - #3에서는...

  - IRC 의 이벤트 처리에는 여러가지가 있고, 대부분을 처리할 수 있었습니다.
  - IRC 커맨드에는 여러종류가 있고, 상황에 맞춰서 사용할 수 있었습니다.

  - #4에서는...

   - PoCo::IRC에 Plugin 을 붙여보도록 해보겠습니다. :-)


  - PoCo::Plugin::(.*)

 현재 PoCo::Plugin 모듈은 수십개가 CPAN에 올라와 있습니다. 하지만 그 중에서 쓸만한 것은 별로 없는 편입니다. 현재 제가 사용하는 PoCo::Plugin 모듈은 PoCo::Plugin::URI::FindPoCo::Plugin::Google::Calculator 인데요. 근데 실제로 Google::Calculator 는 별로 사용하지 않는 편입니다. 있는 지도 모르시는 분들이 많고..;; 제가 도움말도 안적어 놔서 그렇습니다.

  - Tutorial

 여기서는 URI::Find 플러그인 모듈을 사용해서 그 URL의 타이틀을 얻어내서 찍어주는 간단한 예를 보이려고 합니다.

use POE qw(Component::IRC      Component::IRC::Plugin::URI::Find                                                                                                               
Component::IRC::Plugin::Google::Calculator                                                                                                      
);

  우선은 사용할 플러그인 모듈들을 use 해줍니다.
  여기서는 *::URI::Find, *::Google::Calculator 모듈을 사용해 보도록 하겠습니다.

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

 URI::Find 의 경우에는 package_states 에 "irc_urifind_uri" 를 넣어줍니다. irc_public에서 URL을 판별하면 그것을 irc_urifind_uri 로 넘겨주게 됩니다.

sub _start {
    my $heap = $_[HEAP];
   
    my $irc = $heap->{irc};

    $irc->yield( register => 'all' );
    $irc->plugin_add(   'UriFind' =>     POE::Component::IRC::Plugin::URI::Find->new         );
    $irc->plugin_add(   'GoogleCalc' =>  POE::Component::IRC::Plugin::Google::Calculator->new );
    $irc->yield( connect => { } );
    return;
}

 _start 에서 plugin_add 를 통해서 해당 플러그인을 등록해 줍니다.

 Google::Calculator 의 경우에는 여기까지 해주시면 끝입니다.  URI::Find의 경우에는 URL을 판별했을 때 그것을 어떻게 사용할 지를 irc_urifind_uri 에 적어줍니다.
                                                                                                                                  
sub irc_urifind_uri {
    my ($who, $channel, $url, $obj, $msg) = @_[ARG0 .. ARG4];
   
    # (LWP::UserAgent|LWP::Simple) 로 여차저차 해서 <title>(.*)</title> 의 내용 뽑아서
    $title 에 담아서... 이렇게..
 
        $irc->yield( notice => $channel => $title );
    }
}

  URL을 판별했을 때의 irc_urifind_uri 에서 받는 인수는 ARG0 - 누가, ARG1 - 어떤 채널에서, ARG2 - 판별한 URL, ARG3 - URI::URL 의 객체, ARG4 - 무슨 말을 했는지 입니다.

 자, 그럼 그 URL을 받아서 타이틀을 뽑아내서, 넘겨주면 됩니다.
 LWP::Simple, LWP::UserAgent ... 뭐 여러가지가 있습니다. LWP 관련해서 한번 찾아보시면 줄줄줄 엮여져 나옵니다. There's More Than One Way To Do It 이라고 하잖아요.
 이 부분의 구현은 직접 하시면 됩니다. 물론 perl-irc-bot 에는 직접 구현되어 있으니, 참조하셔도 됩니다.

 대부분의 Plugin::(.*) 페이지에 가시면, 간단한 사용 예제를 함께 볼 수 있습니다.

사용자 삽입 이미지

 이렇게 http://www.daum.net/ 이라고 치면 Perl_^^ 이라는 봇은 daum의 타이틀을 따오는 것이죠. 뭐, 어떻게 받아들이느냐에 따라서 별로 쓸데없는 기능이기도 합니다만...

사용자 삽입 이미지

  그리고 아까 위에서 말하다가 그만둔 Google::Calculator 의 사용법입니다.
  봇을 호충하고 calc [ 적당한 식 ] 을 써주시면 됩니다. 여러가지 사용법에 대해서는
PoCo::IRC::Plugin::Google::Calculator 페이지를 참조하시면 됩니다.

 - Summary

  - 간단하게 CPAN 상에 올려진 PoCo::IRC::Plugin::(.+) 에 대해서 알아봤습니다.
  - Plugin 추가/사용에 대해서 간단하게 알아봤습니다.

 - #5 에서는

  - Encode 모듈을 사용한 한글 취급에 대해서 알아보겠습니다.
  - 실제 사용중인 Bot Command 에 대한 사용예제를 보여드리겠습니다.

 - 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에게 연락하시면 됩니다.
신고
IT/Perl 2008.05.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에게 연락하시면 됩니다.
신고
IT/Perl 2008.05.20 21:56

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


 YAPC::ASIA 2008 의 광풍이 불고난 다음, Perl 을 사용하는 사람에게 남은 숙제는, Perl에 대해 제대로 알리는 것입니다. 그리고 어떻게 하면 그것이 가능하느냐에 대해 수없이 고민을 해보았습니다. 어떻게 하면 좋을까 해서 나온 게 일단 use strict 가 무엇이고 문법이 어떻고를 떠나, 어떻게 하면 Perl에 재미를 느낄 수 있을 까 하는 것입니다.
 그래서 생각한 것이 현재 irc.hanirc.org, #perl 에서 움직이고 있는 Perl_^^ BOT에 대한 내용을 한번 올려보면 어떨까 하는 것에서 시작합니다.
 
사용자 삽입 이미지

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

 - Warning!!

 - 우선 이 내용에 대해서 불건전한 사용에 대한 책임은 지지 않습니다.
 - 본 내용은 "난 Perl 을 들어봤다. Linux 커맨드는 기본적인 것은 알고 있다." 의 조건에 부합하신 분들에게 최적화 되어 있습니다.
 - IRC Port가 열려 있어야 합니다.
 - 여기에서는 제 시스템 환경인 CentOS 5, Perl 5.8 이상의 환경을 기반으로 합니다.
 - 특히 Windows 의 경우에는 사용해 본 적이 없기에 장담할 수 없습니다.

 - Intro...


 IRC BOT 을 만들 기 위해, IRC Protocol 을 미리 다 알 필요는 없습니다(물론 저도 전부 모릅니다).
 미리 IRC 프로토콜에 맞춰서 만들어진 모듈이 이미 존재하고, 이에 대한 내용이 구성되어 있기 때문이죠.

  Perl CPAN 모듈에서 대표적인 IRC 클라이언트 모듈은

  Net::IRCPOE::Component::IRC 가 있습니다.

  이중에서 Net::IRC는 2004년 이후로는 관리되지 않고 있으며,
  POE::Component::IRC 는 2008년 4월까지 꾸준히 계속해서 관리되어 오고 있고, 이 모듈을 위한 여러가지 플러그인들이 존재하고 있습니다.

  그리고 이제부터 다루고자 할 모듈도 POE::Component::IRC(이하 PoCo::IRC) 입니다.

  - Tutorial

  우선적으로 해야할 것은 CPAN Module 의 인스톨입니다.

  대부분의 리눅스계열의 OS는 Perl은 기본적으로 들어가 있고, cpan 역시 기본적으로 지원하고 있습니다.
  만약, root 계정을 사용할 수 없으시거나, 웹 호스팅을 이용하고 계신다면, CPAN Module을 로컬 계정에 설치할 수 있습니다.
  이에 대해서는 펄매니아 위키에 자세히 적혀져 있으므로 참고하세요.

$ cpan
cpan shell -- CPAN exploration and modules installation (v1.9205)
ReadLine support enabled
                                                                                                                                              cpan[1]>

  cpan 을 실행하면 cpan용 터미널이 뜹니다. 이때 인스톨 하실 모듈을 넣어주시면 됩니다.

cpan[1]> install POE::Component::IRC

  그러면 모듈을 설치합니다. 중간에 어떤 것을 물어보신다면 그냥 엔터만 믿고 눌러주시면 됩니다.

cpan[2]> quit

  설치가 종료하면 "quit"으로 나옵니다.

  이상으로 POE::Component::IRC 모듈의 설치가 끝났습니다.

 - Summary

  - IRC 를 이용하기 위한 CPAN Module에는 대표적으로 Net::IRC, POE::Component::IRC 가 있습니다.
  - 웹 호스팅을 이용하시거나, root 계정을 사용할 수 없으실 때에는 이곳을 참조하세요.
  - CPAN Module 을 인스톨 하기 위해서는 "cpan 터미널에서 install [모듈이름]을 입력합니다."
    (혹은 cpan [모듈이름])

 - #2에서는

  - PoCo::IRC를 이용해서 BOT의 Nick 을 설정합니다.
  - IRC 서버에 접속합니다.
  - PoCo::IRC를 이용해서 어떤 처리를 할 수 있는지 알아봅니다.

※ 현재 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에게 연락하시면 됩니다.

신고

'IT > Perl' 카테고리의 다른 글

[ Perl ] IRC BOT을 만들어봅시다 :-) #2  (4) 2008.05.21
[ Perl ] IRC BOT을 만들어봅시다 :-) #1  (6) 2008.05.20
YAPC::Asia 2008 이야기 #3  (2) 2008.05.18
YAPC::Asia 2008 이야기 #2  (0) 2008.05.18
TOTAL 462,432 TODAY 22

티스토리 툴바