root/lang/perl/tiarra/trunk/module/Auto/Outputz.pm

Revision 24519, 4.6 kB (checked in by topia, 8 months ago)

fix config reloading issue.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id URL Date Rev Author
Line 
1# -----------------------------------------------------------------------------
2# $Id$
3# -----------------------------------------------------------------------------
4package Auto::Outputz;
5use strict;
6use warnings;
7use base qw(Module);
8use Multicast;
9use Module::Use qw(Auto::AliasDB Tools::HTTPClient Auto::Utils);
10use Auto::AliasDB;
11use Tools::HTTPClient; # >= r11345
12use Auto::Utils;
13use HTTP::Request::Common;
14
15sub new {
16  my ($class) = shift;
17  my $this = $class->SUPER::new(@_);
18
19  $this->config_reload(undef);
20
21  return $this;
22}
23
24sub config_reload {
25  my ($this, $old_config) = @_;
26
27  if (!$this->config->key) {
28      die __PACKAGE__.": key must be filled.";
29  }
30
31  $this->{channels} = [];
32  foreach ($this->config->channel('all')) {
33      my ($dirname,$mask) = split /\s+/;
34      if (!defined($dirname) || $dirname eq '' ||
35              !defined($mask) || $mask eq '') {
36          die 'Illegal definition in '.__PACKAGE__."/channel : $_\n";
37      }
38      push @{$this->{channels}},[$dirname,$mask];
39  }
40  $this->{matching_cache} = {};
41
42  my $cmds;
43  if ($this->config->commands) {
44      $cmds = join('|', map quotemeta, split /\s+/, $this->config->commands);
45  } else {
46      $cmds = 'PRIVMSG';
47  }
48  $this->{commands} = qr/^$cmds$/;
49
50  return $this;
51}
52
53## from Log::Channel
54sub _mangle_string {
55    my ($this, $str) = @_;
56
57    $str =~ s/![0-9A-Z]{5}/!/;
58    $str =~ s{([^-\w@#%!+&.\x80-\xff])}{
59        sprintf('=%02x', unpack("C", $1));
60    }ge;
61
62    $str;
63}
64
65sub _channel_match {
66    # 指定されたチャンネル名にマッチするログ保存ファイルのパターンを定義から探す。
67    # 一つもマッチしなければundefを返す。
68    # このメソッドは検索結果を$this->{matching_cache}に保存して、後に再利用する。
69    my ($this,$channel,$chan_short,$network) = @_;
70
71    my $cached = $this->{matching_cache}->{$channel};
72    if (defined $cached) {
73        if ($cached eq '') {
74            # マッチするエントリは存在しない、という結果がキャッシュされている。
75            return undef;
76        }
77        else {
78            return $cached;
79        }
80    }
81
82    foreach my $ch (@{$this->{channels}}) {
83        if (Mask::match($ch->[1],$channel)) {
84            my $name = Tools::HashTools::replace_recursive(
85                $ch->[0], [{
86                    channel => $this->_mangle_string($channel),
87                    channel_short => $this->_mangle_string($chan_short),
88                    network => $this->_mangle_string($network)}]);
89
90            $this->{matching_cache}->{$channel} = $name;
91            return $name;
92        }
93    }
94    $this->{matching_cache}->{$channel} = '';
95    undef;
96}
97
98sub message_arrived {
99  my ($this,$msg,$sender) = @_;
100
101  # クライアントからのメッセージか?
102  if ($sender->isa('IrcIO::Client')) {
103      if ($msg->command =~ $this->{commands}) {
104          my $text = $msg->param(1);
105          my $full_ch_name = $msg->param(0);
106          my ($target, $network) = Multicast::detach($full_ch_name);
107          if (Multicast::nick_p($target)) {
108              $target = 'priv';
109              $full_ch_name = Multicast::attach($target, $network);
110          }
111
112          # calc size
113          my $len = $text =~ tr/\x00-\x7f\xc0-\xf7/\x00-\x7f\xc0-\xf7/;
114
115          my $name = $this->_channel_match($full_ch_name, $target, $network);
116          if ($name) {
117              my $url = "http://outputz.com/api/post/";
118              my @data = (key => $this->config->key,
119                          uri => $name,
120                          size => $len);
121              my $runloop = $this->_runloop;
122              Tools::HTTPClient->new(
123                  Request => POST($url, \@data),
124                 )->start(
125                     Callback => sub {
126                         my $stat = shift;
127                         $runloop->notify_warn(__PACKAGE__." post failed: $stat")
128                             unless ref($stat);
129                         ## FIXME: check response (should check 'error')
130                     },
131                    );
132          }
133      }
134  }
135
136  return $msg;
137}
138
1391;
140
141=pod
142info: チャンネルの発言文字数を outputz に送信する
143default: off
144
145# 復活の呪文。
146key: some secret
147
148# 送信対象にするコマンドの設定。
149# 省略された場合は PRIVMSG 。
150# パラメータ1が送信先、パラメータ2が本文でなければ動作しないので、
151# 動作するコマンドは PRIVMSG/NOTICE/TOPIC/PART 程度。
152-command: PRIVMSG
153
154# 各チャンネルのURIの設定。
155# 記述された順序で検索されるので、全てのチャンネルにマッチする"*"などは最後に書かなければならない。
156# フォーマットは次の通り。
157# channel: <URI> (<チャンネル名> / 'priv')@<ネットワーク名>
158# #(channel) はチャンネル名に、 #(channel_short) はネットワークなしの
159# チャンネル名に、 #(network) はネットワーク名にそれぞれ置き換えられる。
160# また、危険な文字は自動的にエスケープされる。
161channel: http://#(network).irc.example.com/#(channel_short) *
162
163=cut
Note: See TracBrowser for help on using the browser.