I have the following parts to a system:
1 - price_alerts.html
2 - WSServer.pl
3 - WSConnector.pm
4 - CoreApplicationEngine.pm
Basically the CoreApplicationEngine.pm is constantly running and for
arguments sake parsing data coming from text files (nothing to do with
websockets).
I want to send updates to the browser page price_alerts.html - which works
but I am not sure if I am going about it in the correct way.
This is the program flow:
CoreApplicationEngine.pm
--------------------------------------------------
package CoreApplicationEngine;
use WSConnector;
use threads;
...
sub priceParser {
my($self) = @_;
## Process some files here
## When a condition is met update any one browsing on the
price_alerts.html page
my $WSConnector = new WSConnector();
my $thread = async {
$WSConnector->sendPriceAlert($price, $itemid, $item_name);
};
$thread->detach;
}
-----------------------------------------------------
package WSConnector;
use Mojo::UserAgent;
use Mojo::IOLoop;
use JSON;
sub new {
my $class = shift;
my $ua = Mojo::UserAgent->new;
my $self = { 'ua' => $ua };
bless $self, $class;
return $self;
}
sub sendPriceAlert {
my ($self, $price, $itemid, $item_name) = @_;
my $ua = $self->{ua};
my $data;
$data->{type} = "price_alert";
$data->{price} = $price;
$data->{itemid} = $itemid;
$data->{item_name} = $item_name;
my $json_data = encode_json($data);
$ua->websocket(
'ws://192.168.1.50:3000/prices' => sub {
my ( $ua, $tx ) = @_;
print 'WebSocket handshake failed!' and return unless
$tx->is_websocket;
# Send a message to the server
$tx->send($json_return);
}
);
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
}
sub otherAlertsHere { ... }
----------------------------------------------------------------
WSServer.pl
#!/usr/bin/perl -w
use strict;
use Mojolicious::Lite;
use JSON;
websocket '/prices' => sub {
my $c = shift;
# Opened
$c->app->log->debug('Prices WebSocket opened');
my $cli = sprintf( "%s", $c->tx );
$all_cli_txs->{$cli} = $c->tx; ## So I can broadcast to all
connected browsers
# Increase inactivity timeout for connection a bit
$c->inactivity_timeout(1000);
# Incoming message
$c->on(
message => sub {
my ( $c, $msg ) = @_;
my $json = decode_json($msg);
## Process some data here and determine which subscribers
to send to - broadcast, subset or single user - for example sake simply
passing original json data here as $msg
if($json->{type} eq "price_alert"){
for my $client (keys %$all_cli_txs) {
$all_cli_txs->{$client}->send($msg);
}
}
}
}
$c->on(
finish => sub {
my ( $c, $code, $reason ) = @_;
$c->app->log->debug("WebSocket closed with status $code");
}
);
};
websocket '/otherthings' => sub {
my $c = shift;
## ...... more
};
----------------------------------------------------------------
I will not post the javascript code on the front end as that is working
without issue.
I have two main questions:
Question 1 - The code above works but eats memory. When running 1000s of
updates a minutes, for example in a test, memory consumption rises until
the whole system becomes unresponsive. This, I assume, is because of the
thread async call to the WSConnector which is opening 1000s of ws
connections and not closing them.
So the first question is how do I use 'Mojo::IOLoop->stop;' to stop the ws
client after a single send - I dont want a loop?
I have tried a few variations, like the following but cannot seem to get it
to work:
sub sendPriceAlert {
my ($self, $price, $itemid, $item_name) = @_;
my $ua = $self->{ua};
my $data;
$data->{type} = "price_alert";
$data->{price} = $price;
$data->{itemid} = $itemid;
$data->{item_name} = $item_name;
my $json_data = encode_json($data);
$ua->websocket(
'ws://192.168.1.50:3000/prices' => sub {
my ( $ua, $tx ) = @_;
print 'WebSocket handshake failed!' and return unless
$tx->is_websocket;
# Send a message to the server
$tx->send($json_return);
Mojo::IOLoop->stop;
}
);
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
}
Question 2 - I am having a really hard time understanding how websockets
work in practice. The basics are straight forward and I have no problem
implementing basic and more advanced examples. However, I suspect I am
fundamentally missing something as all examples seem to only be reactive,
rather than having the ability to react OR inject 'send' messages from
outside the WS server they simply listen for messages and then send
messages back.
Am I on the right track by using an intermediate ws client (WSConnector.pm)
as the 'pusher' for messages to the front end from the
CoreApplicationEngine.pm?
Or is there a better way to send messages from CoreApplicationEngine.pm
directly to a WS server that would then pass it onto the front end html
page rather than having to use an intermediate client setup.
Thanks in advance to anyone that may be able to help me or point me in the
right direction.
--
You received this message because you are subscribed to the Google Groups
"Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/d/optout.