tac_scribe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42a39845c511575c6fa441f8ba718d29bdb42eb16776ed80c7d4a06eee502148
4
+ data.tar.gz: 2210d0fa857ae275e8e49fe46ca98c38eb5d886ab1a019f9aba8223e288658ca
5
+ SHA512:
6
+ metadata.gz: 74ed6a4ddc0f84d63f191e89de80991afeb00426a4fb4d1d268fbf5df476c7b98b5ebf9f6a3c3106e6ffe92e664ddafcb05654f8524ba603283a2041e176f8a4
7
+ data.tar.gz: e5152534a385ae72983ed9ed098092d542679fdf8a2b9f4f5bda190e150bea7d801c0b72186c2960082c294aa8c968fe57c53ef5a2db3da0923a0ff34aa61817
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
10
+ *.swp
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,22 @@
1
+ .tests:
2
+ image: "ruby:2.5"
3
+ before_script:
4
+ - apt-get update && apt-get install -y git
5
+ - ruby -v
6
+ - which ruby
7
+ - gem install bundler --no-document
8
+ - bundle install --jobs $(nproc) "${FLAGS[@]}"
9
+
10
+ .rspec:
11
+ extends: .tests
12
+ script:
13
+ - bundle exec rake spec
14
+
15
+ rubocop:
16
+ extends: .tests
17
+ script:
18
+ - bundle exec rake rubocop
19
+
20
+ rspec-ruby:
21
+ extends: .rspec
22
+ image: ruby:latest
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,31 @@
1
+ Style/BlockComments:
2
+ Exclude:
3
+ # This is the default rspec generated file so leave it be for consistency
4
+ - spec/spec_helper.rb
5
+ Layout/CommentIndentation:
6
+ Exclude:
7
+ # This is the default rspec generated file so leave it be for consistency
8
+ - spec/spec_helper.rb
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ # Rubocop does not like the rspec describe block style which is always long
13
+ - spec/**/*_spec.rb
14
+ # There isn't much sense breaking up the OptionParser block since splitting
15
+ # into db and tacview option methods will just break the method length cop
16
+ # and splitting further doesn't aid readability
17
+ - exe/start_scribe
18
+ Metrics/MethodLength:
19
+ Exclude:
20
+ # Breaking up the initializer doesn't really do much for readability
21
+ - lib/tac_scribe/daemon.rb
22
+
23
+ Metrics/ParameterLists:
24
+ Exclude:
25
+ # The nature of the beast. Being the entry point into the program
26
+ # necessitates this
27
+ - lib/tac_scribe/daemon.rb
28
+ Style/GlobalVars:
29
+ Exclude:
30
+ # Using a global variable makes it available to the Pry console
31
+ - bin/console
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ tac_scribe
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.6.3
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.6
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,15 @@
1
+ Tac Scribe - Record Tacview events to PostgreSQL
2
+ Copyright (C) 2019 Jeffrey Jones
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Affero General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Affero General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # TacScribe
2
+
3
+ Writes object state from a tacview server to a PostGIS extended Postgresql
4
+ database for further processing by other systems.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'tac_scribe'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install tac_scribe
21
+
22
+ ## Usage
23
+
24
+ You can run the tool using the `start_scribe` command. Use the `--help`
25
+ option for information on required arguments
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then,
30
+ run `rake test` to run the tests. You can also run `bin/console` for an
31
+ interactive prompt that will allow you to experiment.
32
+
33
+ ### Postgresql and PostGIS
34
+
35
+ This gem requires postgresql and PostGIS available and listening on an
36
+ accessible network port.
37
+
38
+ See the `db` folder for information on running the database migrations.
39
+
40
+ ## Contributing
41
+
42
+ Bug reports and pull requests are welcome on GitLab at https://gitlab.com/overlord-bot/tac-scribe.
43
+
44
+ ## License
45
+
46
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
9
+
10
+ task default: :rubocop
11
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'tac_scribe'
6
+ require 'tac_scribe/datastore'
7
+
8
+ TacScribe::Datastore.instance.connect
9
+
10
+ $DB = TacScribe::Datastore.instance.db
11
+
12
+ # You can add fixtures and/or initialization code here to make experimenting
13
+ # with your gem easier. You can also use a different console, if you like.
14
+
15
+ # (If you use this, don't forget to add pry to your Gemfile!)
16
+ # require "pry"
17
+ # Pry.start
18
+
19
+ require 'irb'
20
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ up do
5
+ create_table(:units) do
6
+ String :id, primary_key: true
7
+ column :position, :geography, null: false
8
+ Float :altitude, default: 0
9
+ String :type
10
+ String :name, null: true
11
+ String :pilot, null: true
12
+ String :group, null: true
13
+ Integer :coalition
14
+ Integer :heading
15
+ Time :updated_at
16
+ # TODO: GIST Index on the position
17
+ end
18
+ end
19
+
20
+ down do
21
+ drop_table(:units)
22
+ end
23
+ end
data/db/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # Database Setup
2
+
3
+ See example instructions for ubuntu here [here](https://kitcharoenp.github.io/postgresql/postgis/2018/05/28/set_up_postgreSQL_postgis.html)
4
+
5
+ # Database Migrations
6
+
7
+ Run migrations using
8
+
9
+ `sequel -m db/ postgres://username:password@database_ip:database_port/tac_scribe`
10
+
data/exe/start_scribe ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ require 'bundler/setup'
6
+ require 'tac_scribe'
7
+
8
+ options = {
9
+ tacview_host: 'localhost',
10
+ tacview_port: 42_674,
11
+ tacview_password: nil,
12
+ tacview_client_name: 'TacScribe',
13
+ db_host: 'localhost',
14
+ db_port: 5432,
15
+ db_name: 'tac_scribe',
16
+ verbose_logging: false,
17
+ threads: 1
18
+ }
19
+
20
+ OptionParser.new do |opts|
21
+ opts.banner = 'Usage: ruby start_scribe [options]'
22
+
23
+ opts.separator "\nTacview Options"
24
+ opts.on('-h', '--tacview-host=host',
25
+ 'Tacview server hostname / IP (Default: localhost)') do |v|
26
+ options[:tacview_host] = v
27
+ end
28
+
29
+ opts.on('-p', '--tacview-port=port',
30
+ 'Tacview server port (Default: 42674)') do |v|
31
+ options[:tacview_port] = v
32
+ end
33
+
34
+ opts.on('-a', '--tacview-password=password',
35
+ 'Tacview server password (Optional)') do |v|
36
+ options[:tacview_password] = v
37
+ end
38
+
39
+ opts.on('-c', '--tacview-client-name=client',
40
+ 'Client name (Default: TacScribe)') do |v|
41
+ options[:tacview_client_name] = v
42
+ end
43
+
44
+ opts.separator "\nDatabase Options"
45
+ opts.on('-o', '--db-host=host',
46
+ 'Postgresql server hostname / IP (Default: localhost)') do |v|
47
+ options[:db_host] = v
48
+ end
49
+ opts.on('-r', '--db-port=port',
50
+ 'Postgresql server port (Default: 5432)') do |v|
51
+ options[:db_port] = v
52
+ end
53
+ opts.on('-u', '--db-username=username',
54
+ 'Postgresql username (Required)') do |v|
55
+ options[:db_user] = v
56
+ end
57
+ opts.on('-s', '--db-password=password',
58
+ 'Postgresql password (Required)') do |v|
59
+ options[:db_password] = v
60
+ end
61
+ opts.on('-n', '--db-name=name',
62
+ 'Postgresql database name (Default: tac_scribe)') do |v|
63
+ options[:db_name] = v
64
+ end
65
+ opts.separator "\nMisc options"
66
+ opts.on('-t', '--threads=threads',
67
+ 'Thread Count (Default: 1)') do |v|
68
+ options[:threads] = v
69
+ end
70
+ opts.on('-v', '--verbose',
71
+ 'Verbose logging') do |_v|
72
+ options[:verbose] = true
73
+ end
74
+ end.parse!
75
+
76
+ %i[db_user db_password].each do |parameter|
77
+ next unless !options[parameter] ||
78
+ !options[parameter].is_a?(String) ||
79
+ options[parameter].empty?
80
+
81
+ puts "#{parameter.to_s.tr('_', '-')} required"
82
+ exit(1)
83
+ end
84
+
85
+ TacScribe::Daemon.new(
86
+ tacview_host: options[:tacview_host],
87
+ tacview_port: options[:tacview_port],
88
+ tacview_password: options[:tacview_password],
89
+ tacview_client_name: options[:tacview_client_name],
90
+ db_host: options[:db_host],
91
+ db_port: options[:db_port],
92
+ db_name: options[:db_name],
93
+ db_user: options[:db_user],
94
+ db_password: options[:db_password],
95
+ verbose_logging: options[:verbose],
96
+ thread_count: options[:threads].to_i
97
+ ).start_processing
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tacview_client'
4
+ require_relative 'datastore'
5
+ require_relative 'event_queue'
6
+ require_relative 'event_processor'
7
+
8
+ module TacScribe
9
+ # Main entry-point into Tac Scribe. Instantiate this class to start
10
+ # processing events.
11
+ class Daemon
12
+ def initialize(db_host:, db_port:, db_name:, db_user:, db_password:,
13
+ tacview_host:, tacview_port:, tacview_password:,
14
+ tacview_client_name:, verbose_logging:, thread_count:)
15
+ Datastore.instance.configure do |config|
16
+ config.host = db_host
17
+ config.port = db_port
18
+ config.database = db_name
19
+ config.username = db_user
20
+ config.password = db_password
21
+ end
22
+ Datastore.instance.connect
23
+
24
+ @event_queue = EventQueue.new verbose_logging: verbose_logging
25
+
26
+ @thread_count = thread_count
27
+ @processing_threads = []
28
+
29
+ @client = TacviewClient::Client.new(
30
+ host: tacview_host,
31
+ port: tacview_port,
32
+ password: tacview_password,
33
+ processor: @event_queue,
34
+ client_name: tacview_client_name
35
+ )
36
+ end
37
+
38
+ # Starts processing and reconnects if the client was disconnected.
39
+ # Because connecting to Tacview always gives an initial unit dump
40
+ # we truncate the table each time we reconnect. This will make sure
41
+ # there are no ghost units hanging around after server restart
42
+ # for example
43
+ def start_processing
44
+ loop do
45
+ kill_processing_threads
46
+ @event_queue.events.clear
47
+ Datastore.instance.truncate_table
48
+ start_processing_threads
49
+ @client.connect
50
+ sleep 30
51
+ end
52
+ end
53
+
54
+ def kill_processing_threads
55
+ @processing_threads.each do |thr|
56
+ thr.kill
57
+ thr.join
58
+ end
59
+ end
60
+
61
+ def start_processing_threads
62
+ @thread_count.times do
63
+ @processing_threads << Thread.new do
64
+ EventProcessor.new(datastore: Datastore.instance,
65
+ event_queue: @event_queue).start
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'georuby'
4
+ require 'sequel'
5
+ require 'sequel-postgis-georuby'
6
+ require 'singleton'
7
+
8
+ module TacScribe
9
+ # Acts as the interface to the back-end datastore and hides all datastore
10
+ # implementation details from callers. Note that ruby does not support
11
+ # exception chaining we are not wrapping exceptions yet. This will happen
12
+ # when https://bugs.ruby-lang.org/issues/8257 is fixed.
13
+ class Datastore
14
+ include Singleton
15
+ include GeoRuby::SimpleFeatures
16
+
17
+ attr_accessor :db
18
+
19
+ @configuration = nil
20
+ @db = nil
21
+
22
+ def configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def configure
27
+ configuration
28
+ yield(@configuration) if block_given?
29
+ end
30
+
31
+ # Contains all the connection configuration required for connectin
32
+ # to a postgresql database. Defaults to localhost with ubuntu presets
33
+ class Configuration
34
+ attr_accessor :host, :port, :database, :username, :password
35
+
36
+ def initialize
37
+ @host = 'localhost'
38
+ @port = '5432'
39
+ @database = 'tac_scribe'
40
+ @username = 'tac_scribe'
41
+ @password = 'tac_scribe'
42
+ end
43
+ end
44
+
45
+ def connect
46
+ configure
47
+ @db = Sequel.connect(connection_string, max_connections: 49)
48
+ @db.extension :postgis_georuby
49
+ end
50
+
51
+ def truncate_table
52
+ @db[:units].truncate
53
+ end
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)
67
+ end
68
+ end
69
+
70
+ def delete_object(object_id)
71
+ count = @db[:units].where(id: object_id).delete
72
+ "Deleted #{object_id} #{object_id.class} - #{count}"
73
+ end
74
+
75
+ private
76
+
77
+ def connection_string
78
+ "postgres://#{@configuration.username}:#{@configuration.password}@" \
79
+ "#{@configuration.host}:#{@configuration.port}" \
80
+ "/#{@configuration.database}"
81
+ end
82
+
83
+ def get_unit(id)
84
+ @db[:units].where(id: id).first
85
+ end
86
+
87
+ def update_unit(event, unit, current_position, timestamp)
88
+ heading = calculate_heading(unit[:position],
89
+ current_position,
90
+ unit[:heading])
91
+
92
+ @db[:units].where(id: event[:object_id]).update(
93
+ position: current_position[:lat_lon],
94
+ altitude: current_position[:altitude],
95
+ heading: heading,
96
+ updated_at: timestamp
97
+ )
98
+ end
99
+
100
+ def insert_unit(event, current_position, timestamp)
101
+ @db[:units].insert(id: event[:object_id],
102
+ position: current_position[:lat_lon],
103
+ altitude: current_position[:altitude],
104
+ type: event[:type],
105
+ name: event[:name],
106
+ group: event[:group],
107
+ pilot: event[:pilot],
108
+ coalition: event[:coalition] == 'Allies' ? 0 : 1,
109
+ updated_at: timestamp)
110
+ end
111
+
112
+ def get_position(event, unit)
113
+ {
114
+ lat_lon: Point.from_x_y(
115
+ event.fetch(:longitude) { unit ? unit[:position].y : nil },
116
+ event.fetch(:latitude) { unit ? unit[:position].x : nil }
117
+ ),
118
+ altitude: event.fetch(:altitude) { unit ? unit[:altitude] : nil }
119
+ }
120
+ end
121
+
122
+ def calculate_heading(old_position, current_position, current_heading)
123
+ return current_heading if old_position == current_position[:lat_lon]
124
+
125
+ begin
126
+ old_position.bearing_to(current_position[:lat_lon]).to_i
127
+ rescue Math::DomainError => e
128
+ puts 'Could not calculate heading: ' + e.message
129
+ puts 'Old Position: ' + old_position.inspect
130
+ puts 'New Position: ' + current_position.inspect
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tacview_client/base_processor'
4
+ require 'time'
5
+ require_relative 'datastore'
6
+
7
+ module TacScribe
8
+ # Processes the events emitted by the Ruby Tacview Client
9
+ class EventProcessor
10
+ def initialize(datastore:, event_queue:)
11
+ @datastore = datastore
12
+ @event_queue = event_queue
13
+ end
14
+
15
+ def start
16
+ loop do
17
+ wrapped_event = @event_queue.events.shift
18
+ process_event(wrapped_event)
19
+ rescue StandardError => e
20
+ puts wrapped_event
21
+ puts e.inspect
22
+ next
23
+ end
24
+ end
25
+
26
+ def process_event(wrapped_event)
27
+ case wrapped_event[:type]
28
+ when :update_object
29
+ update_object(wrapped_event[:event], wrapped_event[:time])
30
+ when :delete_object
31
+ delete_object(wrapped_event[:object_id])
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Process an update event for an object
38
+ #
39
+ # On the first appearance of the object there are usually more fields
40
+ # including pilot names, object type etc.
41
+ #
42
+ # For existing objects these events are almost always lat/lon/alt updates
43
+ # only
44
+ #
45
+ # @param event [Hash] A parsed ACMI line. This hash will always include
46
+ # the fields listed below but may also include others depending on the
47
+ # source line.
48
+ # @option event [String] :object_id The hexadecimal format object ID.
49
+ # @option event [BigDecimal] :latitude The object latitude in WGS 84 format.
50
+ # @option event [BigDecimal] :longitude The object latitude in WGS 84
51
+ # format.
52
+ # @option event [BigDecimal] :altitude The object altitude above sea level
53
+ # in meters to 1 decimal place.
54
+ def update_object(event, time)
55
+ if @event_queue.reference_latitude || @event_queue.reference_longitude
56
+ localize_position(event)
57
+ end
58
+
59
+ @datastore.write_object(event, time)
60
+ end
61
+
62
+ # Process a delete event for an object
63
+ #
64
+ # @param object_id [String] A hexadecimal number representing the object
65
+ # ID
66
+ def delete_object(object_id)
67
+ @datastore.delete_object(object_id)
68
+ end
69
+
70
+ # If we have reference lat/long then use that as a base and update the event
71
+ # position
72
+ def localize_position(event)
73
+ # There is no combination of layouts for these lines that doesn' trip
74
+ # at least one rubocop cop so just ignore the guard clause. The best
75
+ # one is using an inline if but that breaks the line length.
76
+ # rubocop:disable Style/GuardClause
77
+ if event[:latitude]
78
+ event[:latitude] = @event_queue.reference_latitude + event[:latitude]
79
+ end
80
+ if event[:longitude]
81
+ event[:longitude] = @event_queue.reference_longitude + event[:longitude]
82
+ end
83
+ # rubocop:enable Style/GuardClause
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tacview_client/base_processor'
4
+ require 'time'
5
+
6
+ module TacScribe
7
+ # Processes the events emitted by the Ruby Tacview Client
8
+ class EventQueue < TacviewClient::BaseProcessor
9
+ attr_accessor :events, :reference_latitude, :reference_longitude
10
+
11
+ def initialize(verbose_logging:)
12
+ @verbose_logging = verbose_logging
13
+ @events = Queue.new
14
+
15
+ return unless verbose_logging == true
16
+
17
+ Thread.new do
18
+ loop do
19
+ puts "Queue Size: #{@events.size}"
20
+ sleep 1
21
+ end
22
+ end
23
+ end
24
+
25
+ # Process an update event for an object
26
+ #
27
+ # On the first appearance of the object there are usually more fields
28
+ # including pilot names, object type etc.
29
+ #
30
+ # For existing objects these events are almost always lat/lon/alt updates
31
+ # only
32
+ #
33
+ # @param event [Hash] A parsed ACMI line. This hash will always include
34
+ # the fields listed below but may also include others depending on the
35
+ # source line.
36
+ # @option event [String] :object_id The hexadecimal format object ID.
37
+ # @option event [BigDecimal] :latitude The object latitude in WGS 84 format.
38
+ # @option event [BigDecimal] :longitude The object latitude in WGS 84
39
+ # format.
40
+ # @option event [BigDecimal] :altitude The object altitude above sea level
41
+ # in meters to 1 decimal place.
42
+ def update_object(event)
43
+ events << { type: :update_object, event: event, time: @time }
44
+ end
45
+
46
+ # Process a delete event for an object
47
+ #
48
+ # @param object_id [String] A hexadecimal number representing the object
49
+ # ID
50
+ def delete_object(object_id)
51
+ events << { type: :delete_object, object_id: object_id }
52
+ end
53
+
54
+ # Process a time update event
55
+ #
56
+ # @param time [BigDecimal] A time update in seconds from the
57
+ # ReferenceTime to 2 decimal places
58
+ def update_time(time)
59
+ @time = @reference_time + time
60
+ end
61
+
62
+ # Set a property
63
+ #
64
+ # @param property [String] The name of the property to be set
65
+ # @param value [String] The value of the property to be set
66
+ def set_property(property:, value:)
67
+ case property
68
+ when 'ReferenceLatitude'
69
+ self.reference_latitude = BigDecimal(value)
70
+ when 'ReferenceLongitude'
71
+ self.reference_longitude = BigDecimal(value)
72
+ when 'ReferenceTime'
73
+ @reference_time = @time = Time.parse(value)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TacScribe
4
+ VERSION = '0.1.0'
5
+ end
data/lib/tac_scribe.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'tac_scribe/version'
4
+ require_relative 'tac_scribe/daemon'
5
+
6
+ # Top-level name space for all TacScribe clases
7
+ module TacScribe
8
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'tac_scribe/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'tac_scribe'
9
+ spec.version = TacScribe::VERSION
10
+ spec.authors = ['Jeffrey Jones']
11
+ spec.email = ['jeff@jones.be']
12
+
13
+ spec.summary = 'Write Tacview data to PostGIS database'
14
+ spec.description = 'Write Tacview data to PostGIS database'
15
+ spec.homepage = 'https://gitlab.com/overlord-bot/tac_scribe'
16
+ spec.license = 'AGPL-3.0-or-later'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.metadata['yard.run'] = 'yri'
26
+
27
+ spec.add_dependency 'georuby', '~>2.5'
28
+ spec.add_dependency 'pg', '~>1.1'
29
+ spec.add_dependency 'sequel', '~>5.22'
30
+ # The following gem is newish and not heavily updated so the chances
31
+ # of an API breaking change are higher then normal. Therefore lock the
32
+ # version
33
+ spec.add_dependency 'sequel-postgis-georuby', '0.1.2'
34
+ spec.add_dependency 'tacview_client', '~>0.1'
35
+
36
+ spec.add_development_dependency 'bundler', '~> 2.0'
37
+ spec.add_development_dependency 'rake', '~> 10.0'
38
+ spec.add_development_dependency 'rspec', '~> 3.8'
39
+ spec.add_development_dependency 'rubocop', '~>0.73'
40
+ spec.add_development_dependency 'simplecov', '~>0.17'
41
+ spec.add_development_dependency 'yard', '~>0.9'
42
+ end
metadata ADDED
@@ -0,0 +1,222 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tac_scribe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeffrey Jones
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-09-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: georuby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sequel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.22'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.22'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sequel-postgis-georuby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: tacview_client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.8'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.8'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.73'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.73'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.17'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.17'
153
+ - !ruby/object:Gem::Dependency
154
+ name: yard
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.9'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.9'
167
+ description: Write Tacview data to PostGIS database
168
+ email:
169
+ - jeff@jones.be
170
+ executables:
171
+ - start_scribe
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".gitignore"
176
+ - ".gitlab-ci.yml"
177
+ - ".rspec"
178
+ - ".rubocop.yml"
179
+ - ".ruby-gemset"
180
+ - ".ruby-version"
181
+ - ".travis.yml"
182
+ - Gemfile
183
+ - LICENSE.txt
184
+ - README.md
185
+ - Rakefile
186
+ - bin/console
187
+ - bin/setup
188
+ - db/001_create_unit_table.rb
189
+ - db/README.md
190
+ - exe/start_scribe
191
+ - lib/tac_scribe.rb
192
+ - lib/tac_scribe/daemon.rb
193
+ - lib/tac_scribe/datastore.rb
194
+ - lib/tac_scribe/event_processor.rb
195
+ - lib/tac_scribe/event_queue.rb
196
+ - lib/tac_scribe/version.rb
197
+ - tac_scribe.gemspec
198
+ homepage: https://gitlab.com/overlord-bot/tac_scribe
199
+ licenses:
200
+ - AGPL-3.0-or-later
201
+ metadata:
202
+ yard.run: yri
203
+ post_install_message:
204
+ rdoc_options: []
205
+ require_paths:
206
+ - lib
207
+ required_ruby_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ required_rubygems_version: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ requirements: []
218
+ rubygems_version: 3.0.3
219
+ signing_key:
220
+ specification_version: 4
221
+ summary: Write Tacview data to PostGIS database
222
+ test_files: []