Connecting to Other Servers
Sometimes it is desirable to connect to another server to retrieve information or offload some work; databases such as PostgreSQL and Apache Couch require this (although it is probably simpler to use available perl interfaces in those cases).
Sloop can do this for TCP using unix local or normal internet addressing. The logic may at first seem a bit tricky due to the asynchronous, non-blocking nature of the connections. The relevant module is Sloop::Other, which, like Sloop::Client, comes in two flavours, Regular and Secure; this is important to note because you must instantiate these yourself.
my $other = Sloop::Other::Regular->new ( dest_addr => '127.0.0.1', dest_port => 1234, incoming => sub { }, logger => $sloop->{logger} ); $sloop->connectOther($other);
The call to connectOther()
sets up handling by the server. Here, $sloop
is assumed to be a Sloop::Server object so that logging is unified. Notice that incoming
is defined (this is required) but doesn't do anything. This can then be set on a case by case basis. For example, in a request handler:
sub { my $client = shift; # But we need some stuff from a remote DB. $other->message(\"Get data!"); $other->{incoming} = sub { my ($self, $msgref, $msgsz) = (shift, shift, shift); # Check if message is complete. my $complete = ... if (!$complete) return 0; # Incorporate data into reply to client. my $reply = ... $client->reply(\$reply); return 1; } }
This is a bit problematic if you must juggle simultaneous similar requests. For this reason, instead of setting incoming
to a handler, you may set it to an array reference containing a list of handlers. The first one will be used, and when it returns > 0, shifted off the array. This allows for collecting incoming data until you have the complete response. Since Sloop itself doesn't know anything about the message format, if you have multiple requests queued, you may end up with part of the next response in $msgref
. You can deal with this by attaching the remainder to $other
; Sloop objects are guaranteed to never use attributes starting with an underscore, so something like $other->{_data}
is fine. The otherDemo.pl example uses this technique.
Alternately, you can just create an Other for each request. Remember to call shut()
or return -1 from an incoming
handler when you are done though, otherwise the object may leak; unlike regular clients, they never time out (although if the remote server disconnects, internal references will be removed).
TLS Connections
If you use Sloop::Other::Secure, the server you connect to can be authenticated by submitting an appropriate trustFile
to Sloop::Socket::TLS::init()
or via the Sloop::Server constructor, if it is also secure. Commonly linux systems have a general purpose global trust store in /etc/pki
or /etc/ssl
; you want a file in PEM format (e.g /etc/ssl/certs/ca-certificates.crt
). If you want to bypass this authentication, use Sloop::Other::Secure::TRUST_ALL
as the trustLevel
argument to the Secure constructor.