0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 21:57:36 +08:00
discourse/lib/freedom_patches/final_destination_connect.rb
Gerhard Schlager 6b89982a91 FIX: Keep TCPServer.open(port) working with the Happy Eyeballs patch
The Happy Eyeballs patch prepends an `open` singleton method onto TCPSocket, and TCPServer inherits it because TCPServer < TCPSocket. With a fixed host/port signature, `TCPServer.open(port)` raised ArgumentError before `super` could run. That broke TemporaryDb#port_available? and, in turn, the migrations tooling's `disco check` plugin-manifest refresh. The patched `open` now takes *args and forwards the caller's arguments untouched to `super` for non-token hosts, so subclasses with looser signatures keep working.
2026-07-22 09:05:38 +02:00

50 lines
1.7 KiB
Ruby
Vendored

# frozen_string_literal: true
# Patch getaddrinfo to recognize `FinalDestination::Connector` tokens
# and return their IPs instead of doing a true lookup.
module FinalDestinationAddrinfoPatch
def getaddrinfo(nodename, service, family = nil, *args, **kwargs)
return super unless FinalDestination::Connector.token?(nodename)
ips =
FinalDestination::Connector.addresses_for_family(
FinalDestination::Connector.addresses(nodename),
family,
)
raise SocketError, "getaddrinfo: Address family for hostname not supported" if ips.empty?
ips.map { |ip| Addrinfo.tcp(ip, service.to_i) }
end
end
# TCPSocket.open uses a C-based implementation by default, which would bypass our
# getaddrinfo patch. Instead, open the socket with `Socket.tcp`, then set up a `TCPSocket`
# instance with the result.
module FinalDestinationTCPSocketPatch
# Takes *args because TCPServer inherits this singleton method and
# `TCPServer.open(port)` has fewer arguments — a fixed host/port signature
# fails the arity check before `super` can run. A bare `super` forwards the
# original arguments untouched.
def open(*args, **kwargs)
host = args[0]
return super unless FinalDestination::Connector.token?(host)
_, port, local_host, local_port = args
socket =
Socket.tcp(
host,
port,
local_host,
local_port,
connect_timeout: kwargs[:open_timeout],
fast_fallback: true,
)
socket.autoclose = false # Let the TCPSocket handle closing
TCPSocket.for_fd(socket.fileno)
end
end
Addrinfo.singleton_class.prepend(FinalDestinationAddrinfoPatch)
TCPSocket.singleton_class.prepend(FinalDestinationTCPSocketPatch)