NAME
Net::Curl::Promiser - A Promise interface for Net::Curl::Multi
DESCRIPTION
This module wraps Net::Curl::Multi to facilitate asynchronous requests with Promise objects. Net::Curl::Promiser interfaces with Net::Curl::Multi’s polling callbacks to simplify your task of coordinating multiple concurrent requests.
Net::Curl::Promiser itself is a base class; you’ll need to provide an interface to whatever event loop you use. See "SUBCLASS INTERFACE" below.
This distribution provides the following as both demonstrations and portable implementations:
Net::Curl::Promiser::Select (for manually-written
select()
loops)
(See the distribution’s /examples directory for one based on Linux’s epoll
.)
PROMISE IMPLEMENTATION
This class’s default Promise implementation is Promise::ES6. You can use a different one by overriding the PROMISE_CLASS()
method in a subclass, as long as the substitute class’s new()
method works the same way as Promise::ES6’s (which itself follows the ECMAScript standard).
(NB: Net::Curl::Promiser::Mojo uses Mojo::Promise instead of Promise::ES6.)
Experimental Promise::XS support
Try out experimental Promise::XS support by running with NET_CURL_PROMISER_PROMISE_ENGINE=Promise::XS
in your environment. This will override PROMISE_CLASS()
.
GENERAL-USE METHODS
The following are of interest to any code that uses this module:
CLASS->new(@ARGS)
Instantiates this class. This creates an underlying Net::Curl::Multi object and calls the subclass’s _INIT()
method at the end, passing a reference to @ARGS.
(Most end classes of this module do not require @ARGS.)
promise($EASY) = OBJ->add_handle( $EASY )
A passthrough to the underlying Net::Curl::Multi object’s method of the same name, but the return is given as a Promise object.
That promise resolves with the passed-in $EASY object. It rejects with either the error given to fail_handle()
or the error that Net::Curl::Multi object’s info_read()
returns.
IMPORTANT: As with libcurl itself, HTTP-level failures (e.g., 4xx and 5xx responses) are NOT considered failures at this level.
$obj = OBJ->fail_handle( $EASY, $REASON )
Prematurely fails $EASY. The given $REASON will be the associated Promise object’s rejection value.
$obj = OBJ->setopt( … )
A passthrough to the underlying Net::Curl::Multi object’s method of the same name. Returns OBJ to facilitate chaining.
CURLMOPT_SOCKETFUNCTION
or CURLMOPT_SOCKETDATA
are set internally; any attempt to set them via this interface will prompt an error.
$obj = OBJ->handles( … )
A passthrough to the underlying Net::Curl::Multi object’s method of the same name.
EVENT LOOP METHODS
The following are needed only when you’re managing an event loop directly:
$num = OBJ->get_timeout()
Returns the underlying Net::Curl::Multi object’s timeout()
value, with a suitable (positive) default substituted if that value is less than 0.
(NB: This value is in milliseconds.)
This may not suit your needs; if you wish/need, you can handle timeouts via the CURLMOPT_TIMERFUNCTION callback instead.
This should only be called (if it’s called at all) from event loop logic.
$obj = OBJ->process( @ARGS )
Tell the underlying Net::Curl::Multi object which socket events have happened.
If, in fact, no events have happened, then this calls socket_action(CURL_SOCKET_TIMEOUT)
on the Net::Curl::Multi object (similar to time_out()
).
Finally, this reaps whatever pending HTTP responses may be ready and resolves or rejects the corresponding Promise objects.
This should only be called from event loop logic.
Returns OBJ.
$is_active = OBJ->time_out();
Tell the underlying Net::Curl::Multi object that a timeout happened, and reap whatever pending HTTP responses may be ready.
Calls socket_action(CURL_SOCKET_TIMEOUT)
on the underlying Net::Curl::Multi object. The return is the same as that operation returns.
Since process()
can also do the work of this function, a call to this function is just an optimization.
This should only be called from event loop logic.
SUBCLASS INTERFACE
NOTE: The distribution provides several ready-built end classes; unless you’re managing your own event loop, you don’t need to concern yourself with this.
To use Net::Curl::Promiser, you’ll need a subclass that defines the following methods:
_INIT(\@ARGS)
: Called at the end ofnew()
. Receives a reference to the arguments given tonew()
._SET_POLL_IN($FD)
: Tells the event loop that the given file descriptor is ready to read._SET_POLL_OUT($FD)
: Like_SET_POLL_IN()
but for a write event._SET_POLL_INOUT($FD)
: Like_SET_POLL_IN()
but registers a read and write event simultaneously._STOP_POLL($FD)
: Tells the event loop that the given file descriptor is finished._GET_FD_ACTION(\@ARGS)
: Receives a reference to the arguments given toprocess()
and returns a reference to a hash of ( $fd => $event_mask ). $event_mask is the sum ofNet::Curl::Multi::CURL_CSELECT_IN()
and/orNet::Curl::Multi::CURL_CSELECT_OUT()
, depending on which events are available.
EXAMPLES
See the distribution’s /examples directory.
SEE ALSO
If you use AnyEvent, then AnyEvent::XSPromises with AnyEvent::YACurl may be a nicer fit for you.
REPOSITORY
https://github.com/FGasper/p5-Net-Curl-Promiser
LICENSE & COPYRIGHT
Copyright 2019-2020 Gasper Software Consulting.
This library is licensed under the same terms as Perl itself.