From 0822847cd53af14ada68762a2f9d152a274a4d9b Mon Sep 17 00:00:00 2001 From: Michael Andreen Date: Mon, 4 Feb 2019 22:07:54 +0100 Subject: [PATCH] Initial Discord support --- Bot.pm | 57 ++++++++++++++- Delling.pm | 36 ++++++++++ DiscordContext.pm | 180 ++++++++++++++++++++++++++++++++++++++++++++++ ndbot.pl | 4 +- 4 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 DiscordContext.pm diff --git a/Bot.pm b/Bot.pm index 5693dd4..89ec47d 100644 --- a/Bot.pm +++ b/Bot.pm @@ -32,6 +32,9 @@ use POE::Component::IRC::Plugin::Connector; use POE::Component::IRC::Plugin::AutoJoin; use POE::Component::IRC::Plugin::NickReclaim; +use Mojo::Discord; +use Mojo::IOLoop; + use NDIRC::Dispatcher; use NDIRC::Context; @@ -43,6 +46,21 @@ has disp => ( lazy_build => 1 ); +has discord => ( + is => 'rw', + isa => 'Object' +); + +has discord_name => ( + is => 'rw', + isa => 'Str' +); + +has discord_id => ( + is => 'rw', + isa => 'Str' +); + # We registered for all events, this will produce some debug info. sub _default { my ($event, $args) = @_[ARG0 .. $#_]; @@ -61,7 +79,7 @@ sub _default { } sub _start { - my ($kernel,$heap,$session) = @_[KERNEL,HEAP,SESSION]; + my ($self,$kernel,$heap,$session) = @_[OBJECT,KERNEL,HEAP,SESSION]; # retrieve our component's object from the heap where we stashed it my $irc = $heap->{irc}; @@ -94,6 +112,28 @@ sub _start { $irc->yield( connect => { server => 'irc.netgamers.org' } ); $kernel->delay( refresh => 60 ); + + if (my $f = new IO::File 'discord'){ + my $user = <$f>; + chomp $user; + my $token = <$f>; + chomp $token; + + $self->discord(Mojo::Discord->new( + 'token' => $token, + 'name' => $user, + 'url' => 'https://nd.ruin.nu', + 'version' => '1.0', + 'callbacks' => { + 'READY' => sub { $self->discord_ready(@_) }, + 'MESSAGE_CREATE' => sub { $self->discord_message_create(@_) }, + 'GUILD_CREATE' => sub { $self->discord_guild_create(@_) }, + }, + 'reconnect' => 1, + 'verbose' => 1, + )); + $self->discord->init(); + } return; } @@ -276,6 +316,21 @@ sub refresh { sub irc_join { } +sub discord_ready { + my $self = shift; + my $hash = shift; + $self->discord_id($hash->{user}{id}); + $self->discord_name($hash->{user}{username}); + + say localtime(time) . " - Connected to Discord. $self->{discord_id}"; +} + +sub discord_message_create { +} + +sub discord_guild_create { +} + sub parseCommand { my ($self, $msg, $server, $nick, $address, $channel, $model) = @_; diff --git a/Delling.pm b/Delling.pm index bf9bb9d..eb9c929 100644 --- a/Delling.pm +++ b/Delling.pm @@ -28,6 +28,8 @@ extends 'NDIRC::Bot'; use POE::Session; use ND::DB; +use NDIRC::DiscordContext; + my ($tick,$stattick) = (0,0); my $last_announcement = 0; @@ -216,4 +218,38 @@ after _start => sub { ($tick,$stattick) = DB()->selectrow_array(q{SELECT tick(),max(tick) FROM planet_stats}); }; +after discord_message_create => sub { + my $self = shift; + my $hash = shift; + + my $author = $hash->{author}; + my $msg = $hash->{content}; + my $channel_id = $hash->{channel_id}; + my $author_name = $author->{username}; + my $author_id = $author->{id}; + say localtime(time) . "$channel_id $author_name $author_id"; + return if $author->{'id'} eq $self->discord_id; # Ignore my own messages + + my $channel = "#testarlite"; + + my ($p,$command,$args) = ($msg =~ /^([.!~])(\S+)(?: (.+))?/); + + say localtime(time) . " - $msg"; + + return 0 unless $self->disp->has_command($command,$channel); + + + my $c = NDIRC::DiscordContext->new({ + discord_id => $author_id, + channel_id => $channel_id, + channel => $channel, + disp => $self->disp, + model => DB(), + discord => $self->discord, + }); + + return $self->disp->run_command($c,$command,$args); + +}; + 1; diff --git a/DiscordContext.pm b/DiscordContext.pm new file mode 100644 index 0000000..8894565 --- /dev/null +++ b/DiscordContext.pm @@ -0,0 +1,180 @@ +#************************************************************************** +# Copyright (C) 2009 by Michael Andreen * +# * +# This program is free software; you can redistribute it and/or modify * +# it under the terms of the GNU General Public License as published by * +# the Free Software Foundation; either version 2 of the License, or * +# (at your option) any later version. * +# * +# This program is distributed in the hope that it will be useful, * +# but WITHOUT ANY WARRANTY; without even the implied warranty of * +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# GNU General Public License for more details. * +# * +# You should have received a copy of the GNU General Public License * +# along with this program; if not, write to the * +# Free Software Foundation, Inc., * +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * +#**************************************************************************/ + +package NDIRC::DiscordContext; +use strict; +use warnings; +use feature ':5.10'; + +use Moose; + +use Set::Object (); + +has discord_id => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has channel_id => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has channel => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has roles => ( + is => 'ro', + isa => 'Object', + lazy_build => 1 +); + +has uid => ( + is => 'ro', + isa => 'Int', + lazy_build => 1 +); + +has disp => ( + is => 'ro', + isa => 'Object', + required => 1 +); + +has model => ( + is => 'ro', + isa => 'Object', + required => 1 +); + +has discord => ( + is => 'ro', + isa => 'Object', + required => 1 +); + +sub assert_user_roles { + my ($self,@roles) = @_; + return 1 unless @roles; + + my $need = Set::Object->new(@roles); + + if ($self->roles->superset($need)){ + return 1; + } + + die "Access denied"; +} + +sub check_user_roles { + my ($self,@roles) = @_; + + local $@; + eval { $self->assert_user_roles(@roles) }; +} + +sub reply { + my ($self,$msg) = @_; + + $self->message($self->channel_id, $msg); +} + +sub message { + my ($self, $target, $msg) = @_; + + $msg =~ s`(.*?)`**$1**`gi; + $msg =~ s`(.*?)`*$2*`gi; + + $self->discord->send_message($target, $msg ); # Send the response. +} + +sub command { + my ($self,@command) = @_; + +} + +sub intel_log { + my ($c,$planet, $message) = @_; + my $log = $c->model->prepare_cached(q{ +INSERT INTO forum_posts (ftid,uid,message) VALUES( + (SELECT ftid FROM planets WHERE pid = $3),$1,$2) + }); + $log->execute($c->uid,$message,$planet); +} + +sub def_log { + my ($c,$call, $message) = @_; + my $log = $c->model->prepare(q{ +INSERT INTO forum_posts (ftid,uid,message) VALUES( + (SELECT ftid FROM calls WHERE call = $3),$1,$2) + }); + $log->execute($c->uid,$message,$call); +} + +sub _build_roles { + my ($self) = @_; + + my $query = $self->model->prepare(q{ +SELECT role FROM group_roles +WHERE gid IN (SELECT gid FROM groupmembers JOIN users USING (uid) + WHERE hostmask = $1) + }); + $query->execute($self->host); + + my @roles; + while (my $group = $query->fetchrow_hashref){ + push @roles,$group->{role}; + } + return Set::Object->new(@roles); +} + +sub _build_uid { + my ($self) = @_; + + my $query = $self->model->prepare(q{ +SELECT uid FROM users +WHERE discord_id = $1 + }); + $query->execute($self->discord_id); + + if (my ($uid) = $query->fetchrow_array){ + $query->finish; + return $uid; + } + return -4; +} + +sub valuecolor { + shift @_; + my $s = $_; + $s = $_[1] if $#_ >= 1; + $s = "" unless defined $s; + return "~~$s~~" if $s eq 'Hostile'; + return "***$s***" if $s eq 'Friendly'; + return "*$s*" if $s eq 'Nap' or $s eq 'NAP'; + return "$s" if $_[0] && $s; + return $s; +} + +1; diff --git a/ndbot.pl b/ndbot.pl index 54e2fcc..afc8722 100755 --- a/ndbot.pl +++ b/ndbot.pl @@ -29,7 +29,7 @@ use lib dirname (__FILE__) . "/.."; #use Devel::Leak::Object qw{ GLOBAL_bless }; -use POE qw(Component::IRC::Qnet::State); +use POE qw(Component::IRC::Qnet::State Loop::Mojo_IOLoop); use Moose; use MooseX::Declare; @@ -64,3 +64,5 @@ POE::Session->create( ); $poe_kernel->run(); + +1; -- 2.39.2