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.



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

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.



84
85
86
# File 'lib/hyperion/http2_handler.rb', line 84

def real_socket
  @real_socket
end

Instance Method Details

#closeObject



114
115
116
# File 'lib/hyperion/http2_handler.rb', line 114

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)


122
123
124
125
# File 'lib/hyperion/http2_handler.rb', line 122

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

#flushObject



108
109
110
111
112
# File 'lib/hyperion/http2_handler.rb', line 108

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.



93
94
95
# File 'lib/hyperion/http2_handler.rb', line 93

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.



101
102
103
104
105
106
# File 'lib/hyperion/http2_handler.rb', line 101

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

  @writer_ctx.enqueue(bytes)
  bytes.bytesize
end