POE::Component::IRC で遊ぶ

Perl の IRC モジュールと言えば、ちょっと前まで Net::IRC だと思っていたが、久しく cpan でそいつをインストールしようとすると、

時代遅れだから POE::Component::IRC を使っちゃいなー ! “

と言われた。

イベントドリブンな IRC クライアントを書く為のモジュールで、PING/PONG の自動応答など、IRC セッションを裏で面倒見てくれる便利なモジュールらしい。

POE 自体、ネットワーク関係の疑似マルチスレッディング、同期通信など、カーネル側でサポートされそうな事をやってくれる便利なパッケージ。これを使うと、よ り環境に依存しないネットワークツールが作れる訳だ。

POE::Component::IRC の日本語ドキュメントもさくっと見つかった。

サンプルがついているので、ちょっと遊んでみる。ついでに、ホスト& IRC サーバともども、UTF-8 な日本語環境で利用する為の工夫もしてみた。

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use Encode;
use POE qw(Component::IRC);

# IRC の接続設定

my $nickname = 'poepoe' . $$;
my $ircname = 'POE POE Bot';
my $ircserver = 'sasebo.ddo.jp';
my $port = 6665;
my @channels = ( '#alice' );

# 接続設定を渡して、オブジェクトを作成

my $irc = POE::Component::IRC->spawn(
    nick => $nickname,
    server => $ircserver,
    port => $port,
    ircname => $ircname,
) or die "Failed. $!";

# イベントハンドラを登録

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

# 実行

$poe_kernel->run();
exit 0;

# 以下、イベント
# 接続

sub start {
    my ($kernel,$heap) = @[KERNEL,HEAP];
    my $irc_session = $heap->{irc}->session_id();
    $kernel->post( $irc_session => register => 'all' );
    $kernel->post( $irc_session => connect => { } );
    undef;
}

# 接続完了 → チャンネルへ Join !

sub irc_001 {
    my ($kernel,$sender) = @[KERNEL,SENDER];
    my $poco_object = $sender->get_heap();
    print "Connected to ", $poco_object->server_name(), "\n";
    $kernel->post( $sender => join => $ ) for @channels;
    undef;
}

# 発言時や状態が変わった時などに呼ばれるイベント。
# ここに自由な挙動を書く。

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

    # 内部 Unicode 用に UTF8 フラグを付与
    $what = Encode::decode("utf-8",$what);

    if ( $what =~ /イ[カモ]/ ) {
        # 本当は、BOT の発言は privmsg ではなく notice にするのがマナー。
        $kernel->post( $sender => privmsg => $channel => "おいしいです、$nick。" );
    }

    # 茶筅に投げてみるテスト
    if ( my ($rot13) = $what =~ /^! (.+)/ ) {
        foreach my $line (echo '$rot13'|chasen -iw){
            $kernel->post( $sender => notice => $channel => $line );
        }
    }
    # 出力時には、UTF8 フラグを除去
    $what = Encode::encode("utf-8",$what);
    undef;
}

# 標準出力に動作ログを吐く

sub default {
    my ($event, $args) = @[ARG0 .. $#_];
    my @output = ( "$event: " );
    foreach my $arg ( @$args ) {
        if ( ref($arg) eq 'ARRAY' ) {
            push( @output, "[" . join(" ,", @$arg ) . "]" );
        } else {
            push ( @output, "'$arg'" );
        }
    }
    print STDOUT join ' ', @output, "\n";
    return 0;
}

ソースも LOCALE も IRC サーバも UTF-8 だが、Perl の内部保持している文字列データは単純な Unicode なので、UTF-8 フラグを付けてから処理してやらなければならない。

上の例では、「イカ」とか「イモ」という発言があれば反応する。

参考ページ

※ 2020/07/02 度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。

投稿者:

dyama

佐世保のシステムエンジニアです。詳しいプロフィールやこのブログについてはこちらをご覧ください。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください