File Coverage

blib/lib/Mojo/IRC/Server/Chinese.pm
Criterion Covered Total %
statement 39 480 8.1
branch 0 176 0.0
condition 0 26 0.0
subroutine 13 66 19.7
pod 1 21 4.7
total 53 769 6.8


line stmt bran cond sub pod time code
1             package Mojo::IRC::Server::Chinese;
2 1     1   56049 use strict;
  1         2  
  1         30  
3             $Mojo::IRC::Server::Chinese::VERSION = "1.8.2";
4 1     1   519 use Encode;
  1         7857  
  1         53  
5 1     1   378 use Encode::Locale;
  1         2397  
  1         32  
6 1     1   5 use Carp;
  1         2  
  1         41  
7 1     1   416 use Parse::IRC;
  1         2003  
  1         43  
8 1     1   403 use Mojo::IOLoop;
  1         220019  
  1         7  
9 1     1   62 use POSIX ();
  1         2  
  1         19  
10 1     1   3 use List::Util qw(first);
  1         2  
  1         41  
11 1     1   4 use Fcntl ':flock';
  1         2  
  1         70  
12 1     1   672 use Mojo::IRC::Server::Chinese::Base 'Mojo::EventEmitter';
  1         2  
  1         6  
13 1     1   393 use Mojo::IRC::Server::Chinese::User;
  1         2  
  1         8  
14 1     1   434 use Mojo::IRC::Server::Chinese::Channel;
  1         2  
  1         7  
15              
16             has host => "0.0.0.0";
17             has port => 6667;
18             has listen => undef;
19             has network => "Chinese IRC NetWork";
20             has ioloop => sub { Mojo::IOLoop->singleton };
21             has parser => sub { Parse::IRC->new };
22             has servername => "chinese-irc-server";
23             has clienthost => undef,
24             has create_time => sub{POSIX::strftime( '%Y/%m/%d %H:%M:%S', localtime() )};
25             has log_level => "info";
26             has log_path => undef;
27             has auth=>undef;
28             has motd_path => undef;
29              
30             has version => sub{$Mojo::IRC::Server::Chinese::VERSION};
31             has start_time => sub{time};
32              
33             has user => sub {[]};
34             has channel => sub {[]};
35              
36             has log => sub{
37             require Mojo::Log;
38 1     1   207 no warnings 'redefine';
  1         2  
  1         5486  
39             *Mojo::Log::append = sub{
40             my ($self, $msg) = @_;
41             return unless my $handle = $self->handle;
42             flock $handle, LOCK_EX;
43             $handle->print(encode("console_out", decode("utf8",$msg))) or $_[0]->die("Can't write to log: $!");
44             flock $handle, LOCK_UN;
45             };
46             Mojo::Log->new(path=>$_[0]->log_path,level=>$_[0]->log_level,format=>sub{
47             my ($time, $level, @lines) = @_;
48             my $title="";
49             if(ref $lines[0] eq "HASH"){
50             my $opt = shift @lines;
51             $time = $opt->{"time"} if defined $opt->{"time"};
52             $title = (defined $opt->{"title"})?$opt->{title} . " ":"";
53             $level = $opt->{level} if defined $opt->{"level"};
54             }
55             @lines = split /\n/,join "",@lines;
56             my $return = "";
57             $time = POSIX::strftime('[%y/%m/%d %H:%M:%S]',localtime($time));
58             for(@lines){
59             $return .=
60             $time
61             . " "
62             . "[$level]"
63             . " "
64             . $title
65             . $_
66             . "\n";
67             }
68             return $return;
69             });
70             };
71              
72             sub new_user{
73 0     0 0   my $s = shift;
74 0           my $user = $s->add_user(Mojo::IRC::Server::Chinese::User->new(@_,_server=>$s));
75 0 0         return $user if $user->is_virtual;
76             $user->io->on(read=>sub{
77 0     0     my($stream,$bytes) = @_;
78 0           $bytes = $user->buffer . $bytes;
79 0           my $pos = rindex($bytes,"\r\n");
80 0 0         if($pos != -1){#\r\n
81 0           my $lines = substr($bytes,0,$pos);
82 0           my $remains = substr($bytes,$pos+2);
83 0           $user->buffer($remains);
84 0           $stream->emit(line=>$_) for split /\r?\n/,$lines;
85             }
86             else{
87 0           $pos = rindex($bytes,"\n");
88 0 0         if($pos != -1){
89 0           my $lines = substr($bytes,0,$pos);
90 0           my $remains = substr($bytes,$pos+1);
91 0           $user->buffer($remains);
92 0           $stream->emit(line=>$_) for split /\r?\n/,$lines;
93             }
94             else{
95 0           $user->buffer($bytes);
96             }
97             }
98 0           });
99             $user->io->on(line=>sub{
100 0     0     my($stream,$line) = @_;
101 0           my $msg = $s->parser->parse($line);
102 0           $user->last_active_time(time());
103 0           $s->emit(user_msg=>$user,$msg);
104 0 0         if($msg->{command} eq "CAP"){$user->emit(cap=>$msg);$s->emit(cap=>$user,$msg);}
  0 0          
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
105 0           elsif($msg->{command} eq "PASS"){$user->emit(pass=>$msg);$s->emit(pass=>$user,$msg);}
  0            
106 0           elsif($msg->{command} eq "NICK"){$user->emit(nick=>$msg);$s->emit(nick=>$user,$msg);}
  0            
107 0           elsif($msg->{command} eq "USER"){$user->emit(user=>$msg);$s->emit(user=>$user,$msg);}
  0            
108 0           elsif($msg->{command} eq "JOIN"){$user->emit(join=>$msg);$s->emit(join=>$user,$msg);}
  0            
109 0           elsif($msg->{command} eq "PART"){$user->emit(part=>$msg);$s->emit(part=>$user,$msg);}
  0            
110 0           elsif($msg->{command} eq "KICK"){$user->emit(kick=>$msg);$s->emit(kick=>$user,$msg);}
  0            
111 0           elsif($msg->{command} eq "INVITE"){$user->emit(invite=>$msg);$s->emit(invite=>$user,$msg);}
  0            
112 0           elsif($msg->{command} eq "PING"){$user->emit(ping=>$msg);$s->emit(ping=>$user,$msg);}
  0            
113 0           elsif($msg->{command} eq "PONG"){$user->emit(pong=>$msg);$s->emit(pong=>$user,$msg);}
  0            
114 0           elsif($msg->{command} eq "MODE"){$user->emit(mode=>$msg);$s->emit(mode=>$user,$msg);}
  0            
115 0           elsif($msg->{command} eq "PRIVMSG"){$user->emit(privmsg=>$msg);$s->emit(privmsg=>$user,$msg);}
  0            
116 0           elsif($msg->{command} eq "QUIT"){$user->is_quit(1);$user->emit(quit=>$msg);$s->emit(quit=>$user,$msg);}
  0            
  0            
117 0           elsif($msg->{command} eq "WHO"){$user->emit(who=>$msg);$s->emit(who=>$user,$msg);}
  0            
118 0           elsif($msg->{command} eq "WHOIS"){$user->emit(whois=>$msg);$s->emit(whois=>$user,$msg);}
  0            
119 0           elsif($msg->{command} eq "LIST"){$user->emit(list=>$msg);$s->emit(list=>$user,$msg);}
  0            
120 0           elsif($msg->{command} eq "TOPIC"){$user->emit(topic=>$msg);$s->emit(topic=>$user,$msg);}
  0            
121 0           elsif($msg->{command} eq "AWAY"){$user->emit(away=>$msg);$s->emit(away=>$user,$msg);}
  0            
122 0           else{$user->send($user->serverident,"421",$user->nick,$msg->{command},"Unknown command");}
123 0           });
124              
125             $user->io->on(error=>sub{
126 0     0     my ($stream, $err) = @_;
127 0           $user->emit("close",$err);
128 0           $s->emit(close_user=>$user,$err);
129 0           $s->debug("C[" .$user->name."] 连接错误: $err");
130 0           });
131             $user->io->on(close=>sub{
132 0     0     my ($stream, $err) = @_;
133 0           $user->emit("close",$err);
134 0           $s->emit(close_user=>$user,$err);
135 0           });
136             $user->on(close=>sub{
137 0     0     my ($user,$err) = @_;
138 0 0         return if $user->is_quit;
139 0 0         my $quit_reason = defined $user->close_reason? $user->close_reason:
    0          
140             defined $err ? $err :
141             "remote host closed connection";
142 0           $user->forward($user->ident,"QUIT",$quit_reason);
143 0           $user->is_quit(1);
144 0           $user->info("[" . $user->name . "] 已退出($quit_reason)");
145 0           $user->{_server}->remove_user($user);
146 0           });
147 0     0     $user->on(pass=>sub{my($user,$msg) = @_;my $pass = $msg->{params}[0]; $user->pass($pass);});
  0            
  0            
  0            
148 0     0     $user->on(nick=>sub{my($user,$msg) = @_;my $nick = $msg->{params}[0];$user->set_nick($nick)});
  0            
  0            
  0            
149 0     0     $user->on(user=>sub{my($user,$msg) = @_;
150 0 0         if(defined $user->search_user(user=>$msg->{params}[0])){
151 0           $user->send($user->serverident,"446",$user->nick,"该帐号已被使用");
152 0           $user->io->close_gracefully();
153 0           $user->{_server}->remove_user($user);
154 0           return;
155             }
156 0           $user->user($msg->{params}[0]);
157             #$user->mode($msg->{params}[1]);
158 0           $user->realname($msg->{params}[3]);
159 0 0 0       if(!$user->is_registered and $user->nick ne "*" and $user->user ne "*"){
      0        
160 0           $user->is_registered(1);
161             }
162 0           });
163 0     0     $user->on(join=>sub{my($user,$msg) = @_;
164 0           my $channels = $msg->{params}[0];
165 0           for my $channel_name (split /,/,$channels){
166 0           my $channel = $user->search_channel(name=>$channel_name);
167 0 0         if(defined $channel){
168 0           $user->join_channel($channel);
169             }
170             else{
171 0           $channel = $user->new_channel(name=>$channel_name,id=>lc($channel_name));
172 0           $user->join_channel($channel);
173             }
174             }
175 0           });
176 0     0     $user->on(part=>sub{my($user,$msg) = @_;
177 0           my $channel_name = $msg->{params}[0];
178 0           my $part_info = $msg->{params}[1];
179 0           my $channel = $user->search_channel(name=>$channel_name);
180 0 0         return if not defined $channel;
181 0           $user->part_channel($channel,$part_info);
182 0           });
183             $user->on(invite=>sub{
184 0     0     my($user,$msg) = @_;
185 0           my $invite_nickname = $msg->{params}[0];
186 0           my $channel_name = $msg->{params}[1];
187 0           my $channel = $user->search_channel(name=>$channel_name);
188 0           my $invite_user = $user->search_user(nick=>$invite_nickname);
189 0 0         if(not defined $invite_user){
190 0           $user->send($user->serverident,"401",$user->nick,$invite_nickname,"No such nick");
191 0           return;
192             }
193 0 0         if(not defined $channel){
    0          
194 0           $user->send($user->serverident,"403",$user->nick,$channel_name,"No such channel");
195             }
196             elsif(defined $channel){
197 0 0         if( not $user->is_join_channel($channel)){
    0          
198 0           $user->send($user->serverident,"442",$user->nick,$channel->name,"You're not on that channel");
199             }
200             elsif($invite_user->is_join_channel($channel)){
201 0           $user->send($user->serverident,"443",$user->nick,$invite_user->nick,$channel->name,"is already on channel");
202             }
203             else{
204 0           $user->send($user->serverident,"341",$user->nick,$invite_user->nick,$channel->name);
205 0           $invite_user->send($user->ident,"INVITE",$invite_user->nick,$channel->name);
206             }
207             }
208 0           });
209 0     0     $user->on(ping=>sub{my($user,$msg) = @_;
210 0           my $servername = $msg->{params}[0];
211 0           $user->send($user->serverident,"PONG",$user->servername,$servername);
212 0           });
213             $user->on(pong=>sub{
214 0     0     my($user,$msg) = @_;
215 0           my $current_ping_count = $user->ping_count;
216 0           $user->ping_count(--$current_ping_count);
217 0           });
218 0     0     $user->on(quit=>sub{my($user,$msg) = @_;
219 0           my $quit_reason = $msg->{params}[0];
220 0           $user->quit($quit_reason);
221 0           });
222 0     0     $user->on(privmsg=>sub{my($user,$msg) = @_;
223 0           $user->last_speak_time(time());
224 0 0         if(substr($msg->{params}[0],0,1) eq "#" ){
225 0           my $channel_name = $msg->{params}[0];
226 0           my $content = $msg->{params}[1];
227 0           my $channel = $user->search_channel(name=>$channel_name);
228 0 0         if(not defined $channel){$user->send($user->serverident,"403",$user->nick,$channel_name,"No such channel");return}
  0            
  0            
229 0           $channel->forward($user,$user->ident,"PRIVMSG",$channel_name,$content);
230 0           $s->info({level=>"IRC频道消息",title=>$user->nick ."|" .$channel->name.":"},$content);
231             }
232             else{
233 0           my $nick = $msg->{params}[0];
234 0           my $content = $msg->{params}[1];
235 0           my $u = $user->search_user(nick=>$nick);
236 0 0         if(defined $u){
237 0           $u->send($user->ident,"PRIVMSG",$nick,$content);
238 0 0         $user->send($user->serverident,"301",$user->nick,$u->nick,$u->away_info) if $u->is_away;
239 0           $s->info({level=>"IRC私信消息",title=>"[".$user->nick."]->[$nick] :"},$content);
240             }
241             else{
242 0           $user->send($user->serverident,"401",$user->nick,$nick,"No such nick");
243             }
244             }
245 0           });
246 0     0     $user->on(mode=>sub{my($user,$msg) = @_;
247 0 0         if(substr($msg->{params}[0],0,1) eq "#" ){
248 0           my $channel_name = $msg->{params}[0];
249 0           my $channel_mode = $msg->{params}[1];
250 0           my $channel = $user->search_channel(name=>$channel_name);
251 0 0         if(not defined $channel){$user->send($user->serverident,"403",$user->nick,$channel_name,"No such channel");return}
  0            
  0            
252 0 0 0       if(defined $channel_mode and $channel_mode eq "b"){
    0 0        
253 0           $user->send($user->serverident,"368",$user->nick,$channel_name,"End of channel ban list");
254             }
255             elsif(defined $channel_mode and $channel_mode ne "b") {
256 0           $channel->set_mode($user,$channel_mode);
257             }
258             else{
259 0           $user->send($user->serverident,"324",$user->nick,$channel_name,'+'.$channel->mode);
260 0           $user->send($user->serverident,"329",$user->nick,$channel_name,$channel->ctime);
261             }
262             }
263             else{
264 0           my $nick = $msg->{params}[0];
265 0           my $mode = $msg->{params}[1];
266 0 0         if(defined $mode){$user->set_mode($mode)}
  0            
267 0           else{$user->send($user->serverident,"221",$user->nick,'+'.$user->mode)}
268             }
269 0           });
270 0     0     $user->on(who=>sub{my($user,$msg) = @_;
271 0 0         if(substr($msg->{params}[0],0,1) eq "#" ){
272 0           my $channel_name = $msg->{params}[0];
273 0           my $channel = $user->search_channel(name=>$channel_name);
274 0 0         if(not defined $channel){$user->send($user->serverident,"403",$user->nick,$channel_name,"No such channel");return}
  0            
  0            
275 0           for($channel->users){
276 0           $user->send($user->serverident,"352",$user->nick,$channel_name,$_->user,$_->host,$_->servername,$_->nick,"H","0 " . $_->realname);
277             }
278 0           $user->send($user->serverident,"315",$user->nick,$channel_name,"End of WHO list");
279             }
280             else{
281 0           my $nick = $msg->{params}[0];
282 0           my $u = $user->search_user(nick=>$nick);
283 0 0         if(defined $u){
284 0           my $channel_name = "*";
285 0 0         if($u->is_join_channel()){
286 0           my $last_channel = (grep {$_->mode !~ /s/} $u->channels)[-1];
  0            
287 0 0         $channel_name = $last_channel->name if defined $last_channel;
288             }
289 0           $user->send($user->serverident,"352",$user->nick,$channel_name,$u->user,$u->host,$u->servername,$u->nick,"H","0 " . $u->realname);
290 0           $user->send($user->serverident,"315",$user->nick,$nick,"End of WHO list");
291             }
292             else{
293 0           $user->send($user->serverident,"401",$user->nick,$nick,"No such nick");
294             }
295            
296             }
297 0           });
298 0     0     $user->on(whois=>sub{my($user,$msg) = @_;
299 0           my $nickname = $msg->{params}[0];
300 0           my $whois_user = $user->search_user(nick=>$nickname);
301 0 0         if(not defined $whois_user){
302 0           $user->send($user->serverident,"401",$user->nick,$nickname,"No such nick");
303 0           return;
304             }
305 0           $user->send($user->serverident,"311",$user->nick,$whois_user->nick,$whois_user->user,$whois_user->host,"*",$whois_user->realname);
306 0           $user->send($user->serverident,"312",$user->nick,$whois_user->nick,$whois_user->servername,$whois_user->servername);
307 0           $user->send($user->serverident,"319",$user->nick,$whois_user->nick,join(" ",map {$_->name} $whois_user->channels));
  0            
308 0           $user->send($user->serverident,"318",$user->nick,$whois_user->nick,"End of WHOIS list");
309            
310 0           });
311 0     0     $user->on(list=>sub{my($user,$msg) = @_;
312 0           for my $channel ($user->{_server}->channels){
313 0 0         next if $channel->mode =~ /s/;
314 0           $user->send($user->serverident,"322",$user->nick,$channel->name,$channel->count(),$channel->topic);
315             }
316 0           $user->send($user->serverident,"323",$user->nick,"End of LIST");
317 0           });
318 0     0     $user->on(topic=>sub{my($user,$msg) = @_;
319 0           my $channel_name = $msg->{params}[0];
320 0           my $channel = $user->search_channel(name=>$channel_name);
321 0 0         if(not defined $channel){$user->send($user->serverident,"403",$user->nick,$channel_name,"No such channel");return}
  0            
  0            
322 0 0         if(defined $msg->{params}[1]){
323 0           my $topic = $msg->{params}[1];
324 0           $channel->set_topic($user,$topic);
325             }
326             else{
327 0           $user->send($user->serverident,"332",$user->nick,$channel_name,$channel->topic);
328             }
329 0           });
330 0     0     $user->on(away=>sub{my($user,$msg) = @_;
331 0 0         if($msg->{params}[0]){
332 0           my $away_info = $msg->{params}[0];
333 0           $user->away($away_info);
334             }
335             else{
336 0           $user->back();
337             }
338 0           });
339              
340 0           $user;
341             }
342             sub new_channel{
343 0     0 0   my $s = shift;
344 0           my $channel = $s->add_channel(Mojo::IRC::Server::Chinese::Channel->new(@_,_server=>$s));
345 0           $s->emit(new_channel=>$channel);
346 0           return $channel;
347             }
348             sub add_channel{
349 0     0 0   my $s = shift;
350 0           my $channel = shift;
351 0           my $is_cover = shift;
352 0           my $channel_name = $channel->name;
353 0 0         $channel_name = "#" . $channel_name if substr($channel_name,0,1) ne "#";
354 0           $channel_name=~s/\s|,|&//g;
355 0           $channel->name($channel_name);
356 0           my $c = $s->search_channel(name=>$channel->name);
357 0 0         return $c if defined $c;
358 0           $c = $s->search_channel(id=>$channel->id);
359 0 0         if(defined $c){if($is_cover){$s->info("频道 " . $c->name. " 已更新");$c=$channel;};return $c;}
  0 0          
  0            
  0            
  0            
360 0           else{push @{$s->channel},$channel;$s->info("频道 ".$channel->name. " 已创建");return $channel;}
  0            
  0            
  0            
361              
362             }
363             sub add_user{
364 0     0 0   my $s = shift;
365 0           my $user = shift;
366 0           my $is_cover = shift;
367 0 0         if($user->is_virtual){
368 0           my $nick = $user->nick;
369 0 0         $nick =~s/\s|\@|!//g;$nick = '未知昵称' if not $nick;
  0            
370 0           $user->nick($nick);
371 0           my $u = $s->search_user(nick=>$user->nick,virtual=>1,id=>$user->id);
372 0 0         return $u if defined $u;
373 0           while(1){
374 0           my $u = $s->search_user(nick=>$user->nick);
375 0 0         if(defined $u){
376 0 0         if($u->nick =~/\((\d+)\)$/){
377 0           my $num = $1;$num++;$user->nick($nick . "($num)");
  0            
  0            
378             }
379 0           else{$user->nick($nick . "(1)")}
380             }
381 0           else{last};
382             }
383             }
384 0           my $u = $s->search_user(id=>$user->id);
385 0 0         if(defined $u){if($is_cover){$s->info("C[".$u->name. "]已更新");$u=$user;};return $u;}
  0 0          
  0            
  0            
  0            
386             else{
387 0           push @{$s->user},$user;$s->info("C[".$user->name. "]已加入");return $user;
  0            
  0            
  0            
388             }
389             }
390             sub remove_user{
391 0     0 0   my $s = shift;
392 0           my $user = shift;
393 0           for(my $i=0;$i<@{$s->user};$i++){
  0            
394 0 0         if($user->id eq $s->user->[$i]->id){
395 0           $_->remove_user($s->user->[$i]->id) for $s->user->[$i]->channels;
396 0           $user->channel([]);
397 0           splice @{$s->user},$i,1;
  0            
398 0 0         if($user->is_virtual){
399 0           $s->info("c[".$user->name."] 已被移除");
400             }
401             else{
402 0           $s->info("C[".$user->name."] 已离开");
403             }
404 0           last;
405             }
406             }
407             }
408              
409             sub remove_channel{
410 0     0 0   my $s = shift;
411 0           my $channel = shift;
412 0           for(my $i=0;$i<@{$s->channel};$i++){
  0            
413 0 0         if($channel->id eq $s->channel->[$i]->id){
414 0           splice @{$s->channel},$i,1;
  0            
415 0           $s->info("频道 ".$channel->name." 已删除");
416 0           last;
417             }
418             }
419             }
420             sub users {
421 0     0 0   my $s = shift;
422 0           return @{$s->user};
  0            
423             }
424             sub channels{
425 0     0 0   my $s = shift;
426 0           return @{$s->channel};
  0            
427             }
428              
429             sub search_user{
430 0     0 0   my $s = shift;
431 0           my %p = @_;
432 0 0         return if 0 == grep {defined $p{$_}} keys %p;
  0            
433 0 0         if(wantarray){
434 0 0   0     return grep {my $c = $_;(first {$p{$_} ne $c->$_} grep {defined $p{$_}} keys %p) ? 0 : 1;} @{$s->user};
  0            
  0            
  0            
  0            
  0            
435             }
436             else{
437 0 0   0     return first {my $c = $_;(first {$p{$_} ne $c->$_} grep {defined $p{$_}} keys %p) ? 0 : 1;} @{$s->user};
  0            
  0            
  0            
  0            
  0            
438             }
439              
440             }
441             sub search_channel{
442 0     0 0   my $s = shift;
443 0           my %p = @_;
444 0 0         return if 0 == grep {defined $p{$_}} keys %p;
  0            
445 0 0         if(wantarray){
446 0 0   0     return grep {my $c = $_;(first {$_ eq "name"?(lc($p{$_}) ne lc($c->$_)):($p{$_} ne $c->$_)} grep {defined $p{$_}} keys %p) ? 0 : 1;} @{$s->channel};
  0 0          
  0            
  0            
  0            
  0            
447             }
448             else{
449 0 0   0     return first {my $c = $_;(first {$_ eq "name"?(lc($p{$_}) ne lc($c->$_)):($p{$_} ne $c->$_)} grep {defined $p{$_}} keys %p) ? 0 : 1;} @{$s->channel};
  0 0          
  0            
  0            
  0            
  0            
450             }
451              
452             }
453             sub timer{
454 0     0 0   my $s = shift;
455 0           $s->ioloop->timer(@_);
456             }
457             sub interval{
458 0     0 0   my $s = shift;
459 0           $s->ioloop->recurring(@_);
460             }
461             sub ident {
462 0     0 0   return $_[0]->servername;
463             }
464             sub ready {
465 0     0 0   my $s = shift;
466 0           my @listen = ();
467 0 0 0       if(defined $s->listen and ref $s->listen eq "ARRAY"){
468 0           for (@{$s->listen}){
  0            
469 0   0       $_->{address} = (delete $_->{host}) // "0.0.0.0";
470 0 0         $_->{port} = ($_->{tls} ? 6697: 6667) if not defined $_->{port};
    0          
471 0           push @listen,$_;
472             }
473             }
474             else{
475 0           @listen = ({host=>$s->host,port=>$s->port});
476             }
477 0           for my $listen (@listen){
478             $s->ioloop->server($listen=>sub{
479 0     0     my ($loop, $stream) = @_;
480 0           $stream->timeout(0);
481 0           my $id = join ":",(
482             $stream->handle->sockhost,
483             $stream->handle->sockport,
484             $stream->handle->peerhost,
485             $stream->handle->peerport
486             );
487 0           my $user = $s->new_user(
488             id => $id,
489             name => join(":",($stream->handle->peerhost,$stream->handle->peerport)),
490             io => $stream,
491             );
492 0 0         $user->host($s->clienthost) if defined $s->clienthost;
493 0           $s->emit(new_user=>$user);
494 0           });
495             }
496            
497             $s->on(new_user=>sub{
498 0     0     my ($s,$user)=@_;
499 0           $s->debug("C[".$user->name. "]已连接");
500 0           });
501              
502             $s->on(user_registered=>sub{
503 0     0     my($s,$user) = @_;
504 0 0 0       if(defined $s->auth and ref $s->auth eq "CODE"){
505 0 0         if(! $s->auth->($user->nick,$user->user,$user->pass)){
506 0           $user->send($user->serverident,"464",$user->nick,"认证失败");
507 0           $user->io->close_gracefully();
508 0           $user->{_server}->remove_user($user);
509 0           return;
510             }
511             }
512 0           $user->send($user->serverident,"001",$user->nick,"Welcome to " . $s->network . " " . $user->ident);
513 0           $user->send($user->serverident,"002",$user->nick,"Your host is " . $s->servername. ", running version " . $s->version);
514 0           $user->send($user->serverident,"003",$user->nick,"This server was created " . POSIX::strftime('%a %b %d %Y at %H:%M:%S %Z',localtime($s->start_time)));
515 0           $user->send($user->serverident,"004",$user->nick,$s->servername." " .$s->version . " aio PioOvstkb");
516 0           $user->send($user->serverident,"251",$user->nick,"There are ". (0+@{$s->user}) ." users and 0 services on 1 servers");
  0            
517 0 0 0       if(defined $s->motd_path and -f $s->motd_path and -s $s->motd_path){
      0        
518 0           eval{
519 0 0         open my $motd_fd,$s->motd_path or die "open motd file [" . $s->motd_path . "] error: $!";
520 0           $user->send($user->serverident,"375",$user->nick,"- " . $s->servername . " Message of the day - ");
521 0           while(<$motd_fd>){
522 0           s/[\r\n]+$//g;
523 0           $user->send($user->serverident,"372",$user->nick,"- $_");
524             }
525 0           $user->send($user->serverident,"376",$user->nick,"End of MOTD command");
526             };
527 0 0         $s->warn($@) if $@;
528             }
529 0           $user->send($user->serverident,"396",$user->nick,$user->host,"您的主机地址已被隐藏");
530 0           });
531             $s->on(user_msg=>sub{
532 0     0     my ($s,$user,$msg)=@_;
533 0           $s->debug("C[".$user->name."] $msg->{raw_line}");
534 0           });
535              
536             $s->on(close_user=>sub{
537 0     0     my ($s,$user,$msg)=@_;
538 0           });
539              
540             $s->interval(60,sub{
541 0 0   0     for(grep {defined $_->last_active_time and time() - $_->last_active_time > 60 } grep {!$_->is_virtual} $s->users){
  0            
  0            
542 0 0         if($_->ping_count >=3 ){
543 0           $_->close_reason("PING timeout 180 seconds");
544 0           $_->io->close_gracefully();
545             }
546             else{
547 0           $_->send(undef,"PING",$_->servername);
548 0           my $current_ping_count = $_->ping_count;
549 0           $_->ping_count(++$current_ping_count);
550             }
551             }
552 0           });
553             }
554              
555             sub run{
556 0     0 0   my $s = shift;
557 0           $s->ready();
558 0 0         $s->ioloop->start unless $s->ioloop->is_running;
559             }
560             sub die{
561 0     0 0   my $s = shift;
562 0     0     local $SIG{__DIE__} = sub{$s->log->fatal(@_);exit -1};
  0            
  0            
563 0           Carp::confess(@_);
564             }
565             sub info{
566 0     0 0   my $s = shift;
567 0           $s->log->info(@_);
568 0           $s;
569             }
570             sub warn{
571 0     0 0   my $s = shift;
572 0           $s->log->warn(@_);
573 0           $s;
574             }
575             sub error{
576 0     0 1   my $s = shift;
577 0           $s->log->error(@_);
578 0           $s;
579             }
580             sub fatal{
581 0     0 0   my $s = shift;
582 0           $s->log->fatal(@_);
583 0           $s;
584             }
585             sub debug{
586 0     0 0   my $s = shift;
587 0           $s->log->debug(@_);
588 0           $s;
589             }
590              
591              
592             1;