Class: Harnex::Adapters::CodexAppServer::JsonRpcClient

Inherits:
Object
  • Object
show all
Defined in:
lib/harnex/adapters/codex_appserver.rb

Overview

Minimal JSON-RPC 2.0 client. One JSON object per line. Responses keyed by id; everything else is a notification.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(read_io:, write_io:, pid: nil) ⇒ JsonRpcClient

Returns a new instance of JsonRpcClient.



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/harnex/adapters/codex_appserver.rb', line 322

def initialize(read_io:, write_io:, pid: nil)
  @read_io = read_io
  @write_io = write_io
  @pid = pid
  @next_id = 1
  @pending = {}
  @id_mutex = Mutex.new
  @write_mutex = Mutex.new
  @notification_handler = nil
  @request_handler = nil
  @disconnect_handler = nil
  @disconnect_signaled = false
  @closed = false
  @reader_thread = nil
end

Instance Attribute Details

#pidObject (readonly)

Returns the value of attribute pid.



320
321
322
# File 'lib/harnex/adapters/codex_appserver.rb', line 320

def pid
  @pid
end

Instance Method Details

#closeObject



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/harnex/adapters/codex_appserver.rb', line 381

def close
  return if @closed

  @closed = true

  @id_mutex.synchronize do
    @pending.each_value { |q| q.push(StandardError.new("codex_appserver client closed")) }
    @pending.clear
  end

  begin
    @write_io.close unless @write_io.closed?
  rescue IOError
    nil
  end

  if @pid && process_alive?(@pid)
    sleep 0.05
    begin
      Process.kill("TERM", @pid)
    rescue Errno::ESRCH
      nil
    end
  end

  @reader_thread&.join(2)
end

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



375
376
377
378
379
# File 'lib/harnex/adapters/codex_appserver.rb', line 375

def notify(method, params = {})
  return if @closed

  write_line({ jsonrpc: "2.0", method: method, params: params })
end

#on_disconnect(&block) ⇒ Object



349
350
351
# File 'lib/harnex/adapters/codex_appserver.rb', line 349

def on_disconnect(&block)
  @disconnect_handler = block
end

#on_notification(&block) ⇒ Object



338
339
340
# File 'lib/harnex/adapters/codex_appserver.rb', line 338

def on_notification(&block)
  @notification_handler = block
end

#on_request(&block) ⇒ Object

Handler for server-initiated requests (id + method). The block receives (method, params) and returns the response body for the JSON-RPC ‘result` field, or nil to reject with -32601.



345
346
347
# File 'lib/harnex/adapters/codex_appserver.rb', line 345

def on_request(&block)
  @request_handler = block
end

#request(method, params = {}) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/harnex/adapters/codex_appserver.rb', line 357

def request(method, params = {})
  raise "codex_appserver client is closed" if @closed

  queue = Queue.new
  id = @id_mutex.synchronize do
    assigned = @next_id
    @next_id += 1
    @pending[assigned] = queue
    assigned
  end

  write_line({ jsonrpc: "2.0", id: id, method: method, params: params })
  result = queue.pop
  raise result if result.is_a?(Exception)

  result
end

#startObject



353
354
355
# File 'lib/harnex/adapters/codex_appserver.rb', line 353

def start
  @reader_thread = Thread.new { read_loop }
end

#terminate_process(term_grace_seconds:, kill_grace_seconds:) ⇒ Object



409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/harnex/adapters/codex_appserver.rb', line 409

def terminate_process(term_grace_seconds:, kill_grace_seconds:)
  return false unless @pid

  begin
    Process.kill("TERM", @pid)
  rescue Errno::ESRCH
    return true
  end

  return true if wait_for_process_exit(@pid, term_grace_seconds)

  begin
    Process.kill("KILL", @pid)
  rescue Errno::ESRCH
    return true
  end

  wait_for_process_exit(@pid, kill_grace_seconds)
end