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.



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

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.



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

def real_socket
  @real_socket
end

Instance Method Details

#closeObject



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

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)


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

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

#flushObject



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

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.



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

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.



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

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

  @writer_ctx.enqueue(bytes)
  bytes.bytesize
end