.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Net::Async::IRC::Introduction 3pm" .TH Net::Async::IRC::Introduction 3pm "2018-07-02" "perl v5.26.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Net::Async::IRC::Introduction \- an introduction .SH "INTRODUCTION" .IX Header "INTRODUCTION" .SS "Hello, World" .IX Subsection "Hello, World" This first example is the \*(L"hello world\*(R" of \s-1IRC\s0; a script that connects to the server and immediately sends a hello message to a preconfigured user. .PP This program starts with the usual boilerplate for any IO::Async\-based program; namely loading the required modules and creating a containing IO::Async::Loop instance. It then constructs the actual Net::Async::IRC object and adds it to this containing loop. As these actions are standard to every program, they won't be repeated in later examples; just presumed to have already taken place: .PP .Vb 2 \& use strict; \& use warnings; \& \& use IO::Async::Loop; \& use Net::Async::IRC; \& \& my $loop = IO::Async::Loop\->new; \& \& my $irc = Net::Async::IRC\->new; \& $loop\->add( $irc ); .Ve .PP Now this is created, we can move on to the specifics of this example. As it's a tiny example script, we'll just hard-code the parameters for the message. A larger program of course would read these from somewhere better \- a config file, commandline arguments, etc... .PP .Vb 3 \& my $SERVER = "irc.example.net"; \& my $NICK = "MyNick"; \& my $TARGET = "TargetNick"; .Ve .PP Finally we can connect to the \s-1IRC\s0 server and send the message: .PP .Vb 9 \& $irc\->login( \& host => $SERVER, \& nick => $NICK, \& )\->then( sub { \& $irc\->do_PRIVMSG( \& target => $TARGET, \& text => "Hello, World" \& ); \& })\->get; .Ve .PP The program calls \*(L"login\*(R" in Net::Async::IRC, which connects the client to the given \s-1IRC\s0 server and logs in as the given nick. This method returns a Future instance to represent its eventual completion, giving us an easy way to sequence further code after it. After login is complete, the next task is simply to send the message. This is done with the \f(CW\*(C`PRIVMSG\*(C'\fR \s-1IRC\s0 command as wrapped by \*(L"do_PRIVMSG\*(R" in Net::Async::IRC. This takes taking the message target name and text string. .PP The trailing call to \*(L"get\*(R" in Future makes the script stop here waiting for this chain of futures to actually complete. Without this, the returned future would simply be lost (as the \*(L"then\*(R" in Future method appears in void context), and the second stage of code within it would probably never get called. In later examples we'll see other techniques, but for now every constructed future will simply be forced by calling \f(CW\*(C`get\*(C'\fR on it. If either of these stages fails, it will cause the \f(CW\*(C`get\*(C'\fR call to throw an exception instead. .PP Once this is sent, the script terminates, closing its connection to the server. .SS "\s-1RECEIVING MESSAGES\s0" .IX Subsection "RECEIVING MESSAGES" As a second example, lets now consider also how we handle messages that arrive from \s-1IRC.\s0 .PP .Vb 5 \& $irc\->configure( \& on_message_PRIVMSG => sub { \& my ( $irc, $message, $hints ) = @_; \& return unless $hints\->{prefix_nick_folded} eq \& $irc\->casefold_name( $TARGET ); \& \& print "The user said: $hints\->{text}\en"; \& } \& ); \& \& $irc\->login( \& host => $SERVER, \& nick => $NICK, \& )\->then( sub { \& $irc\->do_PRIVMSG( \& target => $TARGET, \& text => "Hello, what\*(Aqs your name?" \& ); \& })\->get; \& \& $loop\->run; .Ve .PP Here we have used the \f(CW\*(C`configure\*(C'\fR method to attach an event handler to the \&\f(CW\*(C`on_message_PRIVMSG\*(C'\fR event. This handler code ignores any messages except from the user we are interested in, and simply prints the contents of those we are interested in to the terminal. .PP Having established this event handler, we can then log in and send a message to the target user, similar to the first example. Instead of stopping the script entirely afterwards, we need to ensure that the program keeps running after this initial start so it can continue to receive messages. To do that we enter the main \*(L"run\*(R" in IO::Async::Loop method, which will wait indefinitely, processing any events that are received. .SS "Case-folded Names" .IX Subsection "Case-folded Names" The use of the \*(L"folded\*(R" strings ensures that this code can correctly cope with any odd case-folding rules the \s-1IRC\s0 server has. By comparison, both of the following lines are incorrect, and may cause missed messages on some servers: .PP .Vb 1 \& return unless $hints\->{prefix_name} eq $TARGET; # don\*(Aqt do this \& \& return unless lc $hints\->{prefix_name} eq lc $TARGET; # don\*(Aqt do this .Ve .PP The first does not case-fold the string at all, so will fail in the case of \&\f(CW\*(C`User\*(C'\fR vs \f(CW\*(C`user\*(C'\fR. The second attempts to solve this, but does not take account of the odd case-folding logic most \s-1IRC\s0 servers have, in which the characters \f(CW\*(C`[\e]\*(C'\fR are \*(L"uppercase\*(R" versions of \f(CW\*(C`{|}\*(C'\fR. The \&\*(L"casefold_name\*(R" in Protocol::IRC method is provided as a server-aware alternative to \f(CW\*(C`lc()\*(C'\fR, which handles this. A correct implementation could be written: .PP .Vb 2 \& return unless $irc\->casefold_name( $hints\->{prefix_name} ) eq \& $irc\->casefold_name( $TARGET ); .Ve .PP However, since this is a very common pattern, the hints hash conveniently supplies already-folded strings for any name or nick fields it finds. Furthermore, as the case folded version of the target name won't change after startup, we could store that initially to save re-calculating it at every event: .PP .Vb 4 \& $irc\->login( \& host => $SERVER, \& nick => $NICK, \& )\->get; \& \& my $target_folded = $irc\->casefold_name( $TARGET ); \& \& $irc\->configure( \& on_message_PRIVMSG => sub { \& my ( undef, $message, $hints ) = @_; \& return unless $hints\->{prefix_nick_folded} eq $target_folded; \& \& print "The user said: $hints\->{text}\en"; \& } \& ); .Ve .ie n .SS """PRIVMSG"" vs ""text"" and CTCPs" .el .SS "\f(CWPRIVMSG\fP vs \f(CWtext\fP and CTCPs" .IX Subsection "PRIVMSG vs text and CTCPs" This example has used the basic \f(CW\*(C`on_message_PRIVMSG\*(C'\fR event. A better version would be to use \f(CW\*(C`on_message_text\*(C'\fR instead. This is a synthesized event created on receipt of either \f(CW\*(C`PRIVMSG\*(C'\fR or \f(CW\*(C`NOTICE\*(C'\fR, and itself handles details like \f(CW\*(C`CTCP\*(C'\fR parsing, freeing the user code from having to handle it). For example, the plain \f(CW\*(C`PRIVMSG\*(C'\fR event will get quite confused by an incoming \&\f(CW\*(C`CTCP ACTION\*(C'\fR, such as is created by most \s-1IRC\s0 clients by the \f(CW\*(C`/me\*(C'\fR command. Instead, we can handle that by attaching a handler specifically for \&\f(CW\*(C`CTCP ACTION\*(C'\fR: .PP .Vb 4 \& $irc\->configure( \& on_message_text => sub { \& my ( undef, $message, $hints ) = @_; \& return unless $hints\->{prefix_nick_folded} eq $target_folded; \& \& print "The user said: $hints\->{text}\en"; \& }, \& on_message_ctcp_ACTION => sub { \& my ( undef, $message, $hints ) = @_; \& return unless $hints\->{prefix_nick_folded} eq $target_folded; \& \& print "The user acted: $hints\->{ctcp_args}\en"; \& }, \& ); .Ve .PP This second handlers is invoked on receipt of a \f(CW\*(C`PRIVMSG\*(C'\fR containing a \&\f(CW\*(C`CTCP ACTION\*(C'\fR. The first is only invoked on receipt of a plain \f(CW\*(C`PRIVMSG\*(C'\fR that doesn't contain a \f(CW\*(C`CTCP\*(C'\fR subcommand. .SH "AUTHOR" .IX Header "AUTHOR" Paul Evans