Class: ReactOnRails::Dev::PortSelector
- Inherits:
-
Object
- Object
- ReactOnRails::Dev::PortSelector
- Defined in:
- lib/react_on_rails/dev/port_selector.rb
Defined Under Namespace
Classes: NoPortAvailable
Constant Summary collapse
- DEFAULT_RAILS_PORT =
3000- DEFAULT_WEBPACK_PORT =
3035- MAX_ATTEMPTS =
100
Class Method Summary collapse
- .find_available_port(start_port, exclude: nil) ⇒ Object
-
.port_available?(port) ⇒ Boolean
Public so it can be stubbed in tests.
-
.select_ports ⇒ Object
Returns { rails: Integer, webpack: Integer }.
Class Method Details
.find_available_port(start_port, exclude: nil) ⇒ Object
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/react_on_rails/dev/port_selector.rb', line 55 def find_available_port(start_port, exclude: nil) MAX_ATTEMPTS.times do |i| port = start_port + i next if port == exclude return port if port_available?(port) end raise NoPortAvailable, "No available port found starting at #{start_port}." end |
.port_available?(port) ⇒ Boolean
Public so it can be stubbed in tests. NOTE: Inherent TOCTOU race — another process can claim the port between server.close and the caller binding to it. This is unavoidable with the probe-then-use pattern and acceptable for the worktree port-selection use case.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/react_on_rails/dev/port_selector.rb', line 40 def port_available?(port) # Check both IPv4 and IPv6 loopback. Node 22+ resolves "localhost" # to ::1 first, so webpack-dev-server often binds only to IPv6. # A pure-IPv4 probe would miss that listener. %w[127.0.0.1 ::1].all? do |host| server = TCPServer.new(host, port) server.close true rescue Errno::EADDRINUSE, Errno::EACCES false rescue Errno::EADDRNOTAVAIL, SocketError true # address family unavailable on this system end end |
.select_ports ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/react_on_rails/dev/port_selector.rb', line 18 def select_ports rails_port = explicit_rails_port webpack_port = explicit_webpack_port rails_auto = rails_port.nil? webpack_auto = webpack_port.nil? rails_port ||= find_available_port(DEFAULT_RAILS_PORT, exclude: webpack_port) webpack_port ||= find_available_port(DEFAULT_WEBPACK_PORT, exclude: rails_port) if (rails_auto && rails_port != DEFAULT_RAILS_PORT) || (webpack_auto && webpack_port != DEFAULT_WEBPACK_PORT) puts "Default ports in use. Using Rails :#{rails_port}, webpack :#{webpack_port}" end { rails: rails_port, webpack: webpack_port } end |