AnyEvent-Discord-Client

 view release on metacpan or  search on metacpan

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

        );
      } 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,
      authorization => "Bot $self->{token}",
      "user-agent" => $self->{api_useragent},
      (
          !defined $data ? ()
        : ref $data ? ("content-type" => "application/json")
        : ("content-type" => "application/x-www-form-urlencoded")
      ),
    },
    (
        !defined $data ? ()
      : ref $data ? (body => encode_json($data))
      : (body => $data)
    ),
    sub {
      my ($body, $hdr) = @_;
      return unless $cb;
      $cb->(!defined $body ? undef : defined $hdr->{"content-type"} && $hdr->{"content-type"} eq 'application/json' ? decode_json($body) : 1, $hdr);
    },
  );
}

1;

__END__

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

=head1 METHODS

=over

=item C<commands()>

Returns a hashref of the currently registered commands.

=item C<user()>

Returns a hashref representing a L<Discord User object|https://discordapp.com/developers/docs/resources/user> for the currently logged-in user.

=item C<guilds()>

Returns a hashref of guild IDs to hashrefs representing L<Discord Guild objects|https://discordapp.com/developers/docs/resources/guild> for any Guilds the client has seen.

=item C<channels()>

Returns a hashref of channel IDs to hashrefs representing L<Discord Channel objects|https://discordapp.com/developers/docs/resources/channel> for any Channels the client has seen.

=item C<roles()>

Returns a hashref of role IDs to hashrefs representing L<Discord Role objects|https://discordapp.com/developers/docs/topics/permissions#role-object> for any Roles the client has seen.

=item C<connect()>

Causes the client to connect to Discord.  Will automatically attempt to reconnect if disconnected.  Returns nothing and immediately; to wait forever and prevent the program from exiting, follow this call with:

    AnyEvent->condvar->recv;

=item C<say(I<$channel_id>, I<$message>)>

Sends the given C<$message> text to the given C<$channel_id>.

=item C<typing(I<$channel>)>

Displays a typing indicator in the given channel.  Discord automatically removes the indicator after a few seconds; to keep it longer, this method returns an L<AnyEvent watcher|https://metacpan.org/pod/AnyEvent#WATCHERS> that you can keep in scope un...

    my $typing_watcher = $bot->typing($channel);
    
    # Now, do a potentially very slow operation, like calling an API.
    
    # Once the API responds, even asynchronously, disable the watcher:
    undef $typing_watcher;

=item C<add_commands(I<%commands>)>

Installs new commands - chat messages that begin with the C<prefix> given during construction and any key from the given hash.  When seen as a chat message, the corresponding subref of the registered command will be invoked.  The subref is passed a r...

    $bot->add_commands(
      # register "!hello" command
      'hello' => sub {
        my ($bot, $args, $msg, $channel, $guild) = @_;
    
        $bot->say($channel->{id}, "hi, $msg->{author}{username}!");
      },
    );

=item C<api(I<$method>, I<$path>, I<$data>, I<$cb>)>

Invokes the Discord API asynchronously and returns immediately.  C<$method> is the HTTP method to use; C<$path> is the endpoint to call.  If C<$data> is a reference, it is sent as JSON; otherwise, if it is defined, it is sent as a C<x-www-form-urlenc...

=item C<api_sync(I<$method>, I<$path>, I<$data>)>

Invokes the Discord API synchronously and returns the result of the call.  C<$method> is the HTTP method to use; C<$path> is the endpoint to call.  If C<$data> is a reference, it is sent as JSON; otherwise, if it is defined, it is sent as a C<x-www-f...

=item C<websocket_send(I<$op>, I<$d>)>

Sends a raw WebSocket payload as per the L<Discord Gateway|https://discordapp.com/developers/docs/topics/gateway> documentation.

=back

=head1 AUTHOR

Eric Wastl, C<< <topaz at cpan.org> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-anyevent-discord-client at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=AnyEvent-Discord-Client>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc AnyEvent::Discord::Client


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=AnyEvent-Discord-Client>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/AnyEvent-Discord-Client>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/AnyEvent-Discord-Client>

=item * Search CPAN

L<http://search.cpan.org/dist/AnyEvent-Discord-Client/>

=back


=head1 ACKNOWLEDGEMENTS


=head1 LICENSE AND COPYRIGHT

Copyright 2019 Eric Wastl.

This program is free software; you can redistribute it and/or modify it
under the terms of the the Artistic License (2.0). You may obtain a
copy of the full license at:



( run in 1.989 second using v1.01-cache-2.11-cpan-5735350b133 )