Class: Gienah::Instance

Inherits:
Object
  • Object
show all
Defined in:
lib/gienah/host.rb,
sig/gienah.rbs

Constant Summary collapse

STATES =
i[inactive starting ready stopping failed].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, manifest) ⇒ Instance

Returns a new instance of Instance.



219
220
221
222
223
224
225
226
227
# File 'lib/gienah/host.rb', line 219

def initialize(host, manifest)
  @host = host
  @manifest = manifest
  @id = manifest.id
  @state = :inactive
  @lock = Mutex.new
  @pending = {}
  @next_id = 0
end

Instance Attribute Details

#id ⇒ String (readonly)

Returns the value of attribute id.

Returns:

  • (String)


217
218
219
# File 'lib/gienah/host.rb', line 217

def id
  @id
end

#manifest ⇒ Manifest (readonly)

Returns the value of attribute manifest.

Returns:



217
218
219
# File 'lib/gienah/host.rb', line 217

def manifest
  @manifest
end

#state ⇒ Symbol (readonly)

Returns the value of attribute state.

Returns:

  • (Symbol)


217
218
219
# File 'lib/gienah/host.rb', line 217

def state
  @state
end

Instance Method Details

#call(method, params = {}, timeout: nil) ⇒ Future

Parameters:

  • method (String)
  • params (json) (defaults to: {})
  • timeout: (Numeric, nil) (defaults to: nil)

Returns:



250
251
252
253
# File 'lib/gienah/host.rb', line 250

def call(method, params = {}, timeout: nil)
  ensure_ready!
  request(method, params, timeout: timeout)
end

#granted?(capability) ⇒ Boolean

Parameters:

  • capability (String)

Returns:

  • (Boolean)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/gienah/host.rb', line 261

def granted?(capability)
  requested = capability.to_s
  return true if @manifest.capabilities.include?(requested)

  # Reserved host-pattern capabilities are intentionally matched here so
  # applications can expose one generic method and still keep the gate
  # fail-closed for every other host.
  if requested.start_with?("net:")
    host = requested.delete_prefix("net:")
    return @manifest.capabilities.any? do |entry|
      next false unless entry.start_with?("net:")

      pattern = entry.delete_prefix("net:")
      File.fnmatch?(pattern, host, File::FNM_DOTMATCH)
    end
  end
  false
end

#kill ⇒ nil

Returns:

  • (nil)


280
281
282
283
284
285
# File 'lib/gienah/host.rb', line 280

def kill
  @lock.synchronize { @state = :inactive }
  fail_pending(Error.new("plugin terminated"))
  close_transport
  nil
end

#notify(method, params = {}) ⇒ nil

Parameters:

  • method (String)
  • params (json) (defaults to: {})

Returns:

  • (nil)


255
256
257
258
259
# File 'lib/gienah/host.rb', line 255

def notify(method, params = {})
  ensure_ready!
  @transport.write(Protocol.notification(method, params), max_size: max_message_size)
  nil
end

#restart ⇒ Object



287
288
289
290
# File 'lib/gienah/host.rb', line 287

def restart
  @lock.synchronize { @state = :inactive if @state == :failed }
  start
end

#shutdown ⇒ Object

Returns:

  • (Object)


292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/gienah/host.rb', line 292

def shutdown
  current = @lock.synchronize { @state }
  return if current == :inactive

  if current == :ready
    @lock.synchronize { @state = :stopping }
    begin
      request("shutdown", {}).await(timeout: 0.5)
    rescue StandardError
      nil
    end
  end
  kill
end

#start ⇒ Instance

Returns:



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/gienah/host.rb', line 229

def start
  transition(:starting, from: :inactive)
  @transport = @host.transport_for(self) { |message, error| receive(message, error) }
  startup_timeout = @manifest.limits.fetch("startup_timeout_ms", 5_000).to_f / 1_000
  response = request("initialize", {
    "api_version" => @host.api_version,
    "capabilities" => @manifest.capabilities,
    "host" => {"name" => "gienah", "version" => Gienah::VERSION}
  }, timeout: startup_timeout).await(timeout: startup_timeout)
  raise LifecycleError, "plugin initialization failed" unless response.is_a?(Hash)

  transition(:ready, from: :starting)
  notify("initialized", {"api_version" => @host.api_version})
  self
rescue StandardError => error
  @lock.synchronize { @state = :failed }
  @host.report_error(error, self)
  close_transport
  raise
end