# frozen_string_literal: true require 'tacview_client/base_processor' require 'time' require 'concurrent-ruby' require_relative 'cache' module TacScribe # Processes the events emitted by the Ruby Tacview Client class EventProcessor @@ignored_units = Concurrent::Set.new attr_accessor :events_processed, :events_ignored def initialize(cache:, datastore:, event_queue:, whitelist: nil) @cache = cache @datastore = datastore @event_queue = event_queue @whitelist = whitelist self.events_processed = 0 self.events_ignored = 0 end def start loop do wrapped_event = @event_queue.shift process_event(wrapped_event) rescue StandardError => e puts wrapped_event puts e.inspect puts e.backtrace next end end def process_event(wrapped_event) case wrapped_event[:type] when :update_object update_object(wrapped_event[:event], wrapped_event[:time]) when :delete_object delete_object(wrapped_event[:object_id]) when :set_latitude update_latitude wrapped_event[:value] when :set_longitude update_longitude wrapped_event[:value] end end private # Process an update event for an object # # On the first appearance of the object there are usually more fields # including pilot names, object type etc. # # For existing objects these events are almost always lat/lon/alt updates # only # # @param event [Hash] A parsed ACMI line. This hash will always include # the fields listed below but may also include others depending on the # source line. # @option event [String] :object_id The hexadecimal format object ID. # @option event [BigDecimal] :latitude The object latitude in WGS 84 format. # @option event [BigDecimal] :longitude The object latitude in WGS 84 # format. # @option event [BigDecimal] :altitude The object altitude above sea level # in meters to 1 decimal place. def update_object(event, time) return if ignore_unit?(event) # Hack to make sure the :name field is present so that it is included # in the SQL event[:name] = nil unless event.has_key?(:name) event[:game_time] = time self.events_processed += 1 @cache.write_object(event) end def ignore_unit?(event) if @@ignored_units.include?(event[:object_id]) self.events_ignored += 1 return true end if @whitelist && event[:type] && !@whitelist.include?(event[:type]) @@ignored_units << event[:object_id] self.events_ignored += 1 return true end false end # Process a delete event for an object # # @param id [String] A hexadecimal number representing the object ID def delete_object(id) if @@ignored_units.delete?(id) nil else @cache.delete_object(id) end self.events_processed += 1 end def update_latitude(value) Cache.instance.reference_latitude = value end def update_longitude(value) Cache.instance.reference_longitude = value end end end