App-screenorama

 view release on metacpan or  search on metacpan

script/screenorama  view on Meta::CPAN

#!/usr/bin/env perl
BEGIN {
  @Screenorama::ARGV = do {
    my $i = 0;
    for my $arg (@ARGV) {
      last if $arg eq '--';
      $i++;
    }
    splice @ARGV, $i, @ARGV, ();
  };
  shift @Screenorama::ARGV;
}
use Mojolicious::Lite;
use Mojo::IOLoop::ReadWriteFork;

my $config = $ENV{MOJO_CONFIG} ? plugin 'Config' : app->config;
my ($program, @program_args) = @Screenorama::ARGV ? @Screenorama::ARGV : split /\s/, ($ENV{SCREENORAMA_COMMAND} || '');

$config->{conduit}     ||= $ENV{SCREENORAMA_CONDUIT}     || 'pty';
$config->{kill_signal} ||= $ENV{SCREENORAMA_KILL_SIGNAL} || 15;
$config->{program_args} ||= \@program_args;
$config->{program} ||= $program or die "Usage: $0 -- <program> [args]\n";
$config->{single} //= $ENV{SCREENORAMA_SINGLE} || 0;
$config->{stdin}  //= $ENV{SCREENORAMA_STDIN}  || 0;

get '/' => sub {
  my $c   = shift;
  my $url = $c->req->url->to_abs;

  $c->render('index', stream_base => $url->clone->base->scheme($url->scheme =~ /https/ ? 'wss' : 'ws'));
};

if ($config->{single}) {
  my $plugins = app->plugins;
  my ($fork, $last);

  websocket '/stream' => sub {
    my $c = shift;
    my $cb = sub { $c->send({json => $_[1]}) };

    unless ($fork) {
      $fork = _start_application($c);
      $fork->on(close => sub { $plugins->emit(output => $last = {exit_value => $_[1], signal => $_[2]}) });
      $fork->on(error => sub { $plugins->emit(output => $last = {error => $_[1]}) });
      $fork->on(read => sub { $plugins->emit(output => {output => $_[1]}) });
    }

    $plugins->on(output => $cb);
    $c->on(finish => sub { $plugins->unsubscribe(output => $cb); });
    $c->send({json => $last}) if $last;
  };
}
else {
  websocket '/stream' => sub {
    my $c    = shift;
    my $fork = _start_application($c);

    Scalar::Util::weaken($c);
    $c->on(finish => sub { $fork->kill($config->{kill_signal}); undef $fork; });
    $fork->on(close => sub { $c->send({json => {exit_value => $_[1], signal => $_[2]}})->finish });
    $fork->on(error => sub { $c->send({json => {error      => $_[1]}})->finish });
    $fork->on(read  => sub { $c->send({json => {output     => $_[1]}}) });
  };
}

app->start;

#=============================================================================

sub _start_application {
  my $c    = shift;
  my $fork = Mojo::IOLoop::ReadWriteFork->new;

  Mojo::IOLoop->stream($c->tx->connection)->timeout(60);
  $fork->start(conduit => $config->{conduit}, program => $config->{program}, program_args => $config->{program_args});
  $c->on(json => sub { $fork->write(chr $_[1]->{key}) if $_[1]->{key} }) if $c->app->config->{stdin};
  $c->send({json => {program => $program, program_args => \@program_args}});
  $fork;
}
__DATA__
@@ index.html.ep
<!DOCTYPE html>
<html>
<head>
  <title>screenorama - <%= app->config->{program} %> <%= join ' ', @{app->config->{program_args}} %></title>
  %= stylesheet begin
body { background: #111; padding: 8px; }
body, .shell { font-size: 13px; font-family: monospace; color: #eee; margin: 0; padding: 0; }
pre { margin: 0; padding: 0; }
.status { border-top: 1px solid #333; margin-top: 20px; }
input { position: absolute; left: -600px; }
  % end
  %= javascript begin
var termColors = { // from http://flatuicolors.com/
  '30': '#000000',
  '31': '#c0392b',
  '32': '#2ecc71',
  '33': '#f1c40f',
  '34': '#48a2df',
  '35': '#9b59b6',
  '36': '#1abc9c',
  '37': '#ecf0f1',
};

var screenorama = function() {
  var cursor = document.querySelector('.cursor');
  var input = document.querySelector('input');

  var attach = function(elem, events, cb) {
    events = events.split(' ');
    for (var i = 0; i < events.length; i++) elem.addEventListener(events[i], cb, false);
  };

  screenorama.buf = '';
  screenorama.ws = new WebSocket('<%= $stream_base %>/stream');

% if (app->config->{stdin}) {
  cursor.visible = true;



( run in 1.678 second using v1.01-cache-2.11-cpan-39bf76dae61 )