Class: Hyperion::Http2Handler::SendQueueIO

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperion/http2_handler.rb

Overview

IO-shaped wrapper passed to ‘Protocol::HTTP2::Framer` in place of the real socket. Reads are direct passthroughs (the read loop runs on the connection fiber and there’s only one reader). Writes are enqueued onto the connection-wide ‘WriterContext#queue`; the writer fiber owns the real socket and drains the queue.

We deliberately do NOT delegate ‘flush` to the real socket: writes don’t reach it from this object — the writer fiber does that. ‘flush` here is a no-op (the writer flushes after each batch).

‘closed?` reports the real socket’s state so protocol-http2’s read loop sees EOF the same way it always has.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(real_socket, writer_ctx) ⇒ SendQueueIO

Returns a new instance of SendQueueIO.



88
89
90
91
# File 'lib/hyperion/http2_handler.rb', line 88

def initialize(real_socket, writer_ctx)
  @real_socket = real_socket
  @writer_ctx  = writer_ctx
end

Instance Attribute Details

#real_socketObject (readonly)

Returns the value of attribute real_socket.



86
87
88
# File 'lib/hyperion/http2_handler.rb', line 86

def real_socket
  @real_socket
end

Instance Method Details

#closeObject



116
117
118
# File 'lib/hyperion/http2_handler.rb', line 116

def close
  @real_socket.close unless @real_socket.closed?
end

#closed?Boolean

Multi-line on purpose: a single-line ‘def closed?; @real_socket.closed?; end` gets autocorrected to `delegate :closed?, to: :@real_socket` by Rails-aware ruby-lsp formatters, which is wrong here (this is a plain gem, no ActiveSupport on the dependency graph).

Returns:

  • (Boolean)


124
125
126
127
# File 'lib/hyperion/http2_handler.rb', line 124

def closed?
  socket = @real_socket
  socket.closed?
end

#flushObject



110
111
112
113
114
# File 'lib/hyperion/http2_handler.rb', line 110

def flush
  # No-op: bytes don't live in this object, they live in the queue.
  # The writer fiber flushes the real socket as it drains.
  nil
end

#read(*args) ⇒ Object

Framer’s read path — direct delegation. Single-reader (the conn fiber), so no contention here.



95
96
97
# File 'lib/hyperion/http2_handler.rb', line 95

def read(*args)
  @real_socket.read(*args)
end

#write(bytes) ⇒ Object

Framer’s write path — non-blocking handoff into the send queue. Backpressure is applied here: if pending bytes exceed the cap, the calling fiber parks on the drained notification until the writer has flushed enough to bring us below the threshold.



103
104
105
106
107
108
# File 'lib/hyperion/http2_handler.rb', line 103

def write(bytes)
  return 0 if bytes.nil? || bytes.empty?

  @writer_ctx.enqueue(bytes)
  bytes.bytesize
end