Class: QB::IPC::RPC::Server

Inherits:
Object
  • Object
show all
Includes:
NRSER::Log::Mixin
Defined in:
lib/qb/ipc/rpc/server.rb

Constant Summary collapse

CONTENT_TYPE_JSON =

Constants

{ 'Content-Type' => 'application/json' }.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeServer

Instantiate a new Server.



130
131
132
133
134
# File 'lib/qb/ipc/rpc/server.rb', line 130

def initialize
  @socket_dir = Dir.mktmpdir( 'qb-ipc-rpc' ).to_pn
  @socket_path = socket_dir + 'socket'
  @http_server = ::Unicorn::HttpServer.new self, listeners: socket_path.to_s
end

Instance Attribute Details

#http_serverUnicorn::HTTPServer (readonly)

TODO document http_server attribute.

Returns:

  • (Unicorn::HTTPServer)


123
124
125
# File 'lib/qb/ipc/rpc/server.rb', line 123

def http_server
  @http_server
end

#socket_dirPathname (readonly)

Temp dir where the socket goes.

Returns:

  • (Pathname)


109
110
111
# File 'lib/qb/ipc/rpc/server.rb', line 109

def socket_dir
  @socket_dir
end

#socket_pathPathname (readonly)

Absolute path to the socket file.

Returns:

  • (Pathname)


116
117
118
# File 'lib/qb/ipc/rpc/server.rb', line 116

def socket_path
  @socket_path
end

Class Method Details

.instancereturn_type

TODO:

Document instance method.

Returns @todo Document return value.

Parameters:

  • arg_name (type)

    @todo Add name param description.

Returns:

  • (return_type)

    @todo Document return value.



66
67
68
# File 'lib/qb/ipc/rpc/server.rb', line 66

def self.instance
  @instance
end

.run_around(&block) ⇒ return_type

TODO:

Document run! method.

Returns @todo Document return value.

Parameters:

  • arg_name (type)

    @todo Add name param description.

Returns:

  • (return_type)

    @todo Document return value.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/qb/ipc/rpc/server.rb', line 78

def self.run_around &block
  unless ENV[QB::IPC::RPC::ENV_VAR_NAME].to_s == ''
    raise NRSER::ConflictError.new \
      "RPC ENV var already set",
      var_name:   QB::IPC::RPC::ENV_VAR_NAME,
      var_value:  ENV[QB::IPC::RPC::ENV_VAR_NAME]
  end

  @instance = new.start!

  ENV[QB::IPC::RPC::ENV_VAR_NAME] = instance.socket_path.to_s

  begin
    block_result = block.call
  ensure
    instance.stop!
    @instance = nil
    ENV.delete QB::IPC::RPC::ENV_VAR_NAME
  end

  block_result
end

Instance Method Details

#call(env) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/qb/ipc/rpc/server.rb', line 251

def call env
  begin
    request = Rack::Request.new env
    body = request.body.read
    payload = JSON.load body

    logger.trace "Received request",
      path: request.path,
      body: body,
      payload: payload
    
    route request.path, payload
    
  rescue StandardError => error
    logger.error "Error processing request",
      { request: request },
      error
    
    respond_error message: error.message
  end
end

#handle_plugins_filtersObject



191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/qb/ipc/rpc/server.rb', line 191

def handle_plugins_filters
  map = {}
  
  QB::Ansible::Plugins::Filters.methods( false ).each { |method|
    map[method] = {
      receiver: 'QB::Ansible::Plugins::Filters',
      method:   method.to_s,
    }
  }
  
  respond_ok data: map
end

#handle_send(payload) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/qb/ipc/rpc/server.rb', line 205

def handle_send payload
  receiver = payload.fetch 'receiver'
  method = payload.fetch 'method'
  args = payload.fetch 'args', []

  if payload['kwds'] && !payload['kwds'].empty?
    args = [*args, payload['kwds'].to_options]
  end

  logger.trace "Unpacked /send payload",
    receiver: receiver,
    method: method,
    args: args

  if  Hash === receiver &&
      receiver.key?( NRSER::Props::DEFAULT_CLASS_KEY )
    
    logger.trace "Loading payload into a " + 
      "#{ receiver[NRSER::Props::DEFAULT_CLASS_KEY] }..."

    receiver = NRSER::Props.UNSAFE_load_instance_from_data receiver
  elsif   String === receiver &&
          receiver =~ /\A(?:(?:\:\:)?[A-Z]\w*)+\z/
    if (const = receiver.to_const)
      receiver = const
    end
  end

  logger.trace "Sending...",
    receiver: receiver,
    method: method,
    args: args

  # For some reason this doesn't work:
  # result = receiver.send method, *args, **kwds
  # 
  # So we do this (after conditionally appending kwds up top)
  result = receiver.send method, *args

  logger.trace "Got result, responding",
    result: result

  respond_ok data: result
end

#respond(code, values = {}) ⇒ Object



152
153
154
155
156
157
158
159
160
161
# File 'lib/qb/ipc/rpc/server.rb', line 152

def respond code, values = {}
  [
    code.to_s,
    CONTENT_TYPE_JSON,
    [ values.to_json ]
].tap { |response|
  logger.trace "Responding",
    response: response
}
end

#respond_error(code: 500, message: 'Server error') ⇒ Object



169
170
171
# File 'lib/qb/ipc/rpc/server.rb', line 169

def respond_error code: 500, message: 'Server error'
  respond code, message: message
end

#respond_not_found(message: 'Not found') ⇒ Object



174
175
176
# File 'lib/qb/ipc/rpc/server.rb', line 174

def respond_not_found message: 'Not found'
  respond 404, message: message
end

#respond_ok(values = {}) ⇒ Object



164
165
166
# File 'lib/qb/ipc/rpc/server.rb', line 164

def respond_ok values = {}
  respond 200, values
end

#route(path, payload) ⇒ Object



179
180
181
182
183
184
185
186
187
188
# File 'lib/qb/ipc/rpc/server.rb', line 179

def route path, payload
  case path
  when '/send'
    handle_send payload
  when '/plugins/filters'
    handle_plugins_filters
  else
    respond_not_found
  end
end

#start!Object

Instance Methods



140
141
142
143
# File 'lib/qb/ipc/rpc/server.rb', line 140

def start!
  http_server.start
  self
end

#stop!(graceful: true) ⇒ Object



146
147
148
149
# File 'lib/qb/ipc/rpc/server.rb', line 146

def stop! graceful: true
  http_server.stop graceful
  self
end