Wednesday, July 15, 2026 2:06:03 AM
> send_xm8_notification.rb
# frozen_string_literal: true

module ESM
  module Event
    class SendXm8Notification
      def self.notification_manager
        @notification_manager ||= NotificationManager.new
      end

      def self.send_notifications(notifications)
        if notifications.any? { |n| !n.is_a?(Xm8Notification) }
          raise TypeError, "Invalid notifications provided: #{notifications}"
        end

        notification_manager.add(notifications)
      end

      attr_reader :server, :community, :message

      def initialize(server, message)
        @server = server
        @community = server.community
        @message = message
      end

      def run!
        notifications = filter_notifications
        return if notifications.blank?

        self.class.send_notifications(notifications)
      end

      private

      def filter_notifications
        notifications =
          filter_unregistered_recipients(message.data.notifications)

        notifications.filter_map do |notification|
          Xm8Notification.from(notification)
        rescue Xm8Notification::InvalidType
          notify_invalid_notification!(notification, :invalid_type)
        rescue Xm8Notification::InvalidContent
          notify_invalid_notification!(notification, :invalid_attributes)
        end
      end

      def filter_unregistered_recipients(notifications)
        recipient_steam_uids = notifications.flat_map { |n| n[:recipient_uids] }.uniq
        uid_to_user_mapping = User.where(steam_uid: recipient_steam_uids)
          .to_h { |u| [u.steam_uid, u] }

        notifications_to_send = []
        notifications_to_reject = []

        notifications.each do |notification|
          recipient_notification_mapping = {}

          # These two attributes are index linked, meaning index 0 in both arrays are related
          recipients = notification[:recipient_uids].zip(notification[:uuids])

          # Remove any unregistered UIDs, and store the associated UUID
          recipients.each do |uid, uuid|
            user = uid_to_user_mapping[uid]
            next notifications_to_reject << uuid if user.nil?

            recipient_notification_mapping[user] = uuid
          end

          next if recipient_notification_mapping.blank?

          notification[:server] = server
          notification[:recipient_notification_mapping] = recipient_notification_mapping

          notifications_to_send << notification.without(:recipient_uids, :uuids)
        end

        # Update the server's database to stop sending these
        if notifications_to_reject.size > 0
          update_unregistered_notifications(notifications_to_reject)
        end

        notifications_to_send
      end

      def notify_invalid_notification!(notification, type)
        error = [
          I18n.t(
            "xm8_notifications.#{type}.title",
            server: server.server_id
          ),
          I18n.t(
            "xm8_notifications.#{type}.description",
            type: notification[:type]
          ),
          I18n.t(:xm8_notification),
          JSON.pretty_generate(notification[:content])
        ]

        server.log_error(error.join("\n"))
      end

      def update_unregistered_notifications(unregistered_notifications)
        status_update = unregistered_notifications.to_h do |uuid|
          [uuid, Xm8Notification.failed_state(Xm8Notification::DETAILS_NOT_REGISTERED)]
        end

        message = ESM::Message.new
          .set_type(:query)
          .set_data(
            query_function_name: "update_xm8_notification_state",
            **status_update
          )

        server.send_message(message, block: false)
      end
    end
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 43aa0d7