# frozen_string_literal: true module Api class RulesController < ApplicationController skip_before_action :verify_authenticity_token before_action :authenticate_project! before_action :check_project_enabled # GET /api/:public_key/rules/version # Quick version check - returns latest updated_at timestamp def version current_sampling = HubLoad.current_sampling response.headers['X-Sample-Rate'] = current_sampling[:allowed_requests].to_s render json: { version: Rule.latest_version, count: Rule.active.count, sampling: current_sampling } end # GET /api/:public_key/rules?since=1730646186272060 # Incremental sync - returns rules updated since timestamp (microsecond Unix timestamp) # GET /api/:public_key/rules # Full sync - returns all active rules def index rules = if params[:since].present? # Incremental sync since_time = parse_timestamp(params[:since]) Rule.since(since_time) else # Full sync - only return enabled rules Rule.active.sync_order end current_sampling = HubLoad.current_sampling response.headers['X-Sample-Rate'] = current_sampling[:allowed_requests].to_s render json: { version: Rule.latest_version, sampling: current_sampling, rules: rules.map(&:to_agent_format) } rescue ArgumentError => e render json: { error: "Invalid timestamp format: #{e.message}" }, status: :bad_request end private def authenticate_project! public_key = params[:public_key] || params[:project_id] @project = Project.find_by(public_key: public_key) unless @project render json: { error: "Invalid project key" }, status: :unauthorized return end end def check_project_enabled unless @project.enabled? render json: { error: "Project is disabled" }, status: :forbidden end end def parse_timestamp(timestamp_str) # Parse microsecond Unix timestamp unless timestamp_str.match?(/^\d+$/) raise ArgumentError, "Invalid timestamp format. Expected microsecond Unix timestamp (e.g., 1730646186272060)" end total_microseconds = timestamp_str.to_i seconds = total_microseconds / 1_000_000 microseconds = total_microseconds % 1_000_000 Time.at(seconds, microseconds) rescue ArgumentError => e raise ArgumentError, "Invalid timestamp format: #{e.message}. Use microsecond Unix timestamp (e.g., 1730646186272060)" end end end