LINUX.ORG.RU

Realtime вывод результатов команды на страницу

 ,


0

2

Привет!

Подскажите, пожалуйста, чем можно реализовать realtime вывод результатов выполнения скрипта\команды на вебстраницу используя python (планируется использовать «встроенный» вебсервер, то есть Nginx\Apache и прочие использоваться не будут). Вариант дергать «обработчик» скрипта через небольшие промежутки времени через Ajax мне не очень нравится, да и вообще нужен реалтайм. Может проще для этого встроить какой-нибудь webshell с ограниченной функциональностью? Гуглятся варианты с node.js в основном, нашел еще вот такой вариант, но в браузере у меня не работает, текст выводится только после окончания выполнения скрипта (через curl все в норме).

В общем, как обычно решаются такие задачи? Заранее огромное спасибо!

★★★★★

Tornado

class LogHandler(WebSocketHandler):
    def __init__(self, application, request, **kwargs):
        super(LogHandler, self).__init__(application, request, **kwargs)
        self.watch_callback = None
        self.old_position = None

    def _stop_callback(self):
        if self.watch_callback:
            self.watch_callback.stop()
            self.watch_callback = None

    def open(self):
        pass

    def on_message(self, bid):
        def close(msg):
            self.old_position = None
            self.write_message(msg)
            self._stop_callback()
            self.close()

        def watch_build():
            build = get_build(bid)
            if not build:
                close(message.notification('Build "{0}" does not exists'.format(bid)))
            else:
                watch_file = open(build['path'], 'r')
                if self.old_position is None:
                    self.old_position = os.path.getsize(build['path'])
                watch_file.seek(self.old_position)
                line = watch_file.read()
                self.old_position = watch_file.tell()
                watch_file.close()
                self.write_message(message.log(line if line else ''))
                if build['is_finished']:
                    close(message.finish(build['state']))
        try:
            self.watch_callback = PeriodicCallback(watch_build, 1000)
            self.watch_callback.start()
        except Exception as e:
            close(message.notification(str(e)))

    def on_close(self):
        self._stop_callback()

Это конечно адовый быдлокод, но как пример, думаю, подойдёт.

Kilte ★★★★★
()

Вебсокеты? https://github.com/centrifugal/centrifuge и ещё полтысячи поделок вокруг twisted и не только умеют их.

nginx умеет проксить вебсокеты, но можно и без него. uwsgi тоже умеет в вебсокеты и асинхронность, но опять же можно и без него.

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от Kilte

На торнадо это конечно все делается, но явно не так. Можно использовать

http://tornado.readthedocs.org/en/latest/process.html

Создаешь Subprocess, у него поля stdout, stderr - за ними можно следить в асинхронной манере - как только появятся новые данные они появятся в соответствующем калбеке.

Vovka-Korovka ★★★★★
()
Ответ на: комментарий от Vovka-Korovka

Да, действительно не к месту. У меня просто задача хоть и похожа, но немного другая. Там я не могу взять и запустить какой-то процесс из торнадо. Этим занимается другое приложение (воркер, если можно так сказать) и ничего не остаётся, кроме как смотреть в лог.

Почему-то подумал, что может и это подойти.

Kilte ★★★★★
()

У меня работает так:
Простой вариант: В торнадо создан отдельный вебсокет-хэндлер; при старте приложения запускается тред, опрашивающий очередь сообщений, который разбирает сообщение и шлет кому положено.
Продвинутый вариант: С помощью этого.

winlook38 ★★
()

вебсокеты уже предложили ? в асинхио это даже встроено есть, есть отдельная либа в PyPI с готовыми хэдшейками

Dred ★★★★★
()
Последнее исправление: Dred (всего исправлений: 1)

EventSource

Я думаю что на питоне такое тоже можно организовать.

use Mojolicious::Lite;

# Template with browser-side code
get '/' => 'index';

# EventSource for log messages
get '/events' => sub {
  my $c = shift;

  # Increase inactivity timeout for connection a bit
  $c->inactivity_timeout(300);

  # Change content type
  $c->res->headers->content_type('text/event-stream');

  # Subscribe to "message" event and forward "log" events to browser
  my $cb = $c->app->log->on(message => sub {
    my ($log, $level, @lines) = @_;
    $c->write("event:log\ndata: [$level] @lines\n\n");
  });

  # Unsubscribe from "message" event again once we are done
  $c->on(finish => sub {
    my $c = shift;
    $c->app->log->unsubscribe(message => $cb);
  });
};

app->start;
__DATA__

@@ index.html.ep
<!DOCTYPE html>
<html>
  <head><title>LiveLog</title></head>
  <body>
    <script>
      var events = new EventSource('<%= url_for 'events' %>');

      // Subscribe to "log" event
      events.addEventListener('log', function(event) {
        document.body.innerHTML += event.data + '<br/>';
      }, false);
    </script>
  </body>
</html>

kilolife ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.