Hi Marcos,
I have appended code I wrote for the a event-stream client which
might give you some inspiration ... note that the design is
different as the data source (tail -f) only runs once and not for
every client connecting ... in your design every connection gets
its own tail ....
package Signage2;
use Mojo::Base 'Mojolicious';
# This method will run once at server start
sub startup {
my $self = shift;
# Router
my $r = $self->routes;
my $log = $self->log;
$r->get('/' => 'index');
my $stream = $self->launch_arec;
my $loop = Mojo::IOLoop->singleton;
$r->get('/sound' => sub {
my $self = shift;
# Change content type
my $out_stream = $loop->stream($self->tx->connection);
$self->res->headers->content_type('text/event-stream');
# stop mojo from complaining about incomplete page
$self->render_later;
my $read_cb = $stream->on(read => sub {
my ($stream, $chunk) = @_;
while ($chunk =~ m{^(.+)[\r\n]+}g){
$self->write("event:log\ndata:".$1."\n\n");
}
});
my $close = sub {
my $stream = shift;
$self->write("event:log\ndata:Closed\n\n") if $self;
$log->info("closed client connection");
$self->finish;
};
$stream->once(close => $close);
$stream->once(error => $close);
my $unsubscribe = sub {
$stream->unsubscribe(read=>$read_cb);
$log->info("browser gone");
};
# when the connnection is dead, stop writing to it
$out_stream->once(timeout => $unsubscribe);
$out_stream->once(close => $unsubscribe);
});
}
sub launch_tail {
my $self = shift;
# Increase inactivity timeout for connection a bit
my $log = $self->log;
my $pid = open(my $fh,"-|", "tail","-f","$FILE_PATH") ||
die "can't fork: $!";
# Create stream
my $loop = Mojo::IOLoop->singleton;
my $stream = Mojo::IOLoop::Stream->new($fh);
# register with the io loop
my $id = $loop->stream($stream);
$stream->on(error => sub {
my ($stream, $err) = @_;
$loop->remove($id);
$log->error("Stream Error: $err");
});
$stream->on(close => sub {
my $stream = shift;
$log->info("closing connection to tail");
waitpid($pid,0);
$loop->remove($id);
});
$stream->start;
return $stream;
}
1;
Today marcos rebelo wrote:
> Hi all
> I'm getting crazy with the next script. The script is a sort of tail for a
> file on the server, when I start the server it works ok but when I try to
> reload the page doesn't work any more.
> What am I doing wrong?
> #!/usr/bin/env perl
> use Mojolicious::Lite;
> get '/' => sub {
> my $self = shift;
> $self->render('index');
> };
> my $loop = Mojo::IOLoop->singleton;
> my $FILE_PATH = __FILE__; # Just for example now
> websocket '/tail' => sub {
> my $self = shift;
> open(my $fh, '-|', 'tail', '-f', $FILE_PATH) or die $!;
> $self->on(finish => sub {
> close $fh;
> $fh = undef;
> } );
> my $sub;
> $sub = sub {
> return if not defined $fh;
> my $line = readline($fh);
> $self->send_message( $line );
> print "SEND: $line";
> $loop->timer(0, $sub);
> };
> $sub->();
> };
> app->start;
> __DATA__
> @@ index.html.ep
> <!DOCTYPE html>
> <html>
> <head>
> <title>tail</title>
> <style>
> .class-test {
> width:10000px;
> }
> </style>
> <script type="text/javascript" src="
> http://code.jquery.com/jquery-1.7.2.min.js"></script>
> <script>
> "use strict"
> var create_line_div = function( text ) {
> var div = $("<div></div>");
> div.text(text);
> return div;
> };
> var websocket;
> var createWebSocket = function () {
> websocket = new WebSocket("<%=
> $self->req->url->to_abs->scheme( $self->req->is_secure ? 'wss' : 'ws'
> )->path( '/tail' ) %>");
> websocket.onmessage = function(evt) {
> $('.class-test').append( $( create_line_div( evt.data ) ) ) };
> };
> $( createWebSocket() );
> </script>
> </head>
> <body>
> Welcome to Tail!
> <div class='class-test'>
> </div>
> </body>
> </html>
> Best Regards
> Marcos Rebelo
--
Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
http://it.oetiker.ch t
...@oetiker.ch ++41 62 775 9902 / sb: -9900