Module: RightScale::Windows::PipeServerHandler

Defined in:
lib/chef/windows/pipe_server.rb

Overview

Provides an eventmachine callback handler for the server pipe.

Constant Summary collapse

CONNECTING_STATE =

state between client connections

0
READING_STATE =

after connection, receiving request

1
RESPONDING_STATE =

received request, calculating response

2
WRITING_STATE =

calculated response, respond before disconnecting

3
WAIT_SLEEP_DELAY_MSECS =

yield to avoid busy looping

0.001
ASYNC_IO_SLEEP_DELAY_MSECS =

yield to allow async I/O time to process

0.01

Instance Method Summary collapse

Instance Method Details

#force_detachObject

Forces detachment of the handler unless already unbound.



102
103
104
105
106
107
# File 'lib/chef/windows/pipe_server.rb', line 102

def force_detach
  # No need to use next tick to prevent issue in EM where
  # descriptors list gets out-of-sync when calling detach
  # in an unbind callback
  detach unless @unbound
end

#initialize(options) ⇒ Object

Parameters

options(Hash)

A hash containing the following options by token name:

target(Object)

Object defining handler methods to be called (required).

request_handler(Token)

Token for request handler method name (required).

request_query(Token)

Token for request query method name if server

needs time to calculate a response (allows event loop to continue until such time as request_query returns true).

pipe(IO)

pipe object (required).



54
55
56
57
58
59
60
61
62
# File 'lib/chef/windows/pipe_server.rb', line 54

def initialize(options)
  raise "Missing required :target" unless @target = options[:target]
  raise "Missing required :request_handler" unless @request_handler = options[:request_handler]
  raise "Missing require :pipe" unless @pipe = options[:pipe]
  @request_query = options[:request_query]
  @unbound = false
  @state = CONNECTING_STATE
  @data = nil
end

#notify_readableObject

Callback from EM to asynchronously read the pipe stream. Note that this callback mechanism is deprecated after EM v0.12.8



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/chef/windows/pipe_server.rb', line 66

def notify_readable
  if @state == RESPONDING_STATE || @pipe.wait(WAIT_SLEEP_DELAY_MSECS)
    if @pipe.pending?
      handle_pending
    else
      handle_non_pending
    end

    # sleep a little to allow asynchronous I/O time to complete and
    # avoid busy looping.
    sleep ASYNC_IO_SLEEP_DELAY_MSECS
  end
rescue Exception => e
  RightScale::Log.error("Failed to send data to Powershell", e, :trace)
  (disconnect rescue nil) if @state != CONNECTING_STATE
end

#receive_data(data) ⇒ Object

Callback from EM to receive data, which we also use to handle the asynchronous data we read ourselves.



85
86
87
88
89
90
# File 'lib/chef/windows/pipe_server.rb', line 85

def receive_data(data)
  # automagically append a newlineto make it easier to parse response.
  result = @target.method(@request_handler).call(data)
  result += "\n" unless result[-1] == "\n"[0]
  return result
end

#unbindObject

Callback from EM to unbind.



93
94
95
96
97
98
99
# File 'lib/chef/windows/pipe_server.rb', line 93

def unbind
  Log.debug("unbound")
  @pipe.close rescue nil
  @connected = false
  @pipe = nil
  @unbound = true
end