Skip to content

Instantly share code, notes, and snippets.

@mattn
Last active December 10, 2015 23:08
Show Gist options
  • Save mattn/4507000 to your computer and use it in GitHub Desktop.
Save mattn/4507000 to your computer and use it in GitHub Desktop.
use strict;
use warnings;
use lib qw(lib);
use Plack::Builder;
use Plack::Request;
builder {
enable "Plack::Middleware::Static", path => '.', root => '.';
enable "Plack::Middleware::WebSocket";
enable "Plack::Middleware::LiveReload";
sub { [ 404, [ "Content-Type" => "text/plain" ], ["Not Found"] ] };
};
package Plack::Middleware::LiveReload;
use strict;
use parent qw(Plack::Middleware);
use Cwd qw( abs_path );
use Plack::Response;
use WebSocket::ServerAgent;
use AnyEvent::Loop;
use AnyEvent::Filesys::Notify;
use Plack::Util::Accessor qw( path );
sub call {
my ($self, $env) = @_;
my $res = Plack::Response->new(200);
if ($env->{PATH_INFO} eq '/livereload.js') {
$res->content_type('text/javascript');
$res->body(<<'@EOF');
(function() {
var ws = new WebSocket("ws://" + location.host + "/livereload");
ws.onmessage = function (evt) { location.reload() };
})();
@EOF
return $res->finalize;
} elsif ($env->{PATH_INFO} eq '/livereload') {
if (my $fh = $env->{'websocket.impl'}->handshake) {
my $path = abs_path($self->path || 'htdocs');
my $agent = WebSocket::ServerAgent->new( $fh );
my $watcher = AnyEvent::Filesys::Notify->new(
dirs => [ $path ],
cb => sub {
for my $event (@_) {
next if $event->{type} ne 'modified';
$agent->send_text(substr($event->{path}, length $path));
}
}
);
return sub {
AnyEvent::Loop::one_event;
}
} else {
$res->code($env->{'websocket.impl'}->error_code);
}
return $res->finalize;
}
$self->app->($env);
}
1;
__END__
=head1 NAME
=head1 SYNOPSIS
enable "LiveReload";
=head1 DESCRIPTION
=head1 AUTHOR
Yasuhiro Matsumoto
=head1 SEE ALSO
L<Plack>
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment