AnyEvent-Discord-Client
view release on metacpan or search on metacpan
lib/AnyEvent/Discord/Client.pm view on Meta::CPAN
package AnyEvent::Discord::Client;
use warnings;
use strict;
our $VERSION = '0.000002';
$VERSION = eval $VERSION;
use AnyEvent::WebSocket::Client;
use LWP::UserAgent;
use JSON;
use URI;
use HTTP::Request;
use HTTP::Headers;
use AnyEvent::HTTP;
my $debug = 0;
sub new {
my ($class, %args) = @_;
my $self = {
token => delete($args{token}),
api_root => delete($args{api_root}) // 'https://discordapp.com/api',
prefix => delete($args{prefix}) // "!",
commands => delete($args{commands}) // {},
ua => LWP::UserAgent->new(),
api_useragent => "DiscordBot (https://github.com/topaz/perl-AnyEvent-Discord-Client, 0)",
user => undef,
guilds => {},
channels => {},
roles => {},
gateway => undef,
conn => undef,
websocket => undef,
heartbeat_timer => undef,
last_seq => undef,
reconnect_delay => 1,
};
die "cannot construct new $class without a token parameter" unless defined $self->{token};
die "unrecognized extra parameters were given to $class->new" if %args;
return bless $self, $class;
}
sub commands { $_[0]{commands} }
sub user { $_[0]{user} }
sub guilds { $_[0]{guilds} }
sub channels { $_[0]{channels} }
sub roles { $_[0]{roles} }
my %event_handler = (
READY => sub {
my ($self, $d) = @_;
$self->{user} = $d->{user};
print "logged in as $self->{user}{username}.\n";
print "ready!\n";
},
GUILD_CREATE => sub {
my ($self, $d) = @_;
$self->{guilds}{$d->{id}} = $d;
$self->{channels}{$_->{id}} = {%$_, guild_id=>$d->{id}} for @{$d->{channels}};
$self->{roles}{$_->{id}} = {%$_, guild_id=>$d->{id}} for @{$d->{roles}};
print "created guild $d->{id} ($d->{name})\n";
},
CHANNEL_CREATE => sub {
my ($self, $d) = @_;
$self->{channels}{$d->{id}} = $d;
push @{$self->{guilds}{$d->{guild_id}}{channels}}, $d if $d->{guild_id};
lib/AnyEvent/Discord/Client.pm view on Meta::CPAN
'$referring_domain' => ""
},
compress => JSON::false,
large_threshold => 250,
shard => [0, 1],
});
$self->{conn}->on(each_message => sub {
my($connection, $message) = @_;
my $msg = decode_json($message->{body});
die "invalid message" unless ref $msg eq 'HASH' && defined $msg->{op};
$self->{last_seq} = 0+$msg->{s} if defined $msg->{s};
if ($msg->{op} == 0) { #dispatch
print "\e[1;30mdispatch event $msg->{t}:".Dumper($msg->{d})."\e[0m\n" if $debug;
$event_handler{$msg->{t}}($self, $msg->{d}) if $event_handler{$msg->{t}};
} elsif ($msg->{op} == 10) { #hello
$self->{heartbeat_timer} = AnyEvent->timer(
after => $msg->{d}{heartbeat_interval}/1e3,
interval => $msg->{d}{heartbeat_interval}/1e3,
cb => sub {
$self->websocket_send(1, $self->{last_seq});
},
);
} elsif ($msg->{op} == 11) { #heartbeat ack
# ignore for now; eventually, notice missing ack and reconnect
} else {
print "\e[1;30mnon-event message op=$msg->{op}:".Dumper($msg)."\e[0m\n" if $debug;
}
});
$self->{conn}->on(parse_error => sub {
my ($connection, $error) = @_;
print "parse_error: $error\n";
exit;
});
$self->{conn}->on(finish => sub {
my($connection) = @_;
print "Disconnected! Reconnecting in five seconds...\n";
my $reconnect_timer; $reconnect_timer = AnyEvent->timer(
after => $self->{reconnect_delay},
cb => sub {
$self->connect();
$reconnect_timer = undef;
},
);
});
});
}
sub add_commands {
my ($self, %commands) = @_;
$self->{commands}{$_} = $commands{$_} for keys %commands;
}
sub api_sync {
my ($self, $method, $path, $data) = @_;
my $resp = $self->{ua}->request(HTTP::Request->new(
uc($method),
$self->{api_root} . $path,
HTTP::Headers->new(
Authorization => "Bot $self->{token}",
User_Agent => $self->{api_useragent},
($data ? (Content_Type => "application/json") : ()),
(
!defined $data ? ()
: ref $data ? ("Content_Type" => "application/json")
: ("Content_Type" => "application/x-www-form-urlencoded")
),
),
(
!defined $data ? undef
: ref $data ? encode_json($data)
: $data
),
));
if (!$resp->is_success) {
return undef;
}
if ($resp->header("Content-Type") eq 'application/json') {
return JSON::decode_json($resp->decoded_content);
} else {
return 1;
}
}
sub websocket_send {
my ($self, $op, $d) = @_;
die "no connection!" unless $self->{conn};
$self->{conn}->send(encode_json({op=>$op, d=>$d}));
}
sub say {
my ($self, $channel_id, $message) = @_;
$self->api(POST => "/channels/$channel_id/messages", {content => $message});
}
sub typing {
my ($self, $channel) = @_;
return AnyEvent->timer(
after => 0,
interval => 5,
cb => sub {
$self->api(POST => "/channels/$channel->{id}/typing", '');
},
);
}
sub api {
my ($self, $method, $path, $data, $cb) = @_;
http_request(
uc($method) => $self->{api_root} . $path,
timeout => 5,
recurse => 0,
headers => {
referer => undef,
( run in 2.046 seconds using v1.01-cache-2.11-cpan-8f98c5d2c55 )