http://www.perlmonks.org?node_id=11110913


in reply to Mixing asynchronous data feed with synchronous program flow control

Only FWIW and good measure.

Server:
use Cro::HTTP::Router; use Cro::HTTP::Server; use Cro::HTTP::Router::WebSocket; my $application = route { get -> { web-socket -> $incoming { supply { my Bool $Running; multi sub process-command( "RUN" ) { True, ( $Running ?? "Already running" !! "Starting + to run…" ); } multi sub process-command( "STOP" ) { False, ( $Running ?? "Stopping…" !! "Not running" +); } multi sub process-command( $command ) { $Running, "Unknown command: $command"; } emit "Connected… RUN|STOP\n" ~ "Service is { $Running ?? "already" !! "not" } ru +nning"; whenever $incoming -> $message { my $command = await $message.body-text; say "Command: $command"; ($Running, my $answer) = process-command( $command + ); emit $answer; } } } } } my Cro::Service $service = Cro::HTTP::Server.new( :host<localhost>, :port<8080>, :$application ); $service.start; say "Started"; react whenever signal(SIGINT) { say "Killed"; $service.stop; exit; }
Client:
use Cro::WebSocket::Client; say "Connecting..."; my $conn = try await Cro::WebSocket::Client.connect( 'ws://localhost:8 +080' ); say "WebSocket handshake failed!" and exit unless $conn; say "Connected"; react { # It is guarantueed, only one whenever block in this react block c +an be running at any given time # There are no race conditions, for $conn whenever $conn.messages -> $message { say "Incoming: ", await $message.body; } # Currently this part only works for me since I patched in the clo +sing - supply. # But I am confident my pull request will be accecpted in some for +m # Maybe not with that exact name whenever $conn.closing -> $reason { say "Closing: $reason"; done; } # Without the above, one would have to check here for # $conn.closed != True before calling `send` whenever Supply.interval(5) -> $tick { my $command = ("RUN", "STOP").pick; say "Sending: $command"; $conn.send( $command ); CATCH { say "Error sending <$command>: {.message}" } } };


holli

You can lead your users to water, but alas, you cannot drown them.

Replies are listed 'Best First'.
Re^2: Mixing asynchronous data feed with synchronous program flow control (in Raku)
by Your Mother (Archbishop) on Jan 03, 2020 at 23:39 UTC

    Thank you very much. I’m interested in all (clean) approaches to this. What I’ve got, and haukex corrected, is working well but it’s a prototype still that is going to grow into quite a lot of code so I’m going to look into anything I have time to learn.

      Have you considered POE? (Learning POE is on my to-do list.)

      Or if other languages are an option and this needs to scale out to a large number of connections, have you considered Erlang/OTP? (Which, as I currently understand, effectively hides a multi-threaded event loop in the language runtime, but more-or-less forces you into a message-passing functional programming paradigm as a result. I have heard good things about it but have not yet used it for a non-trivial program myself.)

        Those are good thoughts. I did quite a bit of POE back in the day. I don’t think I’ve used it in… 15 years? Which, strangely enough, was the same time I tried to pick up some Erlang. I failed. :P Partly because that was exactly when Perl got back up with Catalyst, DBIC, Plack… So I stopped needing to branch out.

        POE isn’t a good match for the project. Javascript is probably the best fit for the stuff I’m trying to do right now with the explosion of promise/wait/async stuff in the core and Typescript and such. In fact, I rewrote a bunch of JS in Perl for my newest client because there is no Perl lib but plenty in other languages… :( The code is doing a LOT of other things though and I’m quite solid in Perl and a bit of a behind-the-times dilettante in JS. I’ve already prototyped something like 10 clients and a few dozen approaches and can jump in and out of testing approaches and such because of my familiarity with Perl… and I think it still is the best munging/prototyping language, maybe by a lot.