2016-04-17 16 views
7

bağlı Mojolicious ve websockets ile uğraşıyorum. Sunucudaki çoklu dış komutların çıktısını web sayfasına göndermek istiyorum. Mesajları bağlama ve alma ile ilgili hiçbir sorunum yok, ancak başkalarının istemciye ileti göndermeye devam etmesine izin verirken harici bir komutu durdurmak için sunucuya bir mesaj göndermek istiyorum. Ayrıca çıktıktan sonra harici komutu kontrol etmeyi bırakmak istiyorum.Mojo :: IOLoop yinelenen olay bir Mojo websocket

Harici komut, her birkaç saniyede bir tamsayı harcayan bir tek çizgidir. Numaraları ayrı div s'de görüntüleyen iki web kökü var. Durdurma düğmelerinden herhangi birine tıklamak mesajı gönderir, ancak bu web bağlantısının nasıl kapatılacağını (ve sadece bu web parçasını) ve harici komutu nasıl kapatacağımı belirlemem gerekir. Ben WebSocket'e bağladığınızda

enter image description here

, ben dış komutunu çalıştırın ve çıkış olmadığını kontrol etmek için bir Mojo::IOLoop->recurring kurdu.

Durdurmak istediğimde, Mojo::IOLoop->remove($id) numaralı telefonu aramam gerektiğini anlıyorum, ancak bunu tamamen kaldırıyor gibi görünmüyor ve Mojo::Reactor::Poll: Timer failed: Can't call method "is_websocket" on an undefined value gibi hata iletilerini alıyorum.

Websocket'u kapatmak için denetleyici nesnesinde finish numaralı telefonu çağırırsam, her şey durmuş gibi görünüyor.

Ben tüm Mojolicious::Lite app as a gist var, ama burada

use feature qw(signatures); 
no warnings qw(experimental::signatures); 
## other boilerplate redacted 

websocket '/find' => sub ($c) { 
    state $loop = Mojo::IOLoop->singleton; 

    app->log->debug("websocket for find"); 
    $c->inactivity_timeout(50); 

    my $id; 
    $c->on(message => sub ($ws, $message) { 
     my $json = decode_json($message); 
     my $command = $json->{c}; 
     my $name = $json->{n}; 

     app->log->debug("Got $command command for $name"); 
     if($command eq "start") { 
      $id = run_command($ws); 
      app->log->debug("run_command for $name returned [$id]"); 
      } 
     elsif($command eq "stop") { 
      app->log->debug("stopping loop for $name [$id]"); 
      # XXX What should I do here? 
      # $ws->finish; 
      # $loop->remove($id); 
      } 
     elsif($command eq "open") { 
      app->log->debug("opening websocket for $name"); 
      } 
     } 
     ); 
    $c->on(
     finish => sub ($c, $code) { 
      app->log->debug("WebSocket closed with status $code"); 
      } 
     ); 
    }; 

app->start; 

sub run_command ($ws) { 
    app->log->debug("In run_command: $ws"); 
    open my $fh, "$^X -le '\$|++; while(1) { print int rand(100); sleep 3 }' |"; 
    $fh->autoflush; 

    my $id; 
    $id = Mojo::IOLoop->recurring(1 => sub ($loop) { 
     my $m = <$fh>; 
     unless(defined $m) { 
      app->log->debug("Closing down recurring loop from the inside [$id]"); 
      # XXX: what should I do here? 
      close $fh; 
      return; 
      }; 
     chomp $m; 
     app->log->debug("Input [$m] for [$id] from $fh"); 
     $ws->send(encode_json({ 'm' => $m })); 
     }); 

    return $id; 
    } 

Bu yanıt yararlanabilir

Diğer sorular parçalar var:

+0

Mojolicious, Perl6 stili alt argüman bildirimini etkinleştirir mi? – Zaid

+1

Perl v5.20, deneysel bir özellik olarak alt rutin imzalara sahiptir: http://www.effectiveperlprogramming.com/2015/04/use-v5-20-subroutine-signatures/ –

cevap

1

Bu konuda biraz oynamıştım. Logioniz's answer bana dosya el kitabı ayrıntılarını kendim seçmemeli veya kullanmamam gerektiğini söyledi. Hala nerede asılı olduğunu bilmiyorum.

Bunun yerine, izlemek için bir dosya tanıtıcısından ayarlamak için Mojo::Reactor 'ın io kullandı:

O komutla bittim
sub run_command ($ws) { 
    my $pid = open my $fh, "$^X -le '\$|++; print \$\$; while(1) { print int rand(100); sleep 3 }' |"; 
    $fh->autoflush; 

    my $reactor = Mojo::IOLoop->singleton->reactor->io(
     $fh => sub ($reactor, $writeable) { 
      my $m = <$fh>; 
      chomp $m; 
      $ws->send(encode_json({ 'm' => $m })); 
      } 
     ); 

    return ($fh, $pid); 
    } 

, o dosya tanıtıcısından unwatch ve süreci öldürebilir.remove($fh) çalışmıyor neden hala bilmiyorum

elsif($command eq "stop") { 
     $loop->reactor->watch($fh, 0, 0); 
     kill 'KILL', $pid or app->log->debug("Could not kill $pid: $!"); 
     $ws->finish; 
     } 

: Ben WebSocket'e bitirmek. Sanırım IOLoop'un bazı şeylerini böyle yapıyor.

0

bence olay döngüsünü engellediğiniz için tekrar tekrar çağırmanız gerekir. çok saniye ve my $m = <$fh>; bekleyin yaklaşık 2-3 saniye bekleyin. Böylece olay döngüsünü engellersiniz. Sanırım, uygulamanızı çalıştırdığımda etkinlik finish etkinliğindeki zaman aşımına uğramaz, ancak olay recurrent numaralı telefonu arayın. finish olayı her zaman hareketsizlik zaman aşımına uğrayacak ZORUNLU.

Kodunuzun, olay döngüsünü engellememek için ayrı bir işlemde olması gerektiğini düşünüyorum.

Ayrı işlem yürütmek için this modülünü kullanmayı deneyin. I write küçük bir örnek.