#!/usr/bin/env perl use Mojolicious::Lite -signatures; use Mojo::UserAgent; use Mojo::EventEmitter; use Data::Dump qw/dd pp/; # morbo --listen='http://localhost:3001' mux.pl # This code assumes a single thread / no forking! my $event = Mojo::EventEmitter->new; sub open_server_conn { state $ua = Mojo::UserAgent->new; $ua->inactivity_timeout(5); # must be less than client's timeout app->log->debug("Opening WebSocket to server..."); $ua->websocket('ws://localhost:3000' => sub ($ua, $tx) { die 'WebSocket handshake failed!'.pp($tx) unless $tx->is_websocket; my $timer_id = Mojo::IOLoop->recurring( 30 => sub { app->log->debug("Sending heartbeat"); $tx->send('HEARTBEAT'); } ); $tx->on(finish => sub ($tx, $code, $reason=undef) { app->log->debug("Server WebSocket closed " .pp($code, $reason)); Mojo::IOLoop->remove($timer_id); open_server_conn(); # reopen }); $tx->on(message => sub ($tx, $msg) { # message from server return if $msg=~/^Connected\b|^Starting\b/; return unless $event->has_subscribers('message'); app->log->debug("Relaying ".pp($msg)); $event->emit( message => $msg ); }); $tx->send('RUN'); }); } Mojo::IOLoop->next_tick(\&open_server_conn); websocket '/' => sub ($c) { # client connections $c->app->log->debug('Client connected'); $c->inactivity_timeout(45); my $tx = $c->tx; # client transaction my $cb = $event->on(message => sub ($e,$msg) { $tx->send($msg) }); $c->on(message => sub ($c, $msg) { # message from client if ( uc $msg eq "RUN" ) { } # ignore client messages (for now) elsif ( uc $msg eq "STOP" ) { } elsif ( uc $msg eq "HEARTBEAT" ) { } else { $tx->send("Unknown command: $msg") } }); $c->on(finish => sub ($c, $code, $reason=undef) { $c->app->log->debug("Client disconn ".pp($code, $reason)); $event->unsubscribe(message => $cb); ($tx,$cb) = (); }); $c->send("Connected... RUN|STOP"); }; app->start