Using IO::Socket::IP with Mojo::IOLoop

Viewed 141

I am trying to achieve what these lines of code do synchronously, but asynchronously via Mojo::IOLoop and Mojo::Promises:

my $address = '192.168.1.240';

my $sock = IO::Socket::IP->new(PeerAddr => $address,
                          PeerPort => '9999',
                          Proto    => 'tcp');

$sock->send($on);

my $data;

$sock->recv($data, 2048);

print $data;

This is used to communicate with a smartplug, and a promise-based interface would allow me to abstract out things, so that different plugs (some communicating via HTTP, some via TCP) could be handled in the same way.

Right now I've achieved the result by doing this

sub talk_to_plug_p {
    my ($addr, $command) = @_;

    my $promise =  Mojo::Promise->new;
    my $port = 9999;

    my $sock = IO::Socket::IP->new(PeerAddr => $addr,
                                   PeerPort => $port,
                                   Proto    => 'tcp');

    return $promise->reject("Could not open socket on $addr at port $port") unless $sock;

    my $id = Mojo::IOLoop->client({ handle => $sock } => sub {
                                      my ($loop, $err, $stream) = @_;

                                      $stream->on(read => sub {
                                                      my ($stream, $bytes) = @_;

                                                      # -------------------
                                                      # THIS LOOKS BAD
                                                      # -------------------
                                                      remove_id($loop);
                                                      $promise->resolve($bytes);
                                                  });

                                      $stream->on(error => sub {
                                                      my $err = shift;
                                                      $promise->reject($err);
                                                  });
                                      $stream->write($command);
                                  });

    sub remove_id { shift->remove($id) };

    return $promise;
}

talk_to_plug_p('192.168.1.240', $on)->then(sub { print @_ })->catch(sub { print shift });

Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

Now this works but it kind of looks wrong - especially the remove_id part, and I imagine there must eb a better way than this. I just could not find it.

What would be a cleaner way? i.e.: one that closes the client when bytes have been read, or where I can explicitly close the connection or something similar.

0 Answers
Related