]> ruin.nu Git - NDIRC.git/blob - Bot.pm
Discord id in +user
[NDIRC.git] / Bot.pm
1 #**************************************************************************
2 #   Copyright (C) 2009 by Michael Andreen <harvATruinDOTnu>               *
3 #                                                                         *
4 #   This program is free software; you can redistribute it and/or modify  *
5 #   it under the terms of the GNU General Public License as published by  *
6 #   the Free Software Foundation; either version 2 of the License, or     *
7 #   (at your option) any later version.                                   *
8 #                                                                         *
9 #   This program is distributed in the hope that it will be useful,       *
10 #   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 #   GNU General Public License for more details.                          *
13 #                                                                         *
14 #   You should have received a copy of the GNU General Public License     *
15 #   along with this program; if not, write to the                         *
16 #   Free Software Foundation, Inc.,                                       *
17 #   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
18 #**************************************************************************/
19 package NDIRC::Bot;
20
21 use strict;
22 use warnings;
23 use feature ':5.10';
24
25 use Moose;
26
27 use POE::Component::IRC::Common qw/irc_to_utf8/;
28 use POE::Session;
29 use POE::Kernel;
30 use POE::Component::IRC::Plugin::Logger;
31 use POE::Component::IRC::Plugin::BotTraffic;
32 use POE::Component::IRC::Plugin::Connector;
33 use POE::Component::IRC::Plugin::AutoJoin;
34 use POE::Component::IRC::Plugin::NickReclaim;
35
36 use Mojo::Discord;
37 use Mojo::IOLoop;
38
39 use NDIRC::Dispatcher;
40 use NDIRC::IrcContext;
41
42 use IO::File;
43
44 has disp => (
45         is => 'rw',
46         isa => 'Object',
47         lazy_build => 1
48 );
49
50 has discord => (
51         is => 'rw',
52         isa => 'Object'
53 );
54
55 has discord_name => (
56         is => 'rw',
57         isa => 'Str'
58 );
59
60 has discord_id => (
61         is => 'rw',
62         isa => 'Str'
63 );
64
65 has discord_channels => (
66         is => 'rw',
67         isa => 'HashRef',
68         default => sub { {} }
69 );
70
71 has targets => (
72         is => 'ro',
73         isa => 'HashRef[ArrayRef[Str]]',
74         default => sub{ {} },
75 );
76
77 # We registered for all events, this will produce some debug info.
78 sub _default {
79         my ($event, $args) = @_[ARG0 .. $#_];
80         my @output = ( "$event: " );
81
82         for my $arg (@$args) {
83                 if ( ref $arg eq 'ARRAY' ) {
84                         push( @output, '[' . join(', ', @$arg ) . ']' );
85                 }
86                 else {
87                         push ( @output, "'$arg'" );
88                 }
89         }
90         print join ' ', @output, "\n";
91         return 0;
92 }
93
94 sub _start {
95         my ($self,$kernel,$heap,$session) = @_[OBJECT,KERNEL,HEAP,SESSION];
96
97         # retrieve our component's object from the heap where we stashed it
98         my $irc = $heap->{irc};
99         $kernel->sig( DIE => 'sig_DIE' );
100         $kernel->sig( USR1 => 'sig_usr1' );
101         $kernel->sig( USR2 => 'sig_usr2' );
102         $kernel->sig( INT => 'signal_handler' );
103
104         $irc->plugin_add( 'NickReclaim', POE::Component::IRC::Plugin::NickReclaim->new() );
105         $irc->plugin_add( 'AutoJoin', POE::Component::IRC::Plugin::NickReclaim->new() );
106         $irc->plugin_add( 'BotTraffic', POE::Component::IRC::Plugin::BotTraffic->new() );
107         $irc->plugin_add('Logger', POE::Component::IRC::Plugin::Logger->new(
108                 Path    => 'irclogs',
109                 DCC     => 0,
110                 Private => 1,
111                 Public  => 1,
112                 Sort_by_date => 1,
113                 Strip_color => 1,
114                 Strip_formatting => 1,
115                 Notices => 1,
116         ));
117
118         $heap->{connector} = POE::Component::IRC::Plugin::Connector->new(
119                 servers => [['irc.netgamers.org'], ['underworld.no.eu.netgamers.org']
120                         ,['firefly.no.eu.netgamers.org'], ['underworld.ca.us.netgamers.org'] ]
121         );
122         $irc->plugin_add( 'Connector' => $heap->{connector} );
123
124         $irc->yield( register => 'all' );
125         $irc->yield( connect => { server => 'irc.netgamers.org' } );
126
127         $kernel->delay( refresh => 60 );
128
129         if (my $f =  new IO::File 'discord'){
130                 my $user = <$f>;
131                 chomp $user;
132                 my $token = <$f>;
133                 chomp $token;
134
135                 $self->discord(Mojo::Discord->new(
136                                 'token'     => $token,
137                                 'name'      => $user,
138                                 'url'       => 'https://nd.ruin.nu',
139                                 'version'   => '1.0',
140                                 'callbacks' => {
141                                         'READY'          => sub { $self->discord_ready(@_) },
142                                         'MESSAGE_CREATE' => sub { $self->discord_message_create(@_) },
143                                         'GUILD_CREATE' => sub { $self->discord_guild_create(@_) },
144                                         'CHANNEL_CREATE' => sub { $self->discord_channel_create(@_) },
145                                 },
146                                 'reconnect' => 1,
147                                 'verbose'   => 1,
148                         ));
149                 $self->discord->init();
150         }
151         return;
152 }
153
154 sub auth {
155         my $heap = $_[HEAP];
156
157         if (my $f =  new IO::File 'auth'){
158                 my $user = <$f>;
159                 chomp $user;
160                 my $pass = <$f>;
161                 chomp $pass;
162                 $heap->{irc}->yield(qbot_auth => $user => $pass);
163         }
164 }
165
166 sub sig_usr1 {
167         my ($kernel,$heap) = @_[KERNEL,HEAP];
168
169         $kernel->yield( 'refresh' );
170 }
171
172 sub clear_constraint {
173         my $tc = shift;
174
175         while (1) {
176                 if (ref $tc eq 'MooseX::Meta::TypeConstraint::Structured'){
177                         for my $t (@{$tc->{type_constraints}}){
178                                 clear_constraint($t);
179                         }
180
181                 }
182                 if (ref $tc eq 'Moose::Meta::TypeConstraint::Parameterized'){
183                         clear_constraint($tc->{type_parameter});
184                 }
185                 last if ref $tc eq 'HASH';
186                 last if ref $tc eq '';
187                 if (defined $tc->{_type_constraint}){
188                         $tc = $tc->{_type_constraint};
189                 }elsif(defined $tc->{__type_constraint}){
190                         $tc = $tc->{__type_constraint};
191                 }else{
192                         last;
193                 }
194         }
195 }
196
197 sub clear_metains {
198         my $ins = shift;
199
200         for my $a (@{$ins->{attributes}}){
201                 for my $m (@{$a->{associated_methods}}){
202                         $m->{body} = undef;
203                 }
204                 clear_constraint($a->{isa});
205         }
206 }
207
208 sub clear_cycles {
209         my $c = shift;
210
211         for my $m (values %{$c->meta->{methods}}){
212                 clear_constraint($m->{type_constraint});
213
214                 my $ps = $m->{parsed_signature};
215                 for my $p (@{$ps->{_positional_params}->{params}}){
216                         clear_metains($p->{__MOP__}->{_meta_instance});
217                 }
218
219                 $m->{body} = undef;
220         }
221         clear_metains($c->meta->{_meta_instance});
222 }
223
224
225 sub sig_usr2 {
226         my $self = shift @_;
227
228         for my $c (values %{$self->disp->commands}){
229                 clear_cycles($c);
230         }
231
232         $self->disp($self->_build_disp);
233 }
234
235 sub _build_disp {
236         my ($self) = @_;
237         my $disp = new NDIRC::Dispatcher;
238
239         if (my $commands = new IO::File 'commands'){
240                 my @commands = split /\W+/, do{local $/; <$commands>};
241                 say "Loading commands from: @commands";
242                 $disp->load(@commands);
243         }
244
245         %{$self->targets} = ();
246         my $channels = new IO::File 'channels' or die $!;;
247         while (<$channels>){
248                 my ($chan, @types) = split /\s+/;
249                 say "$chan - @types";
250                 if ($chan =~ /^(.*):(.*)$/){
251                         $chan = $1;
252                         $self->targets->{$2} = [] unless exists $self->targets->{$2};
253                         push @{$self->targets->{$2}},$chan;
254                         say "$2 - @{$self->targets->{$2}}";
255                 }
256                 $disp->add_channel($chan,\@types);
257         }
258
259         return $disp;
260 }
261
262 sub sig_DIE {
263         my( $kernel,$sig, $ex ) = @_[ KERNEL,ARG0, ARG1 ];
264         say "DIED!!!!!!!!!!!!!!";
265         # $sig is 'DIE'
266         # $ex is the exception hash
267         warn "$$: error in event: $ex->{error_str}";
268         $kernel->sig_handled();
269
270         # Send the signal to session that sent the original event.
271         #if( $ex->{source_session} ne $_[SESSION] ) {
272         #$kernel->signal( $ex->{source_session}, 'DIE', $sig, $ex );
273         #}
274 }
275
276 sub signal_handler {
277         my ($kernel, $signal_name, $heap) = @_[KERNEL, ARG0, HEAP];
278         print "First session caught SIG$signal_name\n";
279
280         given($signal_name){
281                 when ('INT') {
282                         exit unless $heap->{irc}->connected;
283                         $heap->{INT} = 1;
284                         $heap->{irc}->yield(quit => 'Bye!');
285                         $kernel->sig_handled();
286                 }
287         }
288         #$kernel->sig_handled();
289 }
290
291 sub irc_disconnected {
292         my ($sender,$heap) = @_[SENDER,HEAP];
293
294         exit if $heap->{INT};
295 }
296
297 sub irc_001 {
298         my ($self,$sender,$kernel) = @_[OBJECT,SENDER,KERNEL];
299
300         # Since this is an irc_* event, we can get the component's object by
301         # accessing the heap of the sender. Then we register and connect to the
302         # specified server.
303         my $irc = $sender->get_heap();
304
305         print "Connected to ", $irc->server_name(), "\n";
306
307         $kernel->yield( 'auth' );
308         $irc->yield( mode => $irc->nick_name, '+ix');
309
310         # we join our channels
311         $irc->yield( join => $_ ) for grep /^#/, keys %{$self->disp->channels};
312         return;
313 }
314
315 sub irc_invite {
316         my ($self,$sender, $who, $channel) = @_[OBJECT,SENDER, ARG0 .. ARG1];
317         my $irc = $sender->get_heap();
318
319         $irc->yield( join => $_ ) for grep /^$channel$/i, keys %{$self->disp->channels}
320 }
321
322 sub irc_public {
323         $_[ARG2] = irc_to_utf8 $_[ARG2];
324 }
325
326 sub irc_msg {
327         $_[ARG2] = irc_to_utf8 $_[ARG2];
328 }
329
330 sub  refresh {
331 }
332
333 sub irc_join {
334 }
335
336 sub discord_ready {
337         my $self = shift;
338         my $hash = shift;
339         $self->discord_id($hash->{user}{id});
340         $self->discord_name($hash->{user}{username});
341
342         say localtime(time) . " - Connected to Discord. $self->{discord_id}";
343 }
344
345 sub discord_message_create {
346 }
347
348 sub discord_guild_create {
349         my $self = shift;
350         my $hash = shift;
351
352         for my $chan (@{$hash->{channels}}) {
353                 say localtime(time) . " - $chan->{id} - $chan->{name}";
354                 $self->discord_channels->{$chan->{id}} = $chan;
355         }
356 }
357
358 sub discord_channel_create {
359         my $self = shift;
360         my $chan = shift;
361
362         for my $key (keys %{$chan}) {
363                 say localtime(time) . " - $key - $chan->{$key}";
364         }
365         $self->discord_channels->{$chan->{id}} = $chan;
366 }
367
368 sub parseCommand {
369         my ($self, $msg, $server, $nick, $address, $channel, $model) = @_;
370
371         return if $channel !~ /^#/ && $msg =~ /^~/;
372         $msg = ".$msg"  if $channel !~ /^#/ && $msg =~ /^[^.!]/;
373
374         my ($p,$command,$args) = ($msg =~ /^([.!~])(\S+)(?: (.+))?/);
375
376         if ($msg =~ m{https?://[\w.]+/.+?scan(_id|_grp)?=(\w+)}){
377                 if (!$command || $command =~ m{^https?://}){
378                         ($p,$command,$args) = ('.','addscan',$msg);
379                 }elsif($command ne 'addscan'){
380                         $self->parseCommand (".addscan $msg", $server, $nick, $address, $channel, $model)
381                 }
382         }
383
384         return 0 unless $self->disp->has_command($command,$channel);
385
386         my $reply_string;
387         given ($p){
388                 when ('!'){
389                         $reply_string = "privmsg $nick";
390                 }
391                 when ('~'){
392                         $reply_string = "privmsg $channel";
393                 }
394                 default {
395                         $reply_string = "notice $nick";
396                 }
397         }
398
399         $address =~ s/.*@(.*)/$1/;
400         my $c = NDIRC::IrcContext->new({
401                         host => $address,
402                         nick => $nick,
403                         channel => $channel,
404                         disp => $self->disp,
405                         model => $model,
406                         server => $server,
407                         reply_string => $reply_string,
408                 });
409
410         return $self->disp->run_command($c,$command,$args);
411 }
412
413 sub toTarget {
414         my ($self, $target, $msg) = @_;
415
416         return unless exists $self->targets->{$target};
417
418         my $session = $poe_kernel->get_active_session();
419         my $heap = $session->get_heap();
420         my $irc = $heap->{irc};
421
422
423         for (@{$self->targets->{$target}}) {
424                 when (/^#/) {
425                         $irc->yield(privmsg => $_, $msg);
426                 }
427                 when (/^d-(\d+)/i) {
428                         $self->discord->send_message($1, $msg );
429                 }
430         }
431 }
432
433 1;