2016-04-17 16 views
7

से जुड़ा हुआ है मैं Mojolicious और websockets के साथ खेल रहा हूं। मैं वेबपृष्ठ पर सर्वर पर एकाधिक बाहरी आदेशों का आउटपुट भेजना चाहता हूं। मुझे संदेशों को जोड़ने और प्राप्त करने में कोई समस्या नहीं है, लेकिन मैं बाहरी संदेश को रोकने के लिए सर्वर पर एक संदेश वापस भेजना चाहता हूं जबकि दूसरों को क्लाइंट को संदेश भेजना जारी रखता हूं। एक बार बाहर निकलने के बाद भी मैं बाहरी कमांड की जांच करना बंद करना चाहता हूं।एक मोजो को बंद करना :: IOLoop पुनरावर्ती घटना एक मोजो websocket

बाहरी कमांड केवल एक-लाइनर है जो हर कुछ सेकंड में एक पूर्णांक को थूकता है। मेरे पास दो websockets हैं जो संख्या div एस में अलग-अलग प्रदर्शित करते हैं। स्टॉप बटन में से किसी एक को क्लिक करने से संदेश भेजता है, लेकिन वह जगह है जहां मुझे यह पता लगाने की आवश्यकता है कि उस वेबसाकेट को बंद करने के लिए (और केवल उस वेबसाकेट) को बंद करें और बाहरी कमांड को बंद करें।

enter image description here

जब मैं WebSocket कनेक्ट, मैं बाहरी कमांड चलाने के लिए और अगर वहाँ उत्पादन है की जाँच करने के लिए एक Mojo::IOLoop->recurring की स्थापना की।

जब मैं रुकना चाहता हूं, मुझे लगता है कि मुझे Mojo::IOLoop->remove($id) पर कॉल करना चाहिए, लेकिन ऐसा लगता है कि इसे पूरी तरह से हटाया नहीं जा रहा है और मुझे Mojo::Reactor::Poll: Timer failed: Can't call method "is_websocket" on an undefined value जैसे त्रुटि संदेश मिलते हैं।

यदि मैं वेबस्केट को बंद करने के लिए नियंत्रक ऑब्जेक्ट पर finish पर कॉल करता हूं, तो यह सबकुछ बंद करना प्रतीत होता है।

मैं पूरी Mojolicious::Lite app as a gist है, लेकिन यहाँ कुछ हिस्सों, जहां मैं

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; 
    } 

अन्य प्रश्न है कि क्या यह उत्तर से लाभ हो सकता है:

+0

क्या Mojolicious Perl6-style उप तर्क घोषणा सक्षम करता है? – Zaid

+1

पर्ल v5.20 में एक प्रयोगात्मक सुविधा के रूप में subroutine हस्ताक्षर हैं: http: //www.effectiveperlprogramming.com/2015/04/use-v5-20-subroutine-signatures/ –

उत्तर

1

मैंने इसके साथ थोड़ा सा खेला। Logioniz's answer ने मुझे यह सोचा कि मुझे खुद को फाइलहेडल विवरणों को मतदान या संभालना नहीं चाहिए। मुझे अभी भी पता नहीं है कि यह कहां लटका रहा था।

इसके बजाय, मैं Mojo::Reactor के io इस्तेमाल किया एक filehandle स्थापित करने के लिए नजर रखने के लिए:

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); 
    } 

जब मैं उस आदेश के साथ किया हूँ, मुझे लगता है कि filehandle unwatch और इस प्रक्रिया को मार सकता है।

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

मैं अभी भी क्यों remove($fh) काम नहीं करता है पता नहीं है: मैं WebSocket खत्म। मुझे लगता है कि मैं इस तरह से कुछ IOLoop चीजें कर रहा हूँ।

0

मुझे लगता है कि कि आप इवेंट लूप को अवरुद्ध करते हैं क्योंकि आपका आवर्ती ई का आह्वान करता है बहुत दूसरा और my $m = <$fh>; लगभग 2-3 सेकंड प्रतीक्षा करें। तो आप इवेंट लूप को अवरुद्ध करते हैं। मुझे ऐसा लगता है क्योंकि जब मैं अपना ऐप चलाता हूं तो ईवेंट finish निष्क्रियता टाइमआउट पर कॉल नहीं करता है, लेकिन ईवेंट recurrent पर कॉल करें। finish घटना हमेशा निष्क्रियता टाइमआउट पर कॉल करनी चाहिए।

मुझे लगता है कि इवेंट लूप को अवरुद्ध करने से बचने के लिए आपका कोड अलग प्रक्रिया में होना चाहिए।

अलग प्रक्रिया में निष्पादित करने के लिए this मॉड्यूल का उपयोग करने का प्रयास करें। मैं write छोटा उदाहरण।

संबंधित मुद्दे