Class: WebConsole::Slave

Inherits:
Object
  • Object
show all
Defined in:
lib/web_console/slave.rb

Overview

Slave\ Process\ Wrapper

Creates and communicates with slave processses.

The communication happens through an input with attached psuedo-terminal. All of the communication is done in asynchrouns way, meaning that when you send input to the process, you have get the output by polling for it.

Constant Summary collapse

READING_ON_CLOSED_END_ERRORS =

Different OS’ and platforms raises different errors when trying to read on output end of a closed process.

[ Errno::EIO, EOFError ]
Closed =

Raised when trying to read from a closed (exited) process.

Class.new(IOError)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command = WebConsole.config.command, options = {}) ⇒ Slave

Returns a new instance of Slave.



23
24
25
26
27
28
# File 'lib/web_console/slave.rb', line 23

def initialize(command = WebConsole.config.command, options = {})
  using_term(options[:term] || WebConsole.config.term) do
    @output, @input, @pid = PTY.spawn(command.to_s)
  end
  configure(options)
end

Instance Attribute Details

#pidObject (readonly)

The slave process id.



21
22
23
# File 'lib/web_console/slave.rb', line 21

def pid
  @pid
end

Instance Method Details

#configure(options = {}) ⇒ Object

Configure the psuedo terminal properties.

Options:

:width  The width of the terminal in number of columns.
:height The height of the terminal in number of rows.

If any of the width or height is missing (or zero), the termininal size won’t be set.



38
39
40
41
# File 'lib/web_console/slave.rb', line 38

def configure(options = {})
  dimentions = options.values_at(:height, :width).collect(&:to_i)
  @input.winsize = dimentions unless dimentions.any?(&:zero?)
end

#dispose(options = {}) ⇒ Object

Dispose the underlying process, sending SIGTERM.

After the process is disposed, it is detached from the parent to prevent zombies.

If the process is already disposed an Errno::ESRCH will be raised and handled internally. If you want to handle Errno::ESRCH yourself, pass {raise: true} as options.

Returns a thread, which can be used to wait for the process termination.



96
97
98
# File 'lib/web_console/slave.rb', line 96

def dispose(options = {})
  dispose_with(:SIGTERM, options)
end

#dispose!(options = {}) ⇒ Object

Dispose the underlying process, sending SIGKILL.

After the process is disposed, it is detached from the parent to prevent zombies.

If the process is already disposed an Errno::ESRCH will be raised and handled internally. If you want to handle Errno::ESRCH yourself, pass {raise: true} as options.

Returns a thread, which can be used to wait for the process termination.



110
111
112
# File 'lib/web_console/slave.rb', line 110

def dispose!(options = {})
  dispose_with(:SIGKILL, options)
end

#pending_output(chunk_len = 49152) ⇒ Object

Gets the pending output of the process.

The pending output is read in an non blocking way by chunks, in the size of chunk_len. By default, chunk_len is 49152 bytes.

Returns nil, if there is no pending output at the moment. Otherwise, returns the output that hasn’t been read since the last invocation.

Raises Errno:EIO on closed output stream. This can happen if the underlying process exits.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/web_console/slave.rb', line 71

def pending_output(chunk_len = 49152)
  # Returns nil if there is no pending output.
  return unless pending_output?

  pending = String.new
  while chunk = @output.read_nonblock(chunk_len)
    pending << chunk
  end
  pending.force_encoding('UTF-8')
rescue IO::WaitReadable
  pending.force_encoding('UTF-8')
rescue
  raise Closed if READING_ON_CLOSED_END_ERRORS.any? { |exc| $!.is_a?(exc) }
end

#pending_output?(timeout = WebConsole.config.timeout) ⇒ Boolean

Returns whether the slave process has any pending output in wait seconds.

By default, the timeout follows config.web_console.timeout. Usually, it is zero, making the response immediate.

Returns:

  • (Boolean)


56
57
58
59
# File 'lib/web_console/slave.rb', line 56

def pending_output?(timeout = WebConsole.config.timeout)
  # JRuby's select won't automatically coerce ActiveSupport::Duration.
  !!IO.select([@output], [], [], timeout.to_i)
end

#send_input(input) ⇒ Object

Sends input to the slave process STDIN.

Returns immediately.

Raises:

  • (ArgumentError)


46
47
48
49
# File 'lib/web_console/slave.rb', line 46

def send_input(input)
  raise ArgumentError if input.nil? or input.try(:empty?)
  input.each_char { |char| @input.putc(char) }
end