Class: Pipemaster::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/pipemaster/client.rb

Overview

Pipemaster client. Use this to send commands to the Pipemaster server.

For example:

c = Pipemaster::Client.new
c.run :motd
puts c.output.string
=> "Toilet out of order please use floor below."

c = Pipemaster::Client.new(9988)
c.input = File.open("image.png")
c.output = File.open("thumbnail.png", "w")
c.run :transform, "thumbnail"

Constant Summary collapse

BUFFER_SIZE =
16 * 1024

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(address = nil) ⇒ Client

Creates a new client. Accepts optional address. If missing, uses the global address (see Pipemaster::Client::address). Address can be port number, hostname (default port), “host:port” or socket file name.

Examples:

Pipemaster::Client.new 7890
Pipemaster::Client.new "localhost:7890"
Pipemaster::Client.new


40
41
42
# File 'lib/pipemaster/client.rb', line 40

def initialize(address = nil)
  @address = expand_addr(address || Client.address || DEFAULT_LISTEN)
end

Class Attribute Details

.addressObject

Address to use by default for new clients. Leave as nil to use the default (Pipemaster::DEFAULT_LISTEN).



29
30
31
# File 'lib/pipemaster/client.rb', line 29

def address
  @address
end

Instance Attribute Details

#inputObject

Set this to supply an input stream (for commands that read from $stdin).



45
46
47
# File 'lib/pipemaster/client.rb', line 45

def input
  @input
end

#outputObject

Set this to supply an output stream, or read the output (defaults to StringIO).



49
50
51
# File 'lib/pipemaster/client.rb', line 49

def output
  @output
end

Class Method Details

.pipe(command, *args) ⇒ Object

Pipe stdin/stdout into the command. For example:

exit Pipemaster.pipe(:echo)


23
24
25
# File 'lib/pipemaster/client.rb', line 23

def pipe(command, *args)
  new.capture($stdin, $stdout).run(command, *args)
end

Instance Method Details

#capture(input, output) ⇒ Object

Captures input and output. For example:

Pipemaster.new(7890).capture($stdin, $stdout).run(:echo)


53
54
55
56
# File 'lib/pipemaster/client.rb', line 53

def capture(input, output)
  self.input, self.output = input, output
  self
end

#run(command, *args) ⇒ Object

Make a request. First argument is the command name. All other arguments are optional. Returns the exit code (usually 0). Will raise IOError if it can’t talk to the server, or the server closed the connection prematurely.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/pipemaster/client.rb', line 62

def run(command, *args)
  # Connect and send arguments.
  socket = connect(@address)
  socket.sync = true
  header = ([command] + args).join("\0")
  socket << [header.size].pack("N") << header
  socket.flush

  @output ||= StringIO.new

  # If there's input, stream it over to the socket, while streaming the
  # response back.
  inputbuf, stdoutbuf = "", ""
  if @input
    while selected = select([@input, socket])
      begin
        if selected.first.include?(@input)
          @input.readpartial(BUFFER_SIZE, inputbuf)
          socket.write inputbuf
        elsif selected.first.include?(socket)
          raise IOError, "Server closed socket" if socket.eof?
          @output.write stdoutbuf if stdoutbuf
          stdoutbuf = socket.readpartial(BUFFER_SIZE)
        end
      rescue EOFError
        break
      end
    end
  end
  socket.close_write # tell other side there's no more input

  # Read remaining response and stream to output.  Remember that very last
  # byte is return code.
  while selected = select([socket])
    break if socket.eof?
    @output.write stdoutbuf if stdoutbuf
    stdoutbuf = socket.readpartial(BUFFER_SIZE)
  end
  if stdoutbuf && stdoutbuf.size > 0
    status = stdoutbuf[-1]
    @output.write stdoutbuf[0..-2]
    return status.ord
  else
    raise IOError, "Server closed socket" if socket.eof?
  end
ensure
  socket.close rescue nil
end