与正在运行的进程的交互

时间:2018-07-10 06:37:27

标签: keyboard-events interaction crystal-lang

让我们举一个简单的例子:

Process.run("ping", {"google.com"}) do |proc|
  proc.output.each_line { |line| puts line }
end

运行一个进程,不断读取其输出并将输出打印到stdout。目前,当我按下一个键时,它会与正在运行的进程的输出一起出现,但是我希望进行某种键处理,因此我可以通过键盘来管理正在运行的进程:停止它,或使用修改后的参数重新启动它。该怎么做?


或者,为了缩小问题范围,如何使该输出-输入对彼此互不阻塞?当前,它需要迈出一步,然后等待其对应事件发生。

Process.run("ping", {"google.com"}) do |proc|
  until proc.output.closed?
    puts proc.output.gets
    puts "Got key: #{STDIN.raw &.read_char}"
  end
end

2 个答案:

答案 0 :(得分:1)

使用终端进行交互式输入并不像看起来那样简单。您可以尝试使用STDIN.raw &.read_char。但这是有限的,可能不会使您走得太远。

通常用于此目的的工具是readline。 stdlib中有Crystal绑定(请参见Readline)。它们目前没有文档,但应该可以使用。您也可以尝试https://github.com/Papierkorb/fancyline,它是readline的纯Crystal实现。

答案 1 :(得分:1)

此示例显示如何处理STDIN和单个TCP会话。这通过将处理程序生成到纤维上来起作用。使用some lines more,您可以与多个客户端共享bash或REPL会话。

示例1:长时间运行的过程

#Long running Process, here an interactive shell for example
spawn do
    begin  
    cmd = "bash -i"
    Process.run(cmd, shell: true) do | p |
         pp p
         my.bashpid = p.pid
         my.bashinputfd = p.input.dup              #get copy of current fd
         p.input.puts("exec 2>&1")                 #stderr > stdout
         p.input.puts("echo connected to bash")    #send to STDIN of bash
          while line = p.output.read_line 
            puts line                     #send to STDOUT
            #send output of shell process to all online clients
            Mc.get_clients.each do |all|  
                     all.puts (line)   #send to Client
                   end  
          end
       end 

    rescue exception
      puts "Error: #{exception.message}"
      puts "Shell process has ended, program exits"
      exit
    end
end

示例2:

require "socket"
#public vars
channel = Channel(String).new
csocket = Socket.tcp(Socket::Family::INET)
socket_conn=false
puts "Welcome:"

    spawn do
      server = TCPServer.new("0.0.0.0", 9090)
      loop do   #handle tcp client reconnects - do forever
       socket = server.accept
       csocket = socket.dup
       socket_conn=true
       p! socket_conn
       print "\r"

       while line = socket.gets
         channel.send(line)
       end
       socket_conn=false
       p! socket_conn
       print "\r"
      end
    end

    spawn do  #handle stdin input char by char - do until ctrl-c pressed
        while (char = STDIN.raw &.read_char) != '\u{3}'    #ctrl-c
        channel.send(char.to_s)
        end
        channel.send('\u{3}'.to_s)
    end

    loop do  #do until cttrl-c
      r = channel.receive
      if r == "\u0003"  #handle ctrl-c from channel
         break
      end
      p! socket_conn
      print "\r"
      p! r
      print "\r"
      if socket_conn 
           csocket.puts "got: #{r}"
      end 
      puts "got: #{r}"
      print "\r"
    end