pprocacci has asked for the wisdom of the Perl Monks concerning the following question:

Monks,

Firstly, thank you in advance for taking your time to read through my question.

The below `heavily modified` perl code works flawlessly without the call to retr_connected_users. Once I add that subroutine, perl gets hung on the `select` syscall *after* it's first interation through the code. I suspect it has something to do with the `some command` code, and I have tried variations like open/<>/close, but I cannot get past the first iteration.

My question is can AnyEvent effect the underlying file descriptors in a way that would cause this strange behavior and is there any way to read external data from pipes/file descriptors synchronously that perhaps I am just missing entirely?

use AnyEvent::XMPP::Ext::MUC; sub retr_connected_users { my @data = map { chomp; s/@.*//; $_ } (`some command`); return @data; } $muc->reg_cb( message => sub { my ( undef, undef, $msg ) = @_; my @inter = retr_connected_users(); foreach my $user(@inter){ AnyEvent::XMPP::IM::Message->new ( body => construct_body($msg->body, $fr +om), to => "$user\@" . HOST, type => "chat", )->send($conn); } }, );
Thanks for your time.

Replies are listed 'Best First'.
Re: AnyEvent weirdness w/ open() and/or ``'s
by james2vegas (Chaplain) on Nov 02, 2013 at 17:06 UTC
    Why do you need to read your data synchronously? Why not read lines from your command asynchronously, and create the messages in a callback? There are many AnyEvent modules to make running and getting output back from external commands easy, but there is also AnyEvent::Util::fork_call (which serialises the whole output of your command before calling the callback).

    Alternatively, you could probably use an IO watcher like this:
    open my $fh, '-|', 'some command'; my $w; $w = AnyEvent->io( fh => $fh, poll => 'r', cb => sub { chomp(my $user = $fh->getline); AnyEvent::XMPP::IM::Message->new( body => construct_body( $msg->body, $from ), to => "$user\@" . HOST, type => "chat", )->send($conn); undef $w if eof($fh); } );
      James,

      I appreciate your response. My familiarity w/ AnyEvent isn't too great and your response has helped greatly. What I ended up doing which I believe to look extremely ugly follows my comments. (again heavily modified)

      To provide further details to hopefully paint a full picture .... I have two sources. One is from a command, and another is from a file. Both sources are pulled into an array and what I believe the below achieves is sending messages to the intersection of the arrays.

      The below works with my limited testing and I appreciate the guidance thus far you've provided. I don't need further help unless of coarse you see something glaringly wrong, but until then, thanks James.

      $muc->reg_cb( message => sub { my ( undef, undef, $msg ) = @_; my @connected_users = (); open my $fh, '-|', 'command_that_outputs_users' or die $!; my $w; $w = AnyEvent->io( fh => $fh, poll => 'r', cb => sub { my $user = $fh->getline; return if !defined($user); chomp($user); push(@connected_users, $user); if(eof($fh)){ close($fh); undef $w; open($fh, "< $file") or die $!; my $w2; $w2 = AnyEvent->io( fh => $fh, poll => 'r', cb => sub { my $user = $fh->getline; return if !defined($user); chomp($user); if($user ~~ @connected_users){ AnyEvent::XMPP::IM::Message->new( body => construct_body( $msg->body, $from ), to => "$user\@" . HOST, type => "chat", )->send($conn); close($fh); undef $w2; } } ); } } ); }, );