Prepara l'architettura multi-nodo (MediaMTX+ffmpeg) con assignment URL per sessione, admin di provision/drain e provider Cloud/DNS astratti verso mltv-stream.net. Co-authored-by: Cursor <cursoragent@cursor.com>
58 lines
1.7 KiB
Ruby
58 lines
1.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Streams
|
|
# Assegna un StreamNode a una nuova sessione (least-loaded tra i ready).
|
|
# Garantisce il nodo "home" derivato dagli ENV MediaMTX attuali.
|
|
class NodeRegistry
|
|
class NoCapacityError < StandardError; end
|
|
|
|
HOME_SLUG = "home"
|
|
|
|
class << self
|
|
def ensure_home_from_env!
|
|
StreamNode.find_or_initialize_by(slug: HOME_SLUG).tap do |node|
|
|
node.assign_attributes(
|
|
hostname: home_hostname,
|
|
role: "home",
|
|
status: "ready",
|
|
provider: "local",
|
|
rtmp_base_url: MatchLiveTv.mediamtx_rtmp_url,
|
|
hls_base_url: MatchLiveTv.hls_public_url,
|
|
api_base_url: MatchLiveTv.mediamtx_api_url,
|
|
internal_rtmp_url: ENV.fetch("MEDIAMTX_INTERNAL_RTMP_URL", "rtmp://mediamtx:1935"),
|
|
internal_hls_url: ENV.fetch("MEDIAMTX_HLS_URL", "http://mediamtx:8888"),
|
|
max_publishers: ENV.fetch("STREAM_NODE_HOME_MAX_PUBLISHERS", "6").to_i,
|
|
max_relays: ENV.fetch("STREAM_NODE_HOME_MAX_RELAYS", "6").to_i
|
|
)
|
|
node.save!
|
|
end
|
|
end
|
|
|
|
def allocate!
|
|
ensure_home_from_env!
|
|
|
|
node = StreamNode.ready
|
|
.to_a
|
|
.select(&:allocatable?)
|
|
.min_by { |n| [n.active_publishers, n.role == "home" ? 1 : 0, n.slug] }
|
|
|
|
raise NoCapacityError, "Nessun nodo streaming con slot liberi" if node.nil?
|
|
|
|
node
|
|
end
|
|
|
|
private
|
|
|
|
def home_hostname
|
|
ENV["STREAM_NODE_HOME_HOSTNAME"].presence ||
|
|
begin
|
|
uri = URI.parse(MatchLiveTv.mediamtx_rtmp_url.sub(/\Artmps?:\/\//, "http://"))
|
|
uri.host.presence
|
|
rescue URI::InvalidURIError
|
|
nil
|
|
end || "home"
|
|
end
|
|
end
|
|
end
|
|
end
|