Предоставление консольных приложений в Интернете с помощью Ruby - PullRequest
0 голосов
/ 28 февраля 2010

Я хочу представить интерактивную программу командной строки через JSON или другой сервис в стиле RPC, используя Ruby. Я нашел несколько приемов, чтобы сделать это, но я что-то упускаю при перенаправлении вывода и ввода.

Один из способов, по крайней мере, в linux - перенаправить stdin и stdout в файл, а затем читать и записывать в этот файл асинхронно с чтением и записью файла. Другой метод, который я пробовал после поиска в Google, заключался в использовании open4. Вот код, который я написал до сих пор, но он застрял после прочтения нескольких строк из стандартного вывода.

require "open4"
include Open4

status = popen4("./srcds_run -console -game tf +map ctf_2fort -maxplayers 6") do |pid, stdin, stdout, stderr|
  puts "PID #{pid}"
  lines=""
  while (line=stdout.gets)
    lines+=line
    puts line
  end
  while (line=stderr.gets)
    lines+=line
    puts line
  end
end

Любая помощь в этом или некоторые идеи будут оценены!

Ответы [ 3 ]

0 голосов
/ 28 февраля 2010

EDIT

Вы должны рассмотреть возможность интеграции с AnyTerm . Затем вы можете либо выставить AnyTerm напрямую, например, через Apache mod_proxy или ваш контроллер Rails будет выступать в качестве обратного прокси-сервера (обрабатывает аутентификацию / проверку сеанса, затем воспроизводит controller.request минус любые куки-файлы до localhost:<AnyTerm-daemon-port> и отправляет обратно в качестве ответа любой ответ AnyTerm.)

class ConsoleController < ApplicationController
  # AnyTerm speaks via HTTP POST only
  def update
    # validate session
    ...
    # forward request to AnyTerm
    response = Net::HTTP.post_form(URI.parse('http://localhost:#{AnyTermPort}/', request.params))
    headers['Content-Type'] = response['Content-Type']
    render_text response.body, response.status
  end

В противном случае вам нужно будет использовать IO :: Select или IO :: read_noblock , чтобы узнать, когда доступны данные для чтения (из сети или подпроцесса), чтобы вы могли не тупик. Смотрите это тоже. Также убедитесь, что ваш Rails используется в многопоточной среде или , что на вашу версию Ruby не влияет эта ошибка IO :: Select .

Вы можете начать с чего-то такого:

status = POpen4::popen4("ping localhost") do |stdout, stderr, stdin, pid|  
  puts "PID #{pid}"  
  # our buffers 
  stdout_lines="" 
  stderr_lines=""
  begin
    loop do
      # check whether stdout, stderr or both are 
      #  ready to be read from without blocking 
      IO.select([stdout,stderr]).flatten.compact.each { |io|
        # stdout, if ready, goes to stdout_lines 
        stdout_lines += io.readpartial(1024) if io.fileno == stdout.fileno 
        # stderr, if ready, goes to stdout_lines 
        stderr_lines += io.readpartial(1024) if io.fileno == stderr.fileno 
      }
      break if stdout.closed? && stderr.closed? 
      # if we acumulated any complete lines (\n-terminated) 
      #  in either stdout/err_lines, output them now 
      stdout_lines.sub!(/.*\n/m) { puts $& ; '' } 
      stderr_lines.sub!(/.*\n/m) { puts $& ; '' } 
    end
  rescue EOFError
    puts "Done"
  end 
end 

Для обработки stdin, измените на:

      IO.select([stdout,stderr],[stdin]).flatten.compact.each { |io|
        # program ready to get stdin? do we have anything for it?
        if io.fileno == stdin.fileno && <got data from client?>
          <write a small chunk from client to stdin>
        end
        # stdout, if ready, goes to stdout_lines 
0 голосов
/ 28 февраля 2010

Другой трюк, который вы можете попробовать, - перенаправить stderr в стандартный вывод вашей команды, чтобы ваша программа могла только читать стандартный вывод. Примерно так:

popen4("./srcds_run -console -game tf +map ctf_2fort -maxplayers 6 2>&1")

Другим преимуществом этого является то, что вы получаете все сообщения / ошибки в порядке, в котором они происходят во время выполнения программы.

0 голосов
/ 28 февраля 2010

Я бы порекомендовал использовать Xinetd (или аналогичный) для запуска команды на каком-либо сокете, а затем использовать сетевой код ruby. Одна из проблем, с которой вы уже столкнулись в своем коде, заключается в том, что два цикла while являются последовательными, что может вызвать проблемы.

...