Class: Vangrail::BoundedJsonCommand

Inherits:
Object
  • Object
show all
Defined in:
lib/vangrail/bounded_json_command.rb

Overview

Bounded JSON-over-stdin subprocess transport with no implicit shell or environment.

Defined Under Namespace

Classes: OutputLimit

Constant Summary collapse

READ_CHUNK =
16 * 1024
TERMINATION_GRACE =
0.1

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command:, timeout:, max_input_bytes:, max_output_bytes:, environment: {}, inherit_environment: false, label: 'JSON command') ⇒ BoundedJsonCommand

Returns a new instance of BoundedJsonCommand.

Raises:

  • (ArgumentError)


19
20
21
22
23
24
25
26
27
28
29
# File 'lib/vangrail/bounded_json_command.rb', line 19

def initialize(command:, timeout:, max_input_bytes:, max_output_bytes:,
               environment: {}, inherit_environment: false, label: 'JSON command')
  @command = Array(command).map(&:to_s).freeze
  @timeout = positive_number(timeout, 'timeout')
  @max_input_bytes = positive_integer(max_input_bytes, 'max_input_bytes')
  @max_output_bytes = positive_integer(max_output_bytes, 'max_output_bytes')
  @environment = environment.to_h { |name, value| [name.to_s, value.to_s] }.freeze
  @inherit_environment = !!inherit_environment # rubocop:disable Style/DoubleNegation
  @label = label.to_s.freeze
  raise ArgumentError, 'command is required' if @command.empty? || @command.any?(&:empty?)
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def command
  @command
end

#environmentObject (readonly)

Returns the value of attribute environment.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def environment
  @environment
end

#inherit_environmentObject (readonly)

Returns the value of attribute inherit_environment.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def inherit_environment
  @inherit_environment
end

#labelObject (readonly)

Returns the value of attribute label.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def label
  @label
end

#max_input_bytesObject (readonly)

Returns the value of attribute max_input_bytes.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def max_input_bytes
  @max_input_bytes
end

#max_output_bytesObject (readonly)

Returns the value of attribute max_output_bytes.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def max_output_bytes
  @max_output_bytes
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



16
17
18
# File 'lib/vangrail/bounded_json_command.rb', line 16

def timeout
  @timeout
end

Instance Method Details

#call(payload) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/vangrail/bounded_json_command.rb', line 31

def call(payload)
  input = JSON.generate(payload)
  raise ProtocolError, "#{label} request exceeds #{max_input_bytes} bytes" if input.bytesize > max_input_bytes

  output, status = execute(input)
  raise ProtocolError, exit_reason(status) unless status.success?

  parsed = JSON.parse(output)
  raise ProtocolError, "#{label} response must be a JSON object" unless parsed.is_a?(Hash)

  parsed
rescue JSON::GeneratorError, EncodingError => e
  raise ProtocolError, "#{label} request is not valid JSON: #{e.message}"
rescue JSON::ParserError => e
  raise ProtocolError, "#{label} returned invalid JSON: #{e.message}"
end