AnyEvent-Discord

 view release on metacpan or  search on metacpan

lib/AnyEvent/Discord.pm  view on Meta::CPAN

package AnyEvent::Discord;
use v5.14;
use Moops;

class AnyEvent::Discord 0.7 {
  use Algorithm::Backoff::Exponential;
  use AnyEvent::Discord::Payload;
  use AnyEvent::WebSocket::Client;
  use Data::Dumper;
  use JSON qw(decode_json encode_json);
  use LWP::UserAgent;
  use HTTP::Request;
  use HTTP::Headers;

  our $VERSION = '0.7';
  has version => ( is => 'ro', isa => Str, default => $VERSION );

  has token => ( is => 'rw', isa => Str, required => 1 );
  has base_uri => ( is => 'rw', isa => Str, default => 'https://discordapp.com/api' );
  has socket_options => ( is => 'rw', isa => HashRef, default => sub { { max_payload_size => 1024 * 1024 } } );
  has verbose => ( is => 'rw', isa => Num, default => 0 );
  has user_agent => ( is => 'rw', isa => Str, default => sub { 'Perl-AnyEventDiscord/' . shift->VERSION } );

  has guilds => ( is => 'ro', isa => HashRef, default => sub { {} } );
  has channels => ( is => 'ro', isa => HashRef, default => sub { {} } );
  has users => ( is => 'ro', isa => HashRef, default => sub { {} } );

  # UserAgent
  has _ua => ( is => 'rw', default => sub { LWP::UserAgent->new() } );
  # Caller-defined event handlers
  has _events => ( is => 'ro', isa => HashRef, default => sub { {} } );
  # Internal-defined event handlers
  has _internal_events => ( is => 'ro', isa => HashRef, builder => '_build_internal_events' );
  # WebSocket
  has _socket => ( is => 'rw' );
  # Heartbeat timer
  has _heartbeat => ( is => 'rw' );
  # Last Sequence
  has _sequence => ( is => 'rw', isa => Num, default => 0 );
  # True if caller manually disconnected, to avoid reconnection
  has _force_disconnect => ( is => 'rw', isa => Bool, default => 0 );
  # Host the backoff algorithm for reconnection
  has _backoff => ( is => 'ro', default => sub { Algorithm::Backoff::Exponential->new( initial_delay => 1 ) } );

  method _build_internal_events() {
    return {
      'guild_create'        => [sub { $self->_event_guild_create(@_); }],
      'guild_delete'        => [sub { $self->_event_guild_delete(@_); }],
      'channel_create'      => [sub { $self->_event_channel_create(@_); }],
      'channel_delete'      => [sub { $self->_event_channel_delete(@_); }],
      'guild_member_create' => [sub { $self->_event_guild_member_create(@_); }],
      'guild_member_remove' => [sub { $self->_event_guild_member_remove(@_); }]
    };
  }

  method on(Str $event_type, CodeRef $handler) {
    $event_type = lc($event_type);
    $self->_debug('Requesting attach of handler ' . $handler . ' to event ' . $event_type);

    $self->_events->{$event_type} //= [];
    return if (scalar(grep { $_ eq $handler } @{$self->_events->{$event_type}}) > 0);

    $self->_debug('Attaching handler ' . $handler . ' to event ' . $event_type);
    push( @{$self->_events->{$event_type}}, $handler );
  }

  method off(Str $event_type, CodeRef $handler?) {
    $event_type = lc($event_type);
    $self->_debug('Requesting detach of handler ' . ($handler or 'n/a') . ' from event ' . $event_type);
    if ($self->_events->{$event_type}) {
      if ($handler) {
        my $index = 0;
        while ($index < scalar(@{$self->_events->{$event_type}})) {
          if ($self->_events->{$event_type}->[$index] eq $handler) {
            $self->_debug('Detaching handler ' . $handler . ' from event ' . $event_type);
            splice( @{$self->_events->{$event_type}}, $index, 1 );
          }
          $index++;
        }
      } else {
        $self->_debug('Detaching ' . scalar(@{$self->_events->{$event_type}}) . ' handler(s) from event ' . $event_type);
        delete($self->_events->{$event_type});
      }
    }
  }

  method connect() {
    my $gateway = $self->_lookup_gateway();

    $self->_debug('Connecting to ' . $gateway);

    my $ws = AnyEvent::WebSocket::Client->new($self->socket_options);
    $ws->connect($gateway)->cb(sub {



( run in 0.803 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )