# NAME

POEx::IRC::Backend - IRC client or server backend

# SYNOPSIS

   use POE;
   use POEx::IRC::Backend;

   POE::Session->create(
     package_states => [
       main => [ qw/
         _start
         ircsock_registered
         ircsock_input
       / ],
     ],
   );

   sub _start {
     # Spawn a Backend and register as the controlling session:
     my $backend = POEx::IRC::Backend->spawn;
     $_[HEAP]->{backend} = $backend;
     $_[KERNEL]->post( $backend->session_id, 'register' );
   }

   sub ircsock_registered {
     my $backend = $_[HEAP]->{backend};

     # Listen for incoming IRC traffic:
     $backend->create_listener(
       bindaddr => $addr,
       port     => $port,
     );

     # Connect to a remote endpoint:
     $backend->create_connector(
       remoteaddr => $remote,
       remoteport => $remoteport,
       # Optional:
       bindaddr => $bindaddr,
       ipv6     => 1,
       ssl      => 1,
     );
   }

   # Handle and dispatch incoming IRC events:
   sub ircsock_input {
     # POEx::IRC::Backend::Connect obj:
     my $this_conn = $_[ARG0];

     # IRC::Message::Object obj:
     my $input_obj = $_[ARG1];

     my $cmd = $input_obj->command;

     # ... dispatch, etc ...
   }

# DESCRIPTION

A [POE](https://metacpan.org/pod/POE) IRC socket handler that can be used (by client or server
implementations) to speak the IRC protocol to endpoints via
[IRC::Message::Object](https://metacpan.org/pod/IRC::Message::Object) objects.

Inspired by [POE::Component::Server::IRC::Backend](https://metacpan.org/pod/POE::Component::Server::IRC::Backend) & [POE::Component::IRC](https://metacpan.org/pod/POE::Component::IRC).

This is a very low-level interface to IRC sockets; the goal is to provide all
the necessary scaffolding to develop stateless or stateful IRC clients and
daemons. See [POEx::IRC::Client::Lite](https://metacpan.org/pod/POEx::IRC::Client::Lite) for an experimental IRC client library
using this backend (and the ["SEE ALSO"](#see-also) section of this documentation for
related tools).

## Attributes

### controller

Retrieve the [POE::Session](https://metacpan.org/pod/POE::Session) ID for the backend's registered controller.

Predicate: **has\_controller**

### connectors

A HASH of active Connector objects, keyed on their wheel ID.

### filter

A [POE::Filter::Stackable](https://metacpan.org/pod/POE::Filter::Stackable) instance consisting of the current ["filter\_irc"](#filter_irc)
stacked with ["filter\_line"](#filter_line) (at the time the attribute is built).

### filter\_irc

A [POE::Filter::IRCv3](https://metacpan.org/pod/POE::Filter::IRCv3) instance with **colonify** disabled, by default (this
behavior changed in v0.27.2).

A server-side Backend may want a colonifying filter:

   my $backend = POEx::IRC::Backend->new(
     filter_irc => POE::Filter::IRCv3->new(colonify => 1),
     ...
   );

### filter\_line

A [POE::Filter::Line](https://metacpan.org/pod/POE::Filter::Line) instance.

### listeners

HASH of active Listener objects, keyed on their wheel ID.

### session\_id

Returns the backend's session ID.

### ssl\_context

Returns the [Net::SSLeay](https://metacpan.org/pod/Net::SSLeay) Context object, if we have one (or `undef` if
not); the context is set up by ["spawn"](#spawn) if `ssl_opts` are specified.

### wheels

HASH of actively connected wheels, keyed on their wheel ID.

## Methods

### spawn

   my $backend = POEx::IRC::Backend->spawn(
     ## Optional, needed for SSL-ified server-side sockets
     ssl_opts => [
       'server.key',
       'server.cert',
     ],
   );

Creates the backend's [POE::Session](https://metacpan.org/pod/POE::Session).

The `ssl_opts` ARRAY is passed directly to
["SSLify\_ContextCreate" in POE::Component::SSLify](https://metacpan.org/pod/POE::Component::SSLify#SSLify_ContextCreate), if present. As of `v0.28.x`,
each Backend gets its own [Net::SSLeay](https://metacpan.org/pod/Net::SSLeay) context object (rather than sharing
the global context). See [POE::Component::SSLify](https://metacpan.org/pod/POE::Component::SSLify) & [Net::SSLeay](https://metacpan.org/pod/Net::SSLeay).

### create\_connector

   $backend->create_connector(
     remoteaddr => $addr,
     remoteport => $addr,
     ## Optional:
     bindaddr => $local_addr,
     ipv6 => 1,
     ssl  => 1,
     ## Unrecognized opts are stored in the Connector's 'args' hash:
     tag   => 'foo',
   );

Attempts to create a [POEx::IRC::Backend::Connector](https://metacpan.org/pod/POEx::IRC::Backend::Connector) that
holds a [POE::Wheel::SocketFactory](https://metacpan.org/pod/POE::Wheel::SocketFactory) connector wheel; connectors will
attempt to establish an outgoing connection immediately.

Unrecognized options are stored in the [POEx::IRC::Backend::Connector](https://metacpan.org/pod/POEx::IRC::Backend::Connector)'s
`args` HASH-type attribute; this is passed to successfully created
[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect) instances (as of `v0.26.x`). Note that the
reference is shared, not copied.

### create\_listener

   $backend->create_listener(
     bindaddr => $addr,
     port     => $port,
     ## Optional:
     ipv6     => 1,
     ssl      => 1,
     idle     => $seconds,
   );

Attempts to create a [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener)
that holds a [POE::Wheel::SocketFactory](https://metacpan.org/pod/POE::Wheel::SocketFactory) listener wheel.

Unrecognized arguments will be added to the Listener object's `args`
attribute, which is then passed on to [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect) objects
created by incoming connections to that listener, similar to the behavior
described in ["create\_connector"](#create_connector) (as of `v0.28.x`).

### remove\_listener

   $backend->remove_listener(
     listener => $listener_id,
   );

   ## or via addr, port, or combination thereof:
   $backend->remove_listener(
     addr => '127.0.0.1',
     port => 6667,
   );

Removes a listener and clears its **wheel** attribute; the socket shuts down
when the [POE::Wheel::SocketFactory](https://metacpan.org/pod/POE::Wheel::SocketFactory) wheel goes out of scope.

### disconnect

   $backend->disconnect($wheel_id, $disconnect_string);

Given a [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect) or its `wheel_id`, mark the specified
wheel for disconnection.

This method will warn if the given `wheel_id` cannot be found, which may be
due to the connection disappearing prior to calling `disconnect`.

You can avoid spurious warnings by checking if the
[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect) still has an active wheel attached:

   if ($this_conn->has_wheel) {
     $backend->disconnect( $this_conn )
   }

Note that disconnection typically happens after a buffer flush; if your
software does not perform entirely like a traditional platform (server
implementations will typically send `ERROR: Closing Link` or similar to
clients marked for disconnection, which will trigger a buffer flush) you may
currently experience "late" disconnects. See ["disconnect\_now"](#disconnect_now).

### disconnect\_now

Like ["disconnect"](#disconnect), but attempt to destroy the wheel immediately (without
waiting for a buffer flush).

### send

   $backend->send(
     {
       prefix  => $prefix,
       params  => [ @params ],
       command => $cmd,
     },
     @connect_ids
   );

   use IRC::Message::Object 'ircmsg';
   my $msg = ircmsg(
     command => 'PRIVMSG',
     params  => [ $chan, $string ],
   );
   $backend->send( $msg, $connect_obj );

Feeds [POE::Filter::IRCv3](https://metacpan.org/pod/POE::Filter::IRCv3) and sends the resultant raw IRC
line to the specified connection wheel ID(s) or [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)
object(s).

Accepts either an [IRC::Message::Object](https://metacpan.org/pod/IRC::Message::Object) or a HASH compatible with
[POE::Filter::IRCv3](https://metacpan.org/pod/POE::Filter::IRCv3) -- look there for details.

Note that unroutable (target connection IDs with no matching live
wheel) messages are silently dropped. You can check ["wheels"](#wheels) yourself before
sending if this behavior is unwanted:

   for my $target (@connect_ids) {
     unless (exists $backend->wheels->{$target}) {
       warn "Cannot send to nonexistant target '$target'";
       next
     }
     $backend->send(
         { prefix => $prefix, params => [ @params ], command => $cmd },
         $target
     );
   }

### has\_ssl\_support

Returns true if [POE::Component::SSLify](https://metacpan.org/pod/POE::Component::SSLify) was successfully loaded.

### has\_zlib\_support

Returns true if [POE::Filter::Zlib::Stream](https://metacpan.org/pod/POE::Filter::Zlib::Stream) was successfully loaded.

### set\_compressed\_link

   $backend->set_compressed_link( $conn_id );

Mark a specified connection wheel ID as pending compression;
[POE::Filter::Zlib::Stream](https://metacpan.org/pod/POE::Filter::Zlib::Stream) will be added to the filter stack when the
next flush event arrives.

This method will die unless ["has\_zlib\_support"](#has_zlib_support) is true.

### set\_compressed\_link\_now

   $backend->set_compressed_link_now( $conn_id );

Add a [POE::Filter::Zlib::Stream](https://metacpan.org/pod/POE::Filter::Zlib::Stream) to the connection's filter stack
immediately, rather than upon next flush event.

This method will die unless ["has\_zlib\_support"](#has_zlib_support) is true.

### unset\_compressed\_link

   $backend->unset_compressed_link( $conn_id );

Remove [POE::Filter::Zlib::Stream](https://metacpan.org/pod/POE::Filter::Zlib::Stream) from the connection's filter stack.

## Received events

### register

   $poe_kernel->post( $backend->session_id,
     'register'
   );

Register the sender session as the backend's controller session. The last
session to send 'register' is the session that receives notification
events from the backend component.

### create\_connector

Event interface to _create\_connector_ -- see ["Methods"](#methods)

### create\_listener

Event interface to _create\_listener_ -- see ["Methods"](#methods)

### remove\_listener

Event interface to _remove\_listener_ -- see ["Methods"](#methods)

### send

Event interface to _/send_ -- see ["Methods"](#methods)

### shutdown

Disconnect all wheels and clean up.

## Dispatched events

These events are dispatched to the controller session; see ["register"](#register).

### ircsock\_compressed

Dispatched when a connection wheel has had a compression filter added.

`$_[ARG0]` is the connection's
[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)

### ircsock\_connection\_idle

Dispatched when a connection wheel has had no input for longer than
specified idle time (see ["create\_listener"](#create_listener) regarding idle times).

Currently these events are only issued for incoming Connects accepted on a
Listener, not outgoing Connects created by a Connector.

`$_[ARG0]` is the connection's
[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)

See also: ["ping\_pending" in POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect#ping_pending)

### ircsock\_connector\_failure

Dispatched when a Connector has failed due to some sort of socket error.

`$_[ARG0]` is the connection's
[POEx::IRC::Backend::Connector](https://metacpan.org/pod/POEx::IRC::Backend::Connector) with wheel() cleared.

`@_[ARG1 .. ARG3]` contain the socket error details reported by
[POE::Wheel::SocketFactory](https://metacpan.org/pod/POE::Wheel::SocketFactory); operation, errno, and errstr, respectively.

### ircsock\_connector\_open

Dispatched when a Connector has established a connection to a peer.

`$_[ARG0]` is the [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect) for the
connection.

### ircsock\_disconnect

Dispatched when a connection wheel has been cleared.

`$_[ARG0]` is the connection's [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)
with wheel() cleared.

### ircsock\_input

Dispatched when there is some IRC input from a connection wheel.

`$_[ARG0]` is the connection's
[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect).

`$_[ARG1]` is an [IRC::Message::Object](https://metacpan.org/pod/IRC::Message::Object).

### ircsock\_listener\_created

Dispatched when a [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener) has been
created.

`$_[ARG0]` is the [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener) instance;
the instance's port() is altered based on getsockname() details after
socket creation and before dispatching this event.

### ircsock\_listener\_failure

Dispatched when a Listener has failed due to some sort of socket error.

`$_[ARG0]` is the [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener) object.

`@_[ARG1 .. ARG3]` contain the socket error details reported by
[POE::Wheel::SocketFactory](https://metacpan.org/pod/POE::Wheel::SocketFactory); operation, errno, and errstr, respectively.

### ircsock\_listener\_open

Dispatched when a listener accepts a connection.

`$_[ARG0]` is the connection's [POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)

`$_[ARG1]` is the connection's [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener)

### ircsock\_listener\_removed

Dispatched when a Listener has been removed.

`$_[ARG0]` is the [POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener) object.

### ircsock\_registered

Dispatched when a ["register"](#register) event has been successfully received, as a
means of acknowledging the controlling session.

`$_[ARG0]` is the Backend's `$self` object.

# BUGS

Probably lots. Please report them via RT, e-mail, IRC
(`irc.cobaltirc.org#perl`), or GitHub
([http://github.com/avenj/poex-irc-backend](http://github.com/avenj/poex-irc-backend)).

# SEE ALSO

[POEx::IRC::Backend::Connect](https://metacpan.org/pod/POEx::IRC::Backend::Connect)

[POEx::IRC::Backend::Connector](https://metacpan.org/pod/POEx::IRC::Backend::Connector)

[POEx::IRC::Backend::Listener](https://metacpan.org/pod/POEx::IRC::Backend::Listener)

[POEx::IRC::Backend::Role::Socket](https://metacpan.org/pod/POEx::IRC::Backend::Role::Socket)

[POEx::IRC::Backend::Role::HasEndpoint](https://metacpan.org/pod/POEx::IRC::Backend::Role::HasEndpoint)

[POEx::IRC::Backend::Role::HasWheel](https://metacpan.org/pod/POEx::IRC::Backend::Role::HasWheel)

[POEx::IRC::Client::Lite](https://metacpan.org/pod/POEx::IRC::Client::Lite) for an experimental IRC client library using this
backend.

[https://github.com/miniCruzer/irssi-bouncer](https://github.com/miniCruzer/irssi-bouncer) for an irssi-based
bouncer/proxy system using this backend.

[POE::Filter::IRCv3](https://metacpan.org/pod/POE::Filter::IRCv3) and [IRC::Message::Object](https://metacpan.org/pod/IRC::Message::Object) for documentation regarding
IRC message parsing.

[IRC::Toolkit](https://metacpan.org/pod/IRC::Toolkit) for an extensive set of IRC-related utilities.

[POE::Component::IRC](https://metacpan.org/pod/POE::Component::IRC) if you're looking for a mature, fully-featured IRC
client library.

# AUTHOR

Jon Portnoy <[email protected]>

Inspiration derived from [POE::Component::Server::IRC::Backend](https://metacpan.org/pod/POE::Component::Server::IRC::Backend) and
[POE::Component::IRC](https://metacpan.org/pod/POE::Component::IRC) by BINGOS, HINRIK et al.