tac_scribe 0.3.0-java → 0.6.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f53013c85197970f92c1b1d77608bbb6c0f6d7d70b09640a4d566282ecd2ecd0
4
- data.tar.gz: e05a92c6f3da05c2f2925bb0ab18740ec31e3629906c56472e3fa94b5c1891c8
3
+ metadata.gz: a4f7e36f9c7d3dcc3fcad923b1840c2a1ff889de5f076e27511f3d0e6de61a82
4
+ data.tar.gz: 8c00eaf5d6816c45a15aaf2776028af026654c887814f8d84458fc7520c4b8c5
5
5
  SHA512:
6
- metadata.gz: 54e42d58f65f1d4e49f1affc4211d8829d4b26a1dfc810c5656c37346e552fad692371c3e0738f7a7629d378d88e481aad570a1a8ab47e329cc2c91aac601f20
7
- data.tar.gz: 71d84cd363227f4ffd2684e00c04ae97e714b74f25339f1cf004d5741c33bf770131d7fb51b2b346f112d575135549ef001c0cb6c71b914cf0a72310659c926b
6
+ metadata.gz: e2e9a0c6b73d94bf7cbef046022ce40ca967287611357cef8d2349dd2b84252c2da1249c54d9c6480a6b06c506bf29fc65dbe5895d18816fab255b28278a5766
7
+ data.tar.gz: 7749e5326bb78bf985e827ed412baf83e87da9c9c5c91ee29f189d96d28b5b23e1b6bd1af1253b1d50ed4b7a183cbe282676ef72446fed02c224e6bd3e10c1be
data/.rubocop.yml CHANGED
@@ -14,7 +14,10 @@ Metrics/BlockLength:
14
14
  # There isn't much sense breaking up the OptionParser block since splitting
15
15
  # into db and tacview option methods will just break the method length cop
16
16
  # and splitting further doesn't aid readability
17
- - exe/start_scribe
17
+ - exe/tac_scribe
18
+ # Cannot really avoid this
19
+ - tac_scribe.gemspec
20
+
18
21
  Metrics/MethodLength:
19
22
  Exclude:
20
23
  # Breaking up the initializer doesn't really do much for readability
@@ -29,3 +32,13 @@ Style/GlobalVars:
29
32
  Exclude:
30
33
  # Using a global variable makes it available to the Pry console
31
34
  - bin/console
35
+ AllCops:
36
+ Exclude:
37
+ # These files will need a MAJOR refactoring to get rid of these warnings
38
+ - lib/tac_scribe/cache.rb
39
+ - lib/tac_scribe/datastore.rb
40
+ - lib/tac_scribe/daemon.rb
41
+ ClassVars:
42
+ Exclude:
43
+ # We are fine with this and understand the risks. We are not inheriting.
44
+ - lib/tac_scribe/event_processor.rb
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- jruby
1
+ ruby-2.6.3
data/CHANGELOG.md CHANGED
@@ -4,7 +4,22 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.6.0]
8
+ ### Added
9
+ - Calculates and stores speed of units
10
+
11
+ ### Fixed
12
+ - Made more robust against failures and more logging messages
13
+
14
+ ## [0.5.0]
15
+ ### Changed
16
+ - Added missing db column to migration file
17
+ - Clear the cache on server restart
18
+ - Add more info to logging
19
+
20
+ ## [0.4.0]
21
+ ### Changed
22
+ - Switch to periodic writing to the database
8
23
 
9
24
  ## [0.3.0] - 2019-10-27
10
25
  ### Changed
@@ -0,0 +1,5 @@
1
+ Sea+Watercraft+AircraftCarrier
2
+ Air+Rotorcraft
3
+ Air+FixedWing
4
+ Ground+Static+Aerodrome
5
+ Navaid+Static+Bullseye
@@ -12,7 +12,9 @@ Sequel.migration do
12
12
  String :group, null: true
13
13
  Integer :coalition
14
14
  Integer :heading
15
+ Integer :speed
15
16
  Time :updated_at
17
+ Boolean :deleted
16
18
  # TODO: GIST Index on the position
17
19
  end
18
20
  end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'georuby'
4
+ require 'sequel'
5
+ require 'sequel-postgis-georuby'
6
+ require 'singleton'
7
+ require 'concurrent-ruby'
8
+ require 'haversine'
9
+
10
+ module TacScribe
11
+ # The in-memory cache that is updated by events in real-time before the data
12
+ # is synced to the DB
13
+ class Cache
14
+ include Singleton
15
+ include GeoRuby::SimpleFeatures
16
+
17
+ @@cache = Concurrent::Hash.new
18
+
19
+ attr_accessor :reference_latitude, :reference_longitude
20
+
21
+ def data
22
+ @@cache
23
+ end
24
+
25
+ def write_object(object)
26
+ if reference_latitude != 0 || reference_longitude != 0
27
+ localize_position(object)
28
+ end
29
+
30
+ id = object[:object_id]
31
+ object[:id] = id
32
+
33
+ cache_object = @@cache[id]
34
+
35
+ object[:position] = set_position(object, cache_object)
36
+
37
+ %i[object_id latitude longitude color country].each do |key|
38
+ object.delete(key)
39
+ end
40
+
41
+ if object[:coalition]
42
+ object[:coalition] = case object[:coalition]
43
+ when 'Allies'
44
+ 0
45
+ when 'Enemies'
46
+ 1
47
+ else
48
+ 2
49
+ end
50
+ end
51
+
52
+ if cache_object
53
+ object[:heading] = calculate_heading(cache_object, object)
54
+ object[:speed] = calculate_speed(cache_object, object)
55
+ cache_object.merge!(object)
56
+ else
57
+ object[:heading] = -1
58
+ object[:speed] = 0
59
+ cache_object = object
60
+ end
61
+
62
+ if !cache_object.key?(:altitude) || !cache_object[:altitude]
63
+ cache_object[:altitude] = 0
64
+ end
65
+ if !cache_object.key?(:coalition) || !cache_object[:coalition]
66
+ cache_object[:coalition] = 2
67
+ end
68
+
69
+ cache_object[:pilot] = nil unless cache_object.key?(:pilot)
70
+
71
+ cache_object[:group] = nil unless cache_object.key?(:group)
72
+
73
+ cache_object[:deleted] = false unless cache_object.key?(:deleted)
74
+
75
+ cache_object[:updated_at] = Time.now
76
+
77
+ @@cache[id] = cache_object
78
+ end
79
+
80
+ def delete_object(id)
81
+ @@cache[id][:deleted] = true if @@cache[id]
82
+ end
83
+
84
+ def clear
85
+ @@cache.clear
86
+ end
87
+
88
+ private
89
+
90
+ def localize_position(object)
91
+ if reference_latitude && object.key?(:latitude)
92
+ object[:latitude] = reference_latitude + object[:latitude]
93
+ end
94
+ if reference_longitude && object.key?(:longitude)
95
+ object[:longitude] = reference_longitude + object[:longitude]
96
+ end
97
+ end
98
+
99
+ def set_position(object, cache_object)
100
+ longitude = if object.key?(:longitude)
101
+ object[:longitude]
102
+ else
103
+ cache_object[:position].y
104
+ end
105
+
106
+ latitude = if object.key?(:latitude)
107
+ object[:latitude]
108
+ else
109
+ cache_object[:position].x
110
+ end
111
+
112
+ # This "Point" class is not lat/long aware which is why we are
113
+ # flipping things up here because when it converts to SQL we need
114
+ # the long to be first since that is what postgresql expects.
115
+ Point.from_x_y(longitude, latitude)
116
+ end
117
+
118
+ def calculate_heading(cache_object, object)
119
+ if cache_object[:position] == object[:position]
120
+ return cache_object[:heading]
121
+ end
122
+
123
+ begin
124
+ cache_object[:position].bearing_to(object[:position]).to_i
125
+ rescue Math::DomainError => e
126
+ puts 'Could not calculate heading: ' + e.message
127
+ puts 'Old Position: ' + cache_object[:position].inspect
128
+ puts 'New Position: ' + object[:position].inspect
129
+ end
130
+ end
131
+
132
+ def calculate_speed(cache_object, object)
133
+ time = object[:game_time] - cache_object[:game_time]
134
+
135
+ start_point = cache_object[:position]
136
+ end_point = object[:position]
137
+
138
+ # Because of the above issues with Point and Lat/Lon
139
+ # the values are reverse here :(
140
+ distance = Haversine.distance(start_point.y, start_point.x,
141
+ end_point.y, end_point.x).to_meters
142
+
143
+ speed = distance / time
144
+
145
+ speed.to_i
146
+ end
147
+ end
148
+ end
@@ -4,6 +4,7 @@ require 'json'
4
4
  require 'tacview_client'
5
5
  require 'set'
6
6
  require_relative 'datastore'
7
+ require_relative 'cache'
7
8
  require_relative 'event_queue'
8
9
  require_relative 'event_processor'
9
10
 
@@ -24,11 +25,13 @@ module TacScribe
24
25
  end
25
26
  Datastore.instance.connect
26
27
 
27
- @event_queue = EventQueue.new verbose_logging: verbose_logging
28
+ @event_queue = EventQueue.new
29
+
30
+ @verbose_logging = verbose_logging
28
31
 
29
32
  @populate_airfields = populate_airfields
30
33
  @thread_count = thread_count
31
- @processing_threads = []
34
+ @threads = {}
32
35
  @whitelist = Set.new(IO.read(whitelist).split) if whitelist
33
36
 
34
37
  @client = TacviewClient::Client.new(
@@ -47,43 +50,99 @@ module TacScribe
47
50
  # for example
48
51
  def start_processing
49
52
  loop do
50
- kill_processing_threads
53
+ puts 'Starting processing loop'
51
54
  @event_queue.clear
52
55
  Datastore.instance.truncate_table
56
+ Cache.instance.clear
53
57
  start_processing_threads
58
+ start_db_sync_thread
59
+ start_reporting_thread
54
60
  populate_airfields if @populate_airfields
61
+ @threads.each_pair do |key, _value|
62
+ puts "#{key} thread started"
63
+ end
55
64
  @client.connect
65
+ # If this code is executed it means we have been disconnected without
66
+ # exceptions. We will still sleep to stop a retry storm. Just not as
67
+ # long.
68
+ sleep 10
56
69
  # Rescuing reliably from Net::HTTP is a complete bear so rescue
57
70
  # StandardError. It ain't pretty but it is reliable. We will puts
58
71
  # the exception just in case
59
72
  # https://stackoverflow.com/questions/5370697/what-s-the-best-way-to-handle-exceptions-from-nethttp
60
73
  rescue StandardError => e
74
+ puts 'Exception in processing loop'
61
75
  puts e.message
62
76
  puts e.backtrace
77
+ kill_threads
63
78
  sleep 30
64
79
  next
65
80
  end
66
81
  end
67
82
 
68
- def kill_processing_threads
69
- @processing_threads.each do |thr|
70
- thr.kill
71
- thr.join
83
+ def kill_threads
84
+ puts 'Killing Threads'
85
+ @threads.each_pair do |key, thread|
86
+ puts "Killing #{key} thread"
87
+ thread.kill
88
+ thread.join
72
89
  end
73
90
  end
74
91
 
75
92
  def start_processing_threads
76
- @thread_count.times do
77
- @processing_threads << Thread.new do
78
- EventProcessor.new(datastore: Datastore.instance,
79
- event_queue: @event_queue,
80
- whitelist: @whitelist).start
93
+ @event_processor = EventProcessor.new(cache: Cache.instance,
94
+ datastore: Datastore.instance,
95
+ event_queue: @event_queue,
96
+ whitelist: @whitelist)
97
+ event_processor_thread = Thread.new do
98
+ @event_processor.start
99
+ end
100
+ event_processor_thread.name = 'Event Processor'
101
+ @threads[:processing] = event_processor_thread
102
+ end
103
+
104
+ def start_db_sync_thread
105
+ db_write_thread = Thread.new do
106
+ loop do
107
+ sleep 1
108
+ deleted = Datastore.instance.write_objects(Cache.instance.data.values)
109
+ deleted.each { |id| Cache.instance.data.delete(id) }
110
+ rescue StandardError
111
+ next
112
+ end
113
+ end
114
+ db_write_thread.name = 'Database Writing'
115
+ @threads[:database] = db_write_thread
116
+ end
117
+
118
+ def start_reporting_thread
119
+ return unless @verbose_logging
120
+
121
+ reporting_thread = Thread.new do
122
+ sleep 5
123
+ loop do
124
+ puts "#{Time.now.strftime('%FT%T')}\t" \
125
+ "Events Incoming: #{@event_queue.events_written}\t" \
126
+ "Processed: #{@event_processor.events_processed}\t" \
127
+ "Ignored: #{@event_processor.events_ignored}\t" \
128
+ "Queue Size: #{@event_queue.size}\t" \
129
+ "Objects Written: #{Datastore.instance.written}\t" \
130
+ "Deleted: #{Datastore.instance.deleted}"
131
+ @event_queue.events_written = 0
132
+ @event_processor.events_processed = 0
133
+ @event_processor.events_ignored = 0
134
+ Datastore.instance.written = 0
135
+ Datastore.instance.deleted = 0
136
+ sleep 1
81
137
  end
82
138
  end
139
+ reporting_thread.name = 'Reporting'
140
+ @threads[:reporting] = reporting_thread
83
141
  end
84
142
 
85
143
  def populate_airfields
86
- json = File.read(File.join(File.dirname(__FILE__), '../../data/airfields.json'))
144
+ json = File.read(File.join(File.dirname(__FILE__),
145
+ '../../data/airfields.json'))
87
146
  airfields = JSON.parse(json)
88
147
  airfields.each_with_index do |airfield, i|
89
148
  @event_queue.update_object(
@@ -14,7 +14,7 @@ module TacScribe
14
14
  include Singleton
15
15
  include GeoRuby::SimpleFeatures
16
16
 
17
- attr_accessor :db
17
+ attr_accessor :db, :written, :deleted
18
18
 
19
19
  @configuration = nil
20
20
  @db = nil
@@ -52,24 +52,29 @@ module TacScribe
52
52
  @db[:units].truncate
53
53
  end
54
54
 
55
- def write_object(event, timestamp)
56
- unit = get_unit(event[:object_id])
57
-
58
- # Tacview omits values that don't change to save
59
- # data bandwidth and storage. If something has not changed then
60
- # use the old value
61
- current_position = get_position(event, unit)
62
-
63
- if unit
64
- update_unit(event, unit, current_position, timestamp)
65
- else
66
- insert_unit(event, current_position, timestamp)
55
+ def write_objects(objects)
56
+ objects = objects.map do |object|
57
+ obj = object.clone
58
+ obj.delete(:game_time)
59
+ obj
67
60
  end
68
- end
69
61
 
70
- def delete_object(object_id)
71
- count = @db[:units].where(id: object_id).delete
72
- "Deleted #{object_id} #{object_id.class} - #{count}"
62
+ @db[:units].insert_conflict(
63
+ constraint: :units_pkey,
64
+ update: { position: Sequel[:excluded][:position],
65
+ altitude: Sequel[:excluded][:altitude],
66
+ heading: Sequel[:excluded][:heading],
67
+ speed: Sequel[:excluded][:speed],
68
+ updated_at: Sequel[:excluded][:updated_at],
69
+ deleted: Sequel[:excluded][:deleted] }
70
+ )
71
+ .multi_insert(objects)
72
+ deleted_ids = @db[:units].where(deleted: true).select_map(:id)
73
+ @db[:units].where(deleted: true).delete
74
+ self.written = objects.size
75
+ self.deleted = deleted_ids.size
76
+
77
+ deleted_ids
73
78
  end
74
79
 
75
80
  private
@@ -85,56 +90,5 @@ module TacScribe
85
90
  "/#{@configuration.database}"
86
91
  end
87
92
  end
88
-
89
- def get_unit(id)
90
- @db[:units].where(id: id).first
91
- end
92
-
93
- def update_unit(event, unit, current_position, timestamp)
94
- heading = calculate_heading(unit[:position],
95
- current_position,
96
- unit[:heading])
97
-
98
- @db[:units].where(id: event[:object_id]).update(
99
- position: current_position[:lat_lon],
100
- altitude: current_position[:altitude],
101
- heading: heading,
102
- updated_at: timestamp
103
- )
104
- end
105
-
106
- def insert_unit(event, current_position, timestamp)
107
- @db[:units].insert(id: event[:object_id],
108
- position: current_position[:lat_lon],
109
- altitude: current_position[:altitude],
110
- type: event[:type],
111
- name: event[:name],
112
- group: event[:group],
113
- pilot: event[:pilot],
114
- coalition: event[:coalition] == 'Allies' ? 0 : 1,
115
- updated_at: timestamp)
116
- end
117
-
118
- def get_position(event, unit)
119
- {
120
- lat_lon: Point.from_x_y(
121
- event.fetch(:longitude) { unit ? unit[:position].y : nil },
122
- event.fetch(:latitude) { unit ? unit[:position].x : nil }
123
- ),
124
- altitude: event.fetch(:altitude) { unit ? unit[:altitude] : nil }
125
- }
126
- end
127
-
128
- def calculate_heading(old_position, current_position, current_heading)
129
- return current_heading if old_position == current_position[:lat_lon]
130
-
131
- begin
132
- old_position.bearing_to(current_position[:lat_lon]).to_i
133
- rescue Math::DomainError => e
134
- puts 'Could not calculate heading: ' + e.message
135
- puts 'Old Position: ' + old_position.inspect
136
- puts 'New Position: ' + current_position.inspect
137
- end
138
- end
139
93
  end
140
94
  end
@@ -3,22 +3,27 @@
3
3
  require 'tacview_client/base_processor'
4
4
  require 'time'
5
5
  require 'concurrent-ruby'
6
- require_relative 'datastore'
6
+ require_relative 'cache'
7
7
 
8
8
  module TacScribe
9
9
  # Processes the events emitted by the Ruby Tacview Client
10
10
  class EventProcessor
11
11
  @@ignored_units = Concurrent::Set.new
12
12
 
13
- def initialize(datastore:, event_queue:, whitelist: nil)
13
+ attr_accessor :events_processed, :events_ignored
14
+
15
+ def initialize(cache:, datastore:, event_queue:, whitelist: nil)
16
+ @cache = cache
14
17
  @datastore = datastore
15
18
  @event_queue = event_queue
16
19
  @whitelist = whitelist
20
+ self.events_processed = 0
21
+ self.events_ignored = 0
17
22
  end
18
23
 
19
24
  def start
20
25
  loop do
21
- wrapped_event = @event_queue.get_event
26
+ wrapped_event = @event_queue.shift
22
27
  process_event(wrapped_event)
23
28
  rescue StandardError => e
24
29
  puts wrapped_event
@@ -33,6 +38,10 @@ module TacScribe
33
38
  update_object(wrapped_event[:event], wrapped_event[:time])
34
39
  when :delete_object
35
40
  delete_object(wrapped_event[:object_id])
41
+ when :set_latitude
42
+ update_latitude wrapped_event[:value]
43
+ when :set_longitude
44
+ update_longitude wrapped_event[:value]
36
45
  end
37
46
  end
38
47
 
@@ -56,44 +65,47 @@ module TacScribe
56
65
  # @option event [BigDecimal] :altitude The object altitude above sea level
57
66
  # in meters to 1 decimal place.
58
67
  def update_object(event, time)
59
- return if @@ignored_units.include?(event[:object_id])
68
+ return if ignore_unit?(even)
60
69
 
61
- if @whitelist && event[:type] && !@whitelist.include?(event[:type])
62
- @@ignored_units << event[:object_id]
63
- return
70
+ event[:game_time] = time
71
+
72
+ self.events_processed += 1
73
+ @cache.write_object(event)
74
+ end
75
+
76
+ def ignore_unit?(event)
77
+ if @@ignored_units.include?(event[:object_id])
78
+ self.events_ignored += 1
79
+ return true
64
80
  end
65
81
 
66
- if @event_queue.reference_latitude || @event_queue.reference_longitude
67
- localize_position(event)
82
+ if @whitelist && event[:type] && !@whitelist.include?(event[:type])
83
+ @@ignored_units << event[:object_id]
84
+ self.events_ignored += 1
85
+ return true
68
86
  end
69
87
 
70
- @datastore.write_object(event, time)
88
+ false
71
89
  end
72
90
 
73
91
  # Process a delete event for an object
74
92
  #
75
- # @param object_id [String] A hexadecimal number representing the object
76
- # ID
77
- def delete_object(object_id)
78
- return if @@ignored_units.delete?(object_id)
93
+ # @param id [String] A hexadecimal number representing the object ID
94
+ def delete_object(id)
95
+ if @@ignored_units.delete?(id)
96
+ nil
97
+ else
98
+ @cache.delete_object(id)
99
+ end
100
+ self.events_processed += 1
101
+ end
79
102
 
80
- @datastore.delete_object(object_id)
103
+ def update_latitude(value)
104
+ Cache.instance.reference_latitude = value
81
105
  end
82
106
 
83
- # If we have reference lat/long then use that as a base and update the event
84
- # position
85
- def localize_position(event)
86
- # There is no combination of layouts for these lines that doesn' trip
87
- # at least one rubocop cop so just ignore the guard clause. The best
88
- # one is using an inline if but that breaks the line length.
89
- # rubocop:disable Style/GuardClause
90
- if event[:latitude]
91
- event[:latitude] = @event_queue.reference_latitude + event[:latitude]
92
- end
93
- if event[:longitude]
94
- event[:longitude] = @event_queue.reference_longitude + event[:longitude]
95
- end
96
- # rubocop:enable Style/GuardClause
107
+ def update_longitude(value)
108
+ Cache.instance.reference_longitude = value
97
109
  end
98
110
  end
99
111
  end
@@ -6,32 +6,22 @@ require 'time'
6
6
  module TacScribe
7
7
  # Processes the events emitted by the Ruby Tacview Client
8
8
  class EventQueue < TacviewClient::BaseProcessor
9
- attr_accessor :reference_latitude, :reference_longitude
9
+ attr_accessor :events_written
10
10
 
11
- def initialize(verbose_logging:)
12
- @verbose_logging = verbose_logging
11
+ def initialize
13
12
  @events = Queue.new
14
- @event_write = 0
15
- @event_read = 0
16
-
17
- return unless verbose_logging == true
18
-
19
- Thread.new do
20
- loop do
21
- puts "#{Time.now.strftime('%FT%T')} - Queue Size: #{@events.size} \t Events Added: #{@event_write} \t Events Processed: #{@event_read}"
22
- @event_write = 0
23
- @event_read = 0
24
- sleep 1
25
- end
26
- end
13
+ self.events_written = 0
27
14
  end
28
15
 
29
16
  def clear
30
17
  @events.clear
31
18
  end
32
19
 
33
- def get_event
34
- @event_read += 1
20
+ def size
21
+ @events.size
22
+ end
23
+
24
+ def shift
35
25
  @events.shift
36
26
  end
37
27
 
@@ -53,7 +43,7 @@ module TacScribe
53
43
  # @option event [BigDecimal] :altitude The object altitude above sea level
54
44
  # in meters to 1 decimal place.
55
45
  def update_object(event)
56
- @event_write += 1
46
+ self.events_written += 1
57
47
  @events << { type: :update_object, event: event, time: @time }
58
48
  end
59
49
 
@@ -62,7 +52,7 @@ module TacScribe
62
52
  # @param object_id [String] A hexadecimal number representing the object
63
53
  # ID
64
54
  def delete_object(object_id)
65
- @event_write += 1
55
+ self.events_written += 1
66
56
  @events << { type: :delete_object, object_id: object_id }
67
57
  end
68
58
 
@@ -81,9 +71,9 @@ module TacScribe
81
71
  def set_property(property:, value:)
82
72
  case property
83
73
  when 'ReferenceLatitude'
84
- self.reference_latitude = BigDecimal(value)
74
+ @events << { type: :set_latitude, value: BigDecimal(value) }
85
75
  when 'ReferenceLongitude'
86
- self.reference_longitude = BigDecimal(value)
76
+ @events << { type: :set_longitude, value: BigDecimal(value) }
87
77
  when 'ReferenceTime'
88
78
  @reference_time = @time = Time.parse(value)
89
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TacScribe
4
- VERSION = '0.3.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/tac_scribe.gemspec CHANGED
@@ -21,12 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.bindir = 'exe'
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ['lib']
24
+ spec.platform = 'java'
24
25
 
25
26
  spec.metadata['yard.run'] = 'yri'
26
27
 
27
28
  if RUBY_PLATFORM == 'java'
28
- # TODO: Specifying a verison chokes bundler for some reason
29
- spec.platform = 'java'
30
29
  spec.add_dependency 'activerecord-jdbcpostgresql-adapter'
31
30
  else
32
31
  spec.add_dependency 'pg', '~>1.1'
@@ -38,6 +37,7 @@ Gem::Specification.new do |spec|
38
37
  # of an API breaking change are higher then normal. Therefore lock the
39
38
  # version
40
39
  spec.add_dependency 'concurrent-ruby', '~>1.1.5'
40
+ spec.add_dependency 'haversine', '~>0.3'
41
41
  spec.add_dependency 'sequel-postgis-georuby', '0.1.2'
42
42
  spec.add_dependency 'tacview_client', '~>0.1'
43
43
 
metadata CHANGED
@@ -1,178 +1,192 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tac_scribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.6.0
5
5
  platform: java
6
6
  authors:
7
7
  - Jeffrey Jones
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-26 00:00:00.000000000 Z
11
+ date: 2020-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: pg
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
- - - ">="
17
+ - - "~>"
17
18
  - !ruby/object:Gem::Version
18
- version: '0'
19
- name: activerecord-jdbcpostgresql-adapter
20
- prerelease: false
19
+ version: '1.1'
21
20
  type: :runtime
21
+ prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
+ name: georuby
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - "~>"
31
32
  - !ruby/object:Gem::Version
32
33
  version: '2.5'
33
- name: georuby
34
- prerelease: false
35
34
  type: :runtime
35
+ prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.5'
41
41
  - !ruby/object:Gem::Dependency
42
+ name: sequel
42
43
  requirement: !ruby/object:Gem::Requirement
43
44
  requirements:
44
45
  - - "~>"
45
46
  - !ruby/object:Gem::Version
46
47
  version: '5.22'
47
- name: sequel
48
- prerelease: false
49
48
  type: :runtime
49
+ prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.22'
55
55
  - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
56
57
  requirement: !ruby/object:Gem::Requirement
57
58
  requirements:
58
59
  - - "~>"
59
60
  - !ruby/object:Gem::Version
60
61
  version: 1.1.5
61
- name: concurrent-ruby
62
- prerelease: false
63
62
  type: :runtime
63
+ prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.1.5
69
69
  - !ruby/object:Gem::Dependency
70
+ name: haversine
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sequel-postgis-georuby
70
85
  requirement: !ruby/object:Gem::Requirement
71
86
  requirements:
72
87
  - - '='
73
88
  - !ruby/object:Gem::Version
74
89
  version: 0.1.2
75
- name: sequel-postgis-georuby
76
- prerelease: false
77
90
  type: :runtime
91
+ prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - '='
81
95
  - !ruby/object:Gem::Version
82
96
  version: 0.1.2
83
97
  - !ruby/object:Gem::Dependency
98
+ name: tacview_client
84
99
  requirement: !ruby/object:Gem::Requirement
85
100
  requirements:
86
101
  - - "~>"
87
102
  - !ruby/object:Gem::Version
88
103
  version: '0.1'
89
- name: tacview_client
90
- prerelease: false
91
104
  type: :runtime
105
+ prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0.1'
97
111
  - !ruby/object:Gem::Dependency
112
+ name: bundler
98
113
  requirement: !ruby/object:Gem::Requirement
99
114
  requirements:
100
115
  - - "~>"
101
116
  - !ruby/object:Gem::Version
102
117
  version: '2.0'
103
- name: bundler
104
- prerelease: false
105
118
  type: :development
119
+ prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
124
  version: '2.0'
111
125
  - !ruby/object:Gem::Dependency
126
+ name: rake
112
127
  requirement: !ruby/object:Gem::Requirement
113
128
  requirements:
114
129
  - - "~>"
115
130
  - !ruby/object:Gem::Version
116
131
  version: '10.0'
117
- name: rake
118
- prerelease: false
119
132
  type: :development
133
+ prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
136
  - - "~>"
123
137
  - !ruby/object:Gem::Version
124
138
  version: '10.0'
125
139
  - !ruby/object:Gem::Dependency
140
+ name: rspec
126
141
  requirement: !ruby/object:Gem::Requirement
127
142
  requirements:
128
143
  - - "~>"
129
144
  - !ruby/object:Gem::Version
130
145
  version: '3.8'
131
- name: rspec
132
- prerelease: false
133
146
  type: :development
147
+ prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
152
  version: '3.8'
139
153
  - !ruby/object:Gem::Dependency
154
+ name: rubocop
140
155
  requirement: !ruby/object:Gem::Requirement
141
156
  requirements:
142
157
  - - "~>"
143
158
  - !ruby/object:Gem::Version
144
159
  version: '0.73'
145
- name: rubocop
146
- prerelease: false
147
160
  type: :development
161
+ prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0.73'
153
167
  - !ruby/object:Gem::Dependency
168
+ name: simplecov
154
169
  requirement: !ruby/object:Gem::Requirement
155
170
  requirements:
156
171
  - - "~>"
157
172
  - !ruby/object:Gem::Version
158
173
  version: '0.17'
159
- name: simplecov
160
- prerelease: false
161
174
  type: :development
175
+ prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
178
  - - "~>"
165
179
  - !ruby/object:Gem::Version
166
180
  version: '0.17'
167
181
  - !ruby/object:Gem::Dependency
182
+ name: yard
168
183
  requirement: !ruby/object:Gem::Requirement
169
184
  requirements:
170
185
  - - "~>"
171
186
  - !ruby/object:Gem::Version
172
187
  version: '0.9'
173
- name: yard
174
- prerelease: false
175
188
  type: :development
189
+ prerelease: false
176
190
  version_requirements: !ruby/object:Gem::Requirement
177
191
  requirements:
178
192
  - - "~>"
@@ -201,10 +215,12 @@ files:
201
215
  - bin/console
202
216
  - bin/setup
203
217
  - data/airfields.json
218
+ - data/whitelist.example
204
219
  - db/001_create_unit_table.rb
205
220
  - db/README.md
206
221
  - exe/tac_scribe
207
222
  - lib/tac_scribe.rb
223
+ - lib/tac_scribe/cache.rb
208
224
  - lib/tac_scribe/daemon.rb
209
225
  - lib/tac_scribe/datastore.rb
210
226
  - lib/tac_scribe/event_processor.rb
@@ -217,7 +233,7 @@ licenses:
217
233
  - AGPL-3.0-or-later
218
234
  metadata:
219
235
  yard.run: yri
220
- post_install_message:
236
+ post_install_message:
221
237
  rdoc_options: []
222
238
  require_paths:
223
239
  - lib
@@ -232,9 +248,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
248
  - !ruby/object:Gem::Version
233
249
  version: '0'
234
250
  requirements: []
235
- rubyforge_project:
236
- rubygems_version: 2.7.6
237
- signing_key:
251
+ rubygems_version: 3.0.3
252
+ signing_key:
238
253
  specification_version: 4
239
254
  summary: Write Tacview data to PostGIS database
240
255
  test_files: []