#!/usr/bin/perl

=head1 NAME

    mediaplan-ctl -- управление тестовым стендом медиапланов на "бете"

=head1 SYNOPSIS

    mediaplan-ctl [<абс. путь к директории>] (start|stop) [-p <порт>]

    # запустить в текущей директории с именем вида /var/www/mediaplan.NNNN на порту NNNN
    mediaplan-ctl start

    # можно указать директорию явно (только абсолютный путь)
    mediaplan-ctl /var/www/mediaplan.13470 start    # тут порт опять же определится из пути

    # можно запустить из рабочей копии в произвольном месте, но тогда нужно указать порт.
    mediaplan-ctl /home/yukaba/mediaplan -p 13420
    # Никакой проверки на занятость в этом случае не делается, так что пользуйтесь с осторожностью. Лучше брать порт из своего зарезервированного диапазона, чтобы уж точно никому не помешать.

    # Остановить запущенный процесс
    mediaplan-ctl stop
    mediaplan-ctl /var/www/mediaplan.13470 stop
    mediaplan-ctl /home/yukaba/mediaplan stop

=head1 DESCRIPTION

    Понимает команды:
        start -- запустит скрипт execute-and-play из рабочей копии. Порт или передаётся явно, или определится по директории, если путь имеет вид /var/www/mediaplan.13420 (аналогично бетам Директа). Номер процесса запишет в mediaplan.pid

        stop -- остановить процесс при наличии файла mediaplan.pid. Дополнительно делается проверка на то, что в командной строке останавливаемого процесса есть строчка "execute-and-play".

    Опции:
        -p, --port
            Указать порт, на котором запустить процесс.

        -h, --help
            Показать эту справку.

=cut

use strict;
use warnings;

use utf8;

use open qw/:std :encoding(UTF-8)/;

use Cwd;
use Getopt::Long;
use Path::Tiny;

use Yandex::Shell;

my $WAIT_FOR_START_TIMEOUT = 300;
my $WAIT_FOR_STOP_TIMEOUT = 300;
my ($CMD, $DIR, $PORT);

run() unless caller();

sub run {
    parse_options();
    my $pid_file = "$DIR/mediaplan.pid";
    my $urls_file = "$DIR/mediaplan.urls";
    chdir $DIR;
    if ($CMD eq 'start') {
        die "pid file $pid_file is already present, will not start" if -f $pid_file;
        my $cmd = "./execute-and-play --port $PORT --no-interactive --urls-file $urls_file 2>&1 &>mediaplan.log </dev/null& echo \$! > $pid_file";
        yash_system($cmd);
        my $start_time = time();
        while (!-f $urls_file) {
            sleep 1;
            if (time() - $start_time > $WAIT_FOR_START_TIMEOUT) {
                die "timed out waiting for service to start\n";
            }
        }
        my (undef, $url) = split /\n/, path($urls_file)->slurp_utf8;
        print "$url\n";
    } elsif ($CMD eq 'stop') {
        die "no pid file $pid_file found, will not stop" unless -f $pid_file;
        yash_system('pkill', '--pidfile', $pid_file, '-TERM', '--full', 'execute-and-play');
       
        my $start_time = time();
        while (1) {
            `pgrep -F $pid_file -f execute-and-play`;
            my $status = $? >> 8;
            if ($status == 0) {
                sleep 3;
            } elsif ($status == 1) {
                alarm 0;
                last;
            } else {
                die "pgrep failed mysteriously";
            }
            if (time() - $start_time > $WAIT_FOR_STOP_TIMEOUT) {
                die "timed out waiting for process to stop\n";
            }
        }
        unlink $pid_file;
        unlink $urls_file;
    } else {
        die "unknown command '$CMD'";
    }
}

sub parse_options {
    GetOptions(
        'p|port=s' => \$PORT,
        'h|help' => sub { system("podselect -section SYNOPSIS -section DESCRIPTION $0 | pod2text-utf8 >&2"); exit 0 },
    ) || die "can't parse options, stop";
    # можно было бы делать mediaplan-ctl (start|stop) <path>
    # но в direct-mk, на который этот скрипт похож, директория (если есть) передаётся первым аргументом и только абсолютным путём
    # и чтобы не путаться каждый раз, делаем тут так же, как в direct-mk
    if ($ARGV[0] && $ARGV[0] =~ m!^/!) {
        $DIR = shift @ARGV;
    }
    $CMD = shift @ARGV;
    die "no command given" unless $CMD;
    $DIR //= getcwd();
    if (!$PORT) {
        ($PORT) = $DIR =~ m!^/var/www/mediaplan\.([0-9]+)$!;
        die "no port given and couldn't determine it from path" unless $PORT;
    }
}
