class SessionChannel < ApplicationCable::Channel include CableBroadcastable def subscribed session = resolve_session reject unless session && session.id.to_s == params[:session_id].to_s stream_for session session.device_states.find_or_create_by!(device_role: params[:device_role] || "controller") end def resolve_session if connection.regia_session connection.regia_session else StreamSession.joins(match: :team) .merge(connection.current_user.manageable_teams) .find_by(id: params[:session_id]) end end def unsubscribed stop_all_streams end def receive(data) session = resolve_session return unless session handle_message(session, data) end private def handle_message(session, data) case data["type"] when "command" SessionChannel.broadcast_message(session, data) execute_command(session, data) when "score_update" update_score(session, data) when "timeout" update_timeout(session, data) when "device_state" update_device(session, data) end end def execute_command(session, data) case data["action"] when "start_stream" Sessions::Start.new(session).call when "stop_stream" Sessions::Stop.new(session).call when "pause_stream" Sessions::Pause.new(session).call when "resume_stream" Sessions::Resume.new(session).call end end def update_score(session, data) score = session.score_state || session.create_score_state! score.update!( home_sets: data["home_sets"] || score.home_sets, away_sets: data["away_sets"] || score.away_sets, home_points: data["home_points"] || score.home_points, away_points: data["away_points"] || score.away_points, current_set: data["current_set"] || score.current_set, set_partials: data.key?("set_partials") ? data["set_partials"] : score.set_partials ) SessionChannel.broadcast_message(session, score.as_cable_payload) end def update_timeout(session, data) score = session.score_state return unless score if data["team"] == "home" score.update!(timeout_home: true) else score.update!(timeout_away: true) end SessionChannel.broadcast_message(session, { type: "timeout", team: data["team"] }) end def update_device(session, data) state = session.device_states.find_or_initialize_by(device_role: data["device_role"] || "camera") state.update!( battery_level: data["battery"], network_type: data["network"], current_bitrate: data["bitrate"], fps: data["fps"], last_seen_at: Time.current ) SessionChannel.broadcast_message(session, state.as_cable_payload) end end