openc3 5.4.2 → 5.4.3.pre.beta0

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: '08e9c285070449047388f035c8c56522154ed54cd9e075dc3b52e87f17a7ff0e'
4
- data.tar.gz: d52d4c20ffd7f7ea1593d19df3be807d7dc4cc787e30390d11f8c1b90103c186
3
+ metadata.gz: 859879129f5646a4e8fd10a916e1e88859a7b5ed178fe2983f42df4e7e8c1a52
4
+ data.tar.gz: 745a188c5e9277e0bb793207f383f85d6ec6d571d41d6115530f6f78bd671817
5
5
  SHA512:
6
- metadata.gz: 5e242af794c1263642f951c46867ce5fa543ccef505c60c0d6a4015c91503acf8d62b3b7b8dd40b91ec4c252013b4a40eec21d0bb3055bc5f6ae11e370c48fbe
7
- data.tar.gz: 06b2ad289fcd4bfbfa23a896469b1d9d4b55b017e4535eb060a101147b4b757535f071dd622121f78923a2d0e1923795e109b94d3c6917933e0ce74e11c586cd
6
+ metadata.gz: '0582ba269983955ae39c8d0c941666d2fcc65811416e3c1ae7026811fa00d9699ecffc09e195909f30cac3c8571f6b83889349fed9c96ec89c95091aff088a61'
7
+ data.tar.gz: a9c9c554d6595cd7718dc58b1e2e07e0ff9a440cd6545674b47250a3542164a41d27bad1bf237c8c121f170dd04380eeaa125769abc9423c0de2e610578f9799
data/Gemfile CHANGED
@@ -6,13 +6,8 @@ gem 'ruby-termios', '>= 0.9' if RbConfig::CONFIG['target_os'] !~ /mswin|mingw|cy
6
6
 
7
7
  gemspec :name => 'openc3'
8
8
 
9
- # unless ENV['JENKINS_HOME']
10
- # # Example of how to use a local branch (doesn't work on Jenkins)
11
- # # You also need to set "bundle config local.mock_redis <LOCAL PATH TO CHECKED OUT GEM>"
12
- # # For example: bundle config local.mock_redis C:/_Programs/oss/mock_redis
13
- # # Make sure the local copy is checked out to the specified branch
14
- # # Delete the config: bundle config --delete local.mock_redis
15
- # group :development do
16
- # gem 'mock_redis', github: 'jasonatball/mock_redis', branch: 'master'
17
- # end
18
- # end
9
+ # Include the rails gems for the convenience of custom microservice plugins
10
+ gem 'rails', '~> 7.0.0'
11
+ gem 'bootsnap', '>= 1.9.3', require: false
12
+ gem 'rack-cors', '~> 1.1'
13
+ gem 'tzinfo-data'
data/bin/openc3cli CHANGED
@@ -43,6 +43,8 @@ require 'redis'
43
43
  require 'erb'
44
44
  require 'pp'
45
45
  # require 'psych' # Psych code is commented out
46
+ require "irb"
47
+ require "irb/completion"
46
48
 
47
49
  $redis_url = "redis://#{ENV['OPENC3_REDIS_HOSTNAME']}:#{ENV['OPENC3_REDIS_PORT']}"
48
50
  # Initialize the connection to the bucket library
@@ -64,13 +66,14 @@ def print_usage
64
66
  puts "Usage:"
65
67
  puts " cli help # Displays this information"
66
68
  puts " cli rake # Runs rake in the local directory"
69
+ puts " cli irb # Runs irb in the local directory"
67
70
  puts " cli validate /PATH/FILENAME.gem SCOPE variables.txt # Validate a COSMOS plugin gem file"
68
71
  puts " cli load /PATH/FILENAME.gem SCOPE variables.txt # Loads a COSMOS plugin gem file"
69
72
  puts " cli generate plugin PLUGIN_NAME # Generate a COSMOS plugin"
70
73
  puts " #{MIGRATE_PARSER}"
71
74
  puts " cli bridge CONFIG_FILENAME # Run COSMOS host bridge"
72
75
  puts " cli bridgesetup CONFIG_FILENAME # Create a default config file"
73
- puts " cli geminstall GEMFILENAME SCOPE # Install loaded gem to /gems"
76
+ puts " cli geminstall GEMFILENAME SCOPE # Install loaded gem to /gems"
74
77
  puts " cli rubysloc # Counts Ruby SLOC recursively. Run with --help for more info."
75
78
  puts " cli xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
76
79
  puts " cli cstol_converter # Converts CSTOL files (.prc) to COSMOS. Run with --help for more info."
@@ -526,6 +529,10 @@ if not ARGV[0].nil? # argument(s) given
526
529
  # Handle each task
527
530
  case ARGV[0].downcase
528
531
 
532
+ when 'irb'
533
+ ARGV.clear
534
+ IRB.start
535
+
529
536
  when 'rake'
530
537
  puts `rake #{ARGV[1..-1].join(' ')}`
531
538
 
@@ -27,7 +27,8 @@ tcpip_client_interface.rb:
27
27
  - name: Protocol Type
28
28
  required: true
29
29
  description: Protocol to apply on the interface data
30
- values:
30
+ # prettier-ignore
31
+ values:
31
32
  <%= MetaConfigParser.load('protocols.yaml').to_meta_config_yaml(8) %>
32
33
  tcpip_server_interface.rb:
33
34
  parameters:
@@ -52,7 +53,8 @@ tcpip_server_interface.rb:
52
53
  - name: Protocol Type
53
54
  required: true
54
55
  description: Protocol to apply on the interface data
55
- values:
56
+ # prettier-ignore
57
+ values:
56
58
  <%= MetaConfigParser.load('protocols.yaml').to_meta_config_yaml(8) %>
57
59
  udp_interface.rb:
58
60
  description: The UDP interface uses UDP packets to send and receive telemetry
@@ -142,73 +144,6 @@ serial_interface.rb:
142
144
  - name: Protocol Type
143
145
  required: true
144
146
  description: Protocol to apply on the interface data
145
- values:
147
+ # prettier-ignore
148
+ values:
146
149
  <%= MetaConfigParser.load('protocols.yaml').to_meta_config_yaml(8) %>
147
- cmd_tlm_server_interface.rb:
148
- description: Provides a connection to the OpenC3 Command and Telemetry Server.
149
- This allows scripts and other OpenC3 tools to send commands to the CmdTlmServer
150
- to enable and disable logging. It also allows scripts and other tools to
151
- receive a OpenC3 version information packet and a limits change packet which
152
- is sent when any telemetry items change limits states. The CmdTlmServer
153
- interface can be used by any OpenC3 configuration.
154
- linc_interface.rb:
155
- description: The LINC interface uses a single TCPIP socket to talk to a Ball
156
- Aerospace LINC Labview target.
157
- parameters:
158
- - name: Host
159
- required: true
160
- description: Machine name to connect to. Can be either a named
161
- machine (DNS entry) or IP address.
162
- values: .+
163
- - name: Port
164
- required: true
165
- description: Port to write commands to and read telemetry from
166
- values: \d{2,5}
167
- - name: Handshake Enabled
168
- required: false
169
- description: Enable command handshaking where commands block until the
170
- corresponding handshake message is received. Default is true.
171
- values: ["true", "false"]
172
- - name: Response Timeout
173
- required: false
174
- description: Number of seconds to wait for a handshaking response.
175
- Default is 5 seconds
176
- values: \d+
177
- - name: Read Timeout
178
- required: true
179
- description: Number of seconds to wait before aborting the read.
180
- Pass 'nil' to block on read. Default is nil.
181
- values: .+
182
- - name: Write Timeout
183
- required: true
184
- description: Number of seconds to wait before aborting the write.
185
- Pass 'nil' to block on write. Default is 5 seconds.
186
- values: .+
187
- - name: Length Bit Offset
188
- required: false
189
- description: The bit offset of the length field. Every packet using this
190
- interface must have the same structure such that the length field is the
191
- same size at the same location. Default is 0.
192
- values: \d+
193
- - name: Length Bit Size
194
- required: false
195
- description: The size in bits of the length field. Default is 16 bits.
196
- values: \d+
197
- - name: Length Value Offset
198
- required: false
199
- description: The offset to apply to the length field value. For example if
200
- the length field indicates packet length minus one, this value should be one.
201
- Default is 4.
202
- values: \d+
203
- - name: GUID Fieldname
204
- required: false
205
- description: Fieldname of the GUID field. Default is 'HDR_GUID'.
206
- values: .+
207
- - name: Length Endianness
208
- required: false
209
- description: The endianness of the length field. Default is BIG_ENDIAN.
210
- values: ["BIG_ENDIAN", "LITTLE_ENDIAN"]
211
- - name: Length Fieldname
212
- required: false
213
- description: Fieldname of the length field. Defaults is 'HDR_LENGTH'.
214
- values: .+
@@ -41,29 +41,6 @@ DISABLE_DISCONNECT:
41
41
  Use this keyword to prevent the user from disconnecting from the interface.
42
42
  This is typically used in a 'production' environment where you would not want
43
43
  the user to inadvertantly disconnect from a target.
44
- LOG:
45
- summary: Enable logging on the interface by the specified log writer
46
- description:
47
- LOG is only required if you want a log writer other than the default
48
- to log commands and telemetry on this interface
49
- warning: Choosing a custom log writer can prevent OpenC3 from reading back your log files
50
- parameters:
51
- - name: Name
52
- required: true
53
- description: Log writer name as defined by PACKET_LOG_WRITER
54
- values: \D\S*
55
- LOG_STORED:
56
- summary: Enable logging of stored telemetry on the interface by the specified log writer
57
- description:
58
- LOG_STORED allows you to specify a different log writer for stored telemetry
59
- (telemetry which has the 'stored' flag set in the packet). By default the stored telemetry
60
- is intermingled in the normal log file.
61
- warning: Choosing a custom log writer can prevent OpenC3 from reading back your log files
62
- parameters:
63
- - name: Name
64
- required: true
65
- description: Log writer name as defined by PACKET_LOG_WRITER
66
- values: \D\S*
67
44
  DONT_LOG:
68
45
  summary: Disable logging commands and telemetry on this interface
69
46
  LOG_RAW:
@@ -106,3 +106,11 @@ MICROSERVICE:
106
106
  required: true
107
107
  description: Environment variable name or file path to store secret
108
108
  values: .*
109
+ ROUTE_PREFIX:
110
+ summary: Prefix of route
111
+ description: Prefix of route to the microservice to expose externally with Traefik
112
+ parameters:
113
+ - name: Route Prefix
114
+ required: true
115
+ description: Route prefix. Must be unique across all scopes. Something like /myprefix
116
+ values: .*
@@ -156,6 +156,7 @@ TARGET:
156
156
  values: \d+
157
157
  TARGET_MICROSERVICE:
158
158
  summary: Breaks a target microservice out into its own process.
159
+ description:
159
160
  Can be used to give more resources to processing that is falling behind.
160
161
  If defined multiple times for the same type, will create multiple processes.
161
162
  Each process can be given specific packets to process with the PACKET keyword.
@@ -162,26 +162,6 @@ TITLE:
162
162
  required: true
163
163
  description: Text to display above the horizontal line
164
164
  values: .*
165
- # SPACER:
166
- # summary: Inserts a spacer into a layout. This can be used to
167
- # separate or align other widgets.
168
- # parameters:
169
- # - name: Width
170
- # required: true
171
- # description: The width of the spacer in pixels.
172
- # values: .*
173
- # - name: Height
174
- # required: true
175
- # description: The height of the spacer in pixels.
176
- # values: .*
177
- # - name: Horizontal Policy
178
- # required: false
179
- # description: The horizontal size policy of the spacer. Default is MINIMUM.
180
- # values: <%= %w(FIXED MINIMUM MAXIMUM PREFERRED EXPANDING MINIMUMEXPANDING IGNORED) %>
181
- # - name: Vertical Policy
182
- # required: false
183
- # description: The vertical size policy of the spacer. Default is MINIMUM.
184
- # values: <%= %w(FIXED MINIMUM MAXIMUM PREFERRED EXPANDING MINIMUMEXPANDING IGNORED) %>
185
165
  ARRAY:
186
166
  summary: Displays ARRAY data organized into rows and space separated
187
167
  parameters:
@@ -303,7 +283,8 @@ BLOCK:
303
283
  # values: .*
304
284
  FORMATVALUE:
305
285
  summary: Displays a box with a formatted value
306
- description: Data is formatted by the specified string rather than by a format string given in
286
+ description:
287
+ Data is formatted by the specified string rather than by a format string given in
307
288
  the telemetry definition files. The white portion of the box darkens to gray
308
289
  while the value remains stagnant, then brightens to white each time the value
309
290
  changes. Additionally the value is colored based on the items limits state
@@ -615,7 +596,8 @@ LABELVALUERANGEBAR:
615
596
  # values: .*
616
597
  LED:
617
598
  summary: Displays a LED which changes color based on telemetry values
618
- description: By default TRUE is green and FALSE is red and all other values are black.
599
+ description:
600
+ By default TRUE is green and FALSE is red and all other values are black.
619
601
  Additional values can be added by using the LED_COLOR setting. For example
620
602
  LED INST PARAMS VALUE3 RAW can be followed by SETTING LED_COLOR 0 GREEN,
621
603
  SETTING LED_COLOR 1 RED, and SETTING LED_COLOR ANY ORANGE.
@@ -1153,7 +1135,8 @@ TEXTBOX:
1153
1135
  # values: .*
1154
1136
  VALUE:
1155
1137
  summary: Displays a box with a telemetry item value
1156
- description: The white portion of the box darkens to gray while the value remains stagnant, then
1138
+ description:
1139
+ The white portion of the box darkens to gray while the value remains stagnant, then
1157
1140
  brightens to white each time the value changes. Additionally the value is
1158
1141
  colored based on the items limits state (Red for example if it is out of limits).
1159
1142
  parameters:
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/packets/binary_accessor'
@@ -28,7 +28,7 @@ class String
28
28
  # The printable range of ASCII characters
29
29
  PRINTABLE_RANGE = 32..126
30
30
  # Regular expression to identify a character that is not in the printable range
31
- NON_PRINTABLE_REGEX = /[^\s -~]/
31
+ NON_PRINTABLE_REGEX = /[^\s!-~]/
32
32
  # Regular expression to identify a String as a floating point number
33
33
  FLOAT_CHECK_REGEX = /\A\s*[-+]?\d*\.\d+\s*\z/
34
34
  # Regular expression to identify a String as a floating point number in
@@ -56,11 +56,15 @@ end
56
56
 
57
57
  class String
58
58
  NON_ASCII_PRINTABLE = /[^\x21-\x7e\s]/
59
-
59
+ NON_UTF8_PRINTABLE = /[\x00-\x08\x0E-\x1F\x7F]/
60
60
  def as_json(options = nil)
61
61
  as_utf8 = self.dup.force_encoding('UTF-8')
62
62
  if as_utf8.valid_encoding?
63
- return as_utf8
63
+ if as_utf8 =~ NON_UTF8_PRINTABLE
64
+ return self.to_json_raw_object
65
+ else
66
+ return as_utf8
67
+ end
64
68
  else
65
69
  return self.to_json_raw_object
66
70
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/microservices/microservice'
@@ -31,6 +31,15 @@ module OpenC3
31
31
 
32
32
  def run
33
33
  Dir.chdir @work_dir
34
+ begin
35
+ if @config["cmd"][0] != 'ruby'
36
+ # Try to make sure the cmd is executable
37
+ FileUtils.chmod 0777, @config["cmd"][0]
38
+ end
39
+ rescue Exception
40
+ # Its ok if this fails
41
+ end
42
+
34
43
  # Fortify: Process Control
35
44
  # This is dangerous! However, plugins need to be able to run whatever they want.
36
45
  # Only admins can install plugins and they need to be vetted for content.
@@ -42,22 +42,24 @@ module OpenC3
42
42
 
43
43
  # Set an item in the current value table
44
44
  def self.set_item(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
45
+ hash = JSON.parse(Store.hget("#{scope}__tlm__#{target_name}", packet_name), :allow_nan => true, :create_additions => true)
45
46
  case type
46
47
  when :WITH_UNITS
47
- field = "#{item_name}__U"
48
- value = value.to_s # WITH_UNITS should always be a string
48
+ hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
49
49
  when :FORMATTED
50
- field = "#{item_name}__F"
51
- value = value.to_s # FORMATTED should always be a string
50
+ hash["#{item_name}__F"] = value.to_s # FORMATTED should always be a string
52
51
  when :CONVERTED
53
- field = "#{item_name}__C"
52
+ hash["#{item_name}__C"] = value
54
53
  when :RAW
55
- field = item_name
54
+ hash[item_name] = value
55
+ when :ALL
56
+ hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
57
+ hash["#{item_name}__F"] = value.to_s # FORMATTED should always be a string
58
+ hash["#{item_name}__C"] = value
59
+ hash[item_name] = value
56
60
  else
57
61
  raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
58
62
  end
59
- hash = JSON.parse(Store.hget("#{scope}__tlm__#{target_name}", packet_name), :allow_nan => true, :create_additions => true)
60
- hash[field] = value
61
63
  Store.hset("#{scope}__tlm__#{target_name}", packet_name, JSON.generate(hash.as_json(:allow_nan => true)))
62
64
  end
63
65
 
@@ -69,7 +69,7 @@ module OpenC3
69
69
  if @color.nil?
70
70
  @color = '#%06x' % (rand * 0xffffff)
71
71
  end
72
- unless @color =~ /(#*)([0-9,a-f,A-f]{6})/
72
+ unless @color =~ /(#*)([0-9,a-f,A-F]{6})/
73
73
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
74
74
  end
75
75
  @color = "##{@color}" unless @color.start_with?('#')
@@ -23,6 +23,7 @@
23
23
  require 'openc3/top_level'
24
24
  require 'openc3/models/model'
25
25
  require 'openc3/models/metric_model'
26
+ require 'openc3/models/traefik_model'
26
27
  require 'openc3/utilities/bucket'
27
28
 
28
29
  module OpenC3
@@ -41,6 +42,7 @@ module OpenC3
41
42
  attr_accessor :ports
42
43
  attr_accessor :parent
43
44
  attr_accessor :secrets
45
+ attr_accessor :prefix
44
46
 
45
47
  # NOTE: The following three class methods are used by the ModelController
46
48
  # and are reimplemented to enable various Model class methods to work
@@ -99,6 +101,7 @@ module OpenC3
99
101
  plugin: nil,
100
102
  needs_dependencies: false,
101
103
  secrets: [],
104
+ prefix: nil,
102
105
  scope:
103
106
  )
104
107
  parts = name.split("__")
@@ -122,6 +125,7 @@ module OpenC3
122
125
  @container = container
123
126
  @needs_dependencies = needs_dependencies
124
127
  @secrets = secrets
128
+ @prefix = prefix
125
129
  @bucket = Bucket.getClient()
126
130
  end
127
131
 
@@ -141,7 +145,8 @@ module OpenC3
141
145
  'updated_at' => @updated_at,
142
146
  'plugin' => @plugin,
143
147
  'needs_dependencies' => @needs_dependencies,
144
- 'secrets' => @secrets.as_json(*a)
148
+ 'secrets' => @secrets.as_json(*a),
149
+ 'prefix' => @prefix
145
150
  }
146
151
  end
147
152
 
@@ -190,6 +195,9 @@ module OpenC3
190
195
  when 'SECRET'
191
196
  parser.verify_num_parameters(3, 3, "#{keyword} <Secret Type: ENV or FILE> <Secret Name> <Environment Variable Name or File Path>")
192
197
  @secrets << parameters.dup
198
+ when 'ROUTE_PREFIX'
199
+ parser.verify_num_parameters(1, 1, "#{keyword} <Route Prefix>")
200
+ @prefix = parameters[0]
193
201
  else
194
202
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Microservice: #{keyword} #{parameters.join(" ")}")
195
203
  end
@@ -214,9 +222,12 @@ module OpenC3
214
222
  end
215
223
  unless validate_only
216
224
  @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: key, body: data)
217
- ConfigTopic.write({ kind: 'created', type: 'microservice', name: @name, plugin: @plugin }, scope: @scope)
218
225
  end
219
226
  end
227
+ unless validate_only
228
+ TraefikModel.register_route(microservice_name: @name, port: @ports[0][0], prefix: @prefix) if @ports[0] and ports[0][0] and @prefix
229
+ ConfigTopic.write({ kind: 'created', type: 'microservice', name: @name, plugin: @plugin }, scope: @scope)
230
+ end
220
231
  end
221
232
 
222
233
  def undeploy
@@ -224,6 +235,7 @@ module OpenC3
224
235
  @bucket.list_objects(bucket: ENV['OPENC3_CONFIG_BUCKET'], prefix: prefix).each do |object|
225
236
  @bucket.delete_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: object.key)
226
237
  end
238
+ TraefikModel.unregister_route(microservice_name: @name, port: @ports[0][0], prefix: @prefix) if @ports[0] and ports[0][0] and @prefix
227
239
  ConfigTopic.write({ kind: 'deleted', type: 'microservice', name: @name, plugin: @plugin }, scope: @scope)
228
240
  rescue Exception => error
229
241
  Logger.error("Error undeploying microservice model #{@name} in scope #{@scope} due to #{error}")
@@ -63,20 +63,12 @@ module OpenC3
63
63
  # END NOTE
64
64
 
65
65
  # Loops over all items and returns objects that match a key value pair
66
- def self.filter(key, value, scope:, use_regex: false)
66
+ def self.filter(key, value, scope:, substr: false)
67
67
  filtered = {}
68
68
  results = all(scope: scope)
69
- regex = nil
70
- regex = Regexp.new(value) if use_regex
71
69
  results.each do |name, result|
72
- if regex
73
- if result[key] =~ regex
74
- filtered[name] = result
75
- end
76
- else
77
- if result[key] == value
78
- filtered[name] = result
79
- end
70
+ if result[key] == value || (substr && result[key].include?(value))
71
+ filtered[name] = result
80
72
  end
81
73
  end
82
74
  return filtered
@@ -78,7 +78,7 @@ module OpenC3
78
78
  if @color.nil?
79
79
  @color = '#%06x' % (rand * 0xffffff)
80
80
  end
81
- unless @color =~ /(#*)([0-9,a-f,A-f]{6})/
81
+ unless @color =~ /(#*)([0-9,a-f,A-F]{6})/
82
82
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
83
83
  end
84
84
  @color = "##{@color}" unless @color.start_with?('#')
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/models/model'
@@ -91,11 +91,10 @@ module OpenC3
91
91
  if color.nil?
92
92
  color = '#%06x' % (rand * 0xffffff)
93
93
  end
94
- valid_color = color =~ /(#*)([0-9,a-f,A-f]{6})/
94
+ valid_color = color =~ /[0-9,a-f,A-F]{6}/
95
95
  if valid_color.nil?
96
96
  raise RuntimeError.new "invalid color but in hex format. #FF0000"
97
97
  end
98
-
99
98
  unless color.start_with?('#')
100
99
  color = "##{color}"
101
100
  end
@@ -0,0 +1,47 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/utilities/store'
20
+
21
+ module OpenC3
22
+ class TraefikModel
23
+ def self.register_route(microservice_name:, port:, prefix:, priority: 20)
24
+ prefix = '/' + prefix unless prefix[0] == '/'
25
+ if ENV['KUBERNETES_SERVICE_HOST']
26
+ url = "http://#{microservice_name.gsub('__', '-')}:#{port}"
27
+ else
28
+ url = "http://openc3-operator:#{port}"
29
+ end
30
+ service_name = microservice_name
31
+ router_name = microservice_name
32
+ Store.set("traefik/http/services/#{service_name}/loadbalancer/servers/0/url", url)
33
+ Store.set("traefik/http/routers/#{router_name}/service", service_name)
34
+ Store.set("traefik/http/routers/#{router_name}/priority", priority)
35
+ Store.set("traefik/http/routers/#{router_name}/rule", "PathPrefix(`#{prefix}`)")
36
+ end
37
+
38
+ def self.unregister_route(microservice_name:)
39
+ service_name = microservice_name
40
+ router_name = microservice_name
41
+ Store.del("traefik/http/routers/#{router_name}/rule")
42
+ Store.del("traefik/http/routers/#{router_name}/priority")
43
+ Store.del("traefik/http/routers/#{router_name}/service")
44
+ Store.del("traefik/http/services/#{service_name}/loadbalancer/servers/0/url")
45
+ end
46
+ end
47
+ end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/models/model'
@@ -92,11 +92,10 @@ module OpenC3
92
92
  if color.nil?
93
93
  color = '#%06x' % (rand * 0xffffff)
94
94
  end
95
- valid_color = color =~ /(#*)([0-9,a-f,A-f]{6})/
95
+ valid_color = color =~ /[0-9,a-f,A-F]{6}/
96
96
  if valid_color.nil?
97
97
  raise TriggerGroupInputError.new "invalid color must be in hex format. #FF0000"
98
98
  end
99
-
100
99
  unless color.start_with?('#')
101
100
  color = "##{color}"
102
101
  end
@@ -65,7 +65,7 @@ module OpenC3
65
65
 
66
66
  endpoint = "/openc3-api/storage/upload/#{upload_path}"
67
67
  result = _get_presigned_request(endpoint, scope: scope)
68
- OpenC3::Logger.info "Writing #{upload_path} at #{result['url']}"
68
+ OpenC3::Logger.info "Writing #{upload_path}"
69
69
 
70
70
  # Try to put the file
71
71
  begin
@@ -104,11 +104,12 @@ module OpenC3
104
104
  if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
105
105
  local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
106
106
  if local_file
107
+ OpenC3::Logger.info "Reading local #{scope}/#{path}"
107
108
  file = Tempfile.new('target', binmode: true)
108
109
  file.write(local_file.read)
109
110
  local_file.close
110
111
  file.rewind
111
- return file if local_file
112
+ return file
112
113
  end
113
114
  end
114
115
 
@@ -133,7 +134,7 @@ module OpenC3
133
134
 
134
135
  endpoint = "/openc3-api/storage/download/#{scope}/#{path}"
135
136
  result = _get_presigned_request(endpoint, scope: scope)
136
- OpenC3::Logger.info "Reading #{scope}/#{path} at #{result['url']}"
137
+ OpenC3::Logger.info "Reading #{scope}/#{path}"
137
138
 
138
139
  # Try to get the file
139
140
  uri = _get_uri(result['url'])
@@ -461,22 +461,7 @@ module OpenC3
461
461
 
462
462
  # @param filename [String] Name of the file to open in the web browser
463
463
  def self.open_in_web_browser(filename)
464
- if filename
465
- if Kernel.is_windows?
466
- self.run_process("cmd /c \"start \"\" \"#{filename.gsub('/', '\\')}\"\"")
467
- elsif Kernel.is_mac?
468
- self.run_process("open -a Safari \"#{filename}\"")
469
- else
470
- which_firefox = `which firefox`.chomp
471
- if which_firefox =~ /Command not found/i or which_firefox =~ /no .* in/i
472
- raise "Firefox not found"
473
- else
474
- system_call = "#{which_firefox} \"#{filename}\""
475
- end
476
-
477
- self.run_process(system_call)
478
- end
479
- end
464
+ puts "open_in_web_browser is DEPRECATED"
480
465
  end
481
466
 
482
467
  # Temporarily set the working directory during a block
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/models/auth_model'
@@ -42,7 +42,9 @@ rescue LoadError
42
42
 
43
43
  if $openc3_authorize
44
44
  raise AuthError.new("Token is required") unless token
45
- raise AuthError.new("Token is invalid for '#{permission}' permission") unless OpenC3::AuthModel.verify(token, permission: permission)
45
+ unless OpenC3::AuthModel.verify(token, permission: permission)
46
+ raise AuthError.new("Current role is invalid for '#{permission}' permission")
47
+ end
46
48
  end
47
49
  end
48
50
 
@@ -119,6 +119,8 @@ module OpenC3
119
119
  end
120
120
  # Array of objects with key and size methods
121
121
  result
122
+ rescue Aws::S3::Errors::NoSuchBucket => error
123
+ raise NotFound, "Bucket '#{bucket}' does not exist."
122
124
  end
123
125
 
124
126
  # Lists the files under a specified path
@@ -164,6 +166,8 @@ module OpenC3
164
166
  token = resp.next_continuation_token
165
167
  end
166
168
  result
169
+ rescue Aws::S3::Errors::NoSuchBucket => error
170
+ raise NotFound, "Bucket '#{bucket}' does not exist."
167
171
  end
168
172
 
169
173
  # put_object fires off the request to store but does not confirm
@@ -21,6 +21,10 @@ ENV['OPENC3_CLOUD'] ||= 'local'
21
21
  # Interface class implemented by each cloud provider: AWS, GCS, Azure
22
22
  module OpenC3
23
23
  class Bucket
24
+ # Raised when the underlying bucket does not exist
25
+ class NotFound < RuntimeError
26
+ end
27
+
24
28
  def self.getClient
25
29
  raise 'OPENC3_CLOUD environment variable is required' unless ENV['OPENC3_CLOUD']
26
30
  # Base is AwsBucket which works with MINIO, Enterprise implements additional
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/operators/operator'
@@ -52,7 +52,7 @@ module OpenC3
52
52
 
53
53
  # Spawns short lived processes and ensures they complete
54
54
  class ProcessManager
55
- MONITOR_CYCLE_SECONDS = 10
55
+ MONITOR_CYCLE_SECONDS = 5
56
56
  CLEANUP_CYCLE_SECONDS = 600
57
57
 
58
58
  @@instance = nil
@@ -68,6 +68,7 @@ module OpenC3
68
68
  begin
69
69
  monitor()
70
70
  rescue => err
71
+ Logger.error("ProcessManager unexpectedly died\n#{err.formatted}", scope: 'DEFAULT')
71
72
  raise "ProcessManager unexpectedly died\n#{err.formatted}"
72
73
  end
73
74
  end
@@ -111,10 +112,10 @@ module OpenC3
111
112
  end
112
113
  processes_to_delete.each do |process|
113
114
  if process.status.state == "Complete"
114
- Logger.info "Process #{process.status.name}:#{process.process_type}:#{process.detail} completed with state #{process.status.state}"
115
+ Logger.info("Process #{process.status.name}:#{process.process_type}:#{process.detail} completed with state #{process.status.state}", scope: process.scope)
115
116
  else
116
- Logger.error "Process #{process.status.name}:#{process.process_type}:#{process.detail} completed with state #{process.status.state}"
117
- Logger.error "Process Output:\n#{process.status.output}"
117
+ Logger.error("Process #{process.status.name}:#{process.process_type}:#{process.detail} completed with state #{process.status.state}", scope: process.scope)
118
+ Logger.error("Process Output:\n#{process.status.output}", scope: process.scope)
118
119
  end
119
120
 
120
121
  @processes.delete(process)
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '5.4.2'
3
+ OPENC3_VERSION = '5.4.3-beta0'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '5'
7
7
  MINOR = '4'
8
- PATCH = '2'
9
- OTHER = ''
10
- BUILD = '6a7f2b4ff8e1255aa4d9768b539211b175cb9ec7'
8
+ PATCH = '3'
9
+ OTHER = 'pre.beta0'
10
+ BUILD = '3eeed1efa129ce27f14bffc2b6bab4428a20c500'
11
11
  end
12
- VERSION = '5.4.2'
13
- GEM_VERSION = '5.4.2'
12
+ VERSION = '5.4.3-beta0'
13
+ GEM_VERSION = '5.4.3.pre.beta0'
14
14
  end
data/lib/openc3.rb CHANGED
@@ -22,6 +22,9 @@
22
22
 
23
23
  # This file sets up using the OpenC3 framework
24
24
 
25
+ # Improve DNS (especially on Alpine)
26
+ require 'resolv-replace'
27
+
25
28
  # Set default encodings
26
29
  saved_verbose = $VERBOSE; $VERBOSE = nil
27
30
  Encoding.default_external = Encoding::ASCII_8BIT
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openc3
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.2
4
+ version: 5.4.3.pre.beta0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Melton
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-04 00:00:00.000000000 Z
12
+ date: 2023-02-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -669,7 +669,6 @@ files:
669
669
  - data/config/_interfaces.yaml
670
670
  - data/config/_items.yaml
671
671
  - data/config/_params.yaml
672
- - data/config/cmd_tlm_server.yaml
673
672
  - data/config/command.yaml
674
673
  - data/config/command_modifiers.yaml
675
674
  - data/config/command_telemetry.yaml
@@ -872,6 +871,7 @@ files:
872
871
  - lib/openc3/models/timeline_model.rb
873
872
  - lib/openc3/models/tool_config_model.rb
874
873
  - lib/openc3/models/tool_model.rb
874
+ - lib/openc3/models/traefik_model.rb
875
875
  - lib/openc3/models/trigger_group_model.rb
876
876
  - lib/openc3/models/trigger_model.rb
877
877
  - lib/openc3/models/widget_model.rb
@@ -925,7 +925,6 @@ files:
925
925
  - lib/openc3/system/system_config.rb
926
926
  - lib/openc3/system/target.rb
927
927
  - lib/openc3/tools/cmd_tlm_server/api.rb
928
- - lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb
929
928
  - lib/openc3/tools/cmd_tlm_server/interface_thread.rb
930
929
  - lib/openc3/tools/table_manager/table.rb
931
930
  - lib/openc3/tools/table_manager/table_config.rb
@@ -1012,9 +1011,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
1012
1011
  version: '2.7'
1013
1012
  required_rubygems_version: !ruby/object:Gem::Requirement
1014
1013
  requirements:
1015
- - - ">="
1014
+ - - ">"
1016
1015
  - !ruby/object:Gem::Version
1017
- version: '0'
1016
+ version: 1.3.1
1018
1017
  requirements: []
1019
1018
  rubygems_version: 3.3.14
1020
1019
  signing_key:
@@ -1,136 +0,0 @@
1
- ---
2
- TITLE:
3
- summary: Sets the Command and Telemetry Server window title
4
- parameters:
5
- - name: Text
6
- required: true
7
- description: Text to put in the title of the Command and Telemetry Server window
8
- values: .+
9
- PACKET_LOG_WRITER:
10
- summary: Declare a packet log writer
11
- description: Packet log writer is used to declare a packet log writer class and
12
- give it a name which can be referenced by an interface. This is required if you
13
- want interfaces to have their own dedicated log writers or want to combine
14
- various interfaces into a single log file. By default, OpenC3 logs all data
15
- on all interfaces into a single command log and a single telemetry log.
16
- This keyword can also be used if you want to declare a different log file class
17
- to create log files.
18
- warning: You should NOT override the default without consulting a OpenC3 expert
19
- as this may break the ability to successfully read and write log files.
20
- example: |
21
- PACKET_LOG_WRITER DEFAULT packet_log_writer.rb # Default
22
- # The default logger filename will be <DATE>_openc3tlm.bin and will create a new log every 1MB
23
- PACKET_LOG_WRITER DEFAULT packet_log_writer.rb openc3 true nil 1000000
24
- # Create a logger named OPENC3_LOG which creates a new log every 5 min (600s)
25
- PACKET_LOG_WRITER OPENC3_LOG packet_log_writer.rb openc3 true 600
26
- parameters:
27
- - name: Log Writer Name
28
- required: true
29
- description: The name of the log writer as reference by other cmd_tlm_server keywords.
30
- This name also appears in the Logging tab on the Command and Telemetry Server.
31
- values: .+
32
- - name: Filename
33
- required: true
34
- description: Ruby file to use when instantiating a new log writer
35
- values: '.+\.rb'
36
- - name: Parameters
37
- required: false
38
- description: Optional parameters to pass to the log writer class when instantiating it.
39
- AUTO_INTERFACE_TARGETS:
40
- summary: Automatically use each target's cmd_tlm_server.txt file to define the interface
41
- description: Look for a cmd_tlm_server.txt file at the top level
42
- of each target directory and use this file to configure the interface for that target.
43
- This is a good way of keeping the knowledge of how to interface to a target
44
- within that target. However, if you use substitute target names (by using DECLARE_TARGET)
45
- or use different IP addresses then this will not work and you'll have to use the
46
- INTERFACE_TARGET or INTERFACE keyword.
47
- INTERFACE_TARGET:
48
- summary: Load the specified target's cmd_tlm_server.txt configuration file
49
- example: |
50
- INTERFACE_TARGET OPENC3 # Look in the OPENC3 target directory for cmd_tlm_server.txt
51
- INTERFACE_TARGET OPENC3 config.txt # Look in the OPENC3 target directory for config.txt
52
- parameters:
53
- - name: Target Name
54
- required: true
55
- description: Name of the target
56
- values: .+
57
- - name: Configuration File
58
- required: false
59
- description: Configuration filename which contains the interface configuration.
60
- Defaults to 'cmd_tlm_server.txt'.
61
- values: .+
62
- INTERFACE:
63
- modifiers:
64
- <%= MetaConfigParser.load('interface_modifiers.yaml').to_meta_config_yaml(4) %>
65
- summary: Defines a connection to a physical target
66
- description: Interfaces are what OpenC3 uses to talk to a particular piece
67
- of hardware. Interfaces require a Ruby file which implements all the interface
68
- methods necessary to talk to the hardware. OpenC3 defines many built in interfaces
69
- or you can define your own as long as it implements the interface protocol.
70
- parameters:
71
- - name: Interface Name
72
- required: true
73
- description: Name of the interface. This name will appear in the
74
- Interfaces tab of the Server and is also referenced by other keywords.
75
- The OpenC3 convention is to name interfaces after their targets with
76
- '_INT' appended to the name, e.g. INST_INT for the INST target.
77
- values: \D\S*
78
- - name: Filename
79
- required: true
80
- description: Ruby file to use when instantiating the interface.
81
- values:
82
- <%= MetaConfigParser.load('_interfaces.yaml').to_meta_config_yaml(8) %>
83
- documentation: Additional parameters are required. Please see the [Interfaces](/docs/v5/interfaces)
84
- documentation for more details.
85
- ROUTER:
86
- modifiers:
87
- ROUTE:
88
- summary: Map an interface to a router
89
- description: Once an interface has been mapped to a router, all its received telemetry
90
- will be sent out through the router.
91
- parameters:
92
- - name: Interface
93
- required: true
94
- description: Name of the interface
95
- values: .+
96
- <%= MetaConfigParser.load('interface_modifiers.yaml').to_meta_config_yaml(4) %>
97
- summary: Create an interface which reverses cmd/tlm data
98
- description: Router creates an interface which receives command packets from
99
- their remote targets and send them out their interfaces. They receive telemetry
100
- packets from their interfaces and send them to their remote targets. This allows
101
- routers to be intermediaries between an external client and an actual device.
102
- parameters:
103
- - name: Name
104
- required: true
105
- description: Name of the router
106
- values: .+
107
- - name: Filename
108
- required: true
109
- description: Ruby file to use when instantiating the interface.
110
- values:
111
- <%= MetaConfigParser.load('_interfaces.yaml').to_meta_config_yaml(8) %>
112
- documentation: Additional parameters are required. Please see the [Interfaces](/docs/v5/interfaces)
113
- documentation for more details.
114
- COLLECT_METADATA:
115
- summary: Prompts the user for meta data when starting the Command and Telemetry Server
116
- BACKGROUND_TASK:
117
- modifiers:
118
- STOPPED:
119
- summary: Indicate the background task should not be automatically started
120
- summary: Create a background task in the Command and Telemetry Server
121
- description: The Server instantiates the class which must inherit from BackgroundTask
122
- and then calls the call() method which the class must implement. The call() method
123
- is only called once so if your background task is supposed to live on while the
124
- Server is running, you must implement your code in a loop with a sleep to not
125
- use all the CPU.
126
- example: BACKGROUND_TASK example_background_task.rb
127
- parameters:
128
- - name: Filename
129
- required: true
130
- description: Ruby file which contains the background task implementation.
131
- Must inherit from BackgroundTask and implement the call method.
132
- values: '.+\.rb'
133
- - name: Optional Arguments
134
- required: false
135
- description: Optional arguments to the background task constructor
136
- values: .+
@@ -1,323 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2022 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU Affero General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
- #
11
- # This program is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Affero General Public License for more details.
15
-
16
- # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
18
- # All Rights Reserved
19
- #
20
- # This file may also be used under the terms of a commercial license
21
- # if purchased from OpenC3, Inc.
22
-
23
- require 'openc3/config/config_parser'
24
-
25
- module OpenC3
26
- # Reads an ascii file that defines the configuration settings used to
27
- # configure the Command/Telemetry Server.
28
- class CmdTlmServerConfig
29
- # @return [Hash<String, Interface>] Interfaces hash
30
- attr_accessor :interfaces
31
- # @return [Hash<String, Interface>] Routers hash
32
- attr_accessor :routers
33
- # @return [Hash<String, PacketLogWriterPair>] Packet log writer hash. Each
34
- # pair encapsulates a command and telemetry log writer.
35
- attr_accessor :packet_log_writer_pairs
36
- # @return [Array<BackgroundTask>] Array of background tasks
37
- attr_accessor :background_tasks
38
- # @return [String] Command and Telemetry Server title
39
- attr_accessor :title
40
- # @return [Boolean] Flag indicating if meta data should be collected
41
- attr_accessor :metadata
42
-
43
- # Create a default pair of packet log writers and parses the
44
- # configuration file.
45
- #
46
- # @param filename [String] The name of the configuration file to parse
47
- def initialize(filename, system_config)
48
- @system_config = system_config
49
- @interfaces = {}
50
- @routers = {}
51
- @packet_log_writer_pairs = {}
52
- # cmd_log_writer = System.default_packet_log_writer.new(:CMD, *System.default_packet_log_writer_params)
53
- # tlm_log_writer = System.default_packet_log_writer.new(:TLM, *System.default_packet_log_writer_params)
54
- # @packet_log_writer_pairs['DEFAULT'] = PacketLogWriterPair.new(cmd_log_writer, tlm_log_writer)
55
- @background_tasks = []
56
- @title = nil
57
- @metadata = false
58
- process_file(filename)
59
- end
60
-
61
- protected
62
-
63
- def get_target_interface_name(target_name)
64
- @interfaces.each do |interface_name, interface|
65
- return interface_name if interface.target_names.include?(target_name)
66
- end
67
- nil
68
- end
69
-
70
- def setup_interface_or_router
71
- current_interface_or_router = OpenStruct.new
72
- current_interface_or_router.interfaces = []
73
- current_interface_or_router.routers = []
74
- current_interface_or_router.target_names = []
75
- current_interface_or_router
76
- end
77
-
78
- # Processes a file and adds in the configuration defined in the file
79
- #
80
- # @param filename [String] The name of the configuration file to parse
81
- # @param recursive [Boolean] Whether process_file is being called
82
- # recursively
83
- def process_file(filename, recursive = false)
84
- current_interface_or_router = nil
85
- current_type = nil
86
- current_interface_log_added = false
87
-
88
- Logger.info "Processing CmdTlmServer configuration in file: #{File.expand_path(filename)}"
89
-
90
- parser = ConfigParser.new("https://openc3.com/docs/v5")
91
- parser.parse_file(filename) do |keyword, params|
92
- case keyword
93
- when 'TITLE'
94
- raise parser.error("#{keyword} not allowed in target #{filename}") if recursive
95
-
96
- parser.verify_num_parameters(1, 1, "#{keyword} <Title Text>")
97
- @title = params[0]
98
-
99
- when 'PACKET_LOG_WRITER'
100
- # usage = "PACKET_LOG_WRITER <Name> <Filename> <Specific Parameters>"
101
- # parser.verify_num_parameters(2, nil, usage)
102
- # packet_log_writer_name = params[0].upcase
103
- # packet_log_writer_class = OpenC3.require_class(params[1])
104
-
105
- # # Verify not overridding a packet log writer that is already associated with an interface
106
- # packet_log_writer_pair = @packet_log_writer_pairs[packet_log_writer_name]
107
- # if packet_log_writer_pair
108
- # @interfaces.each do |interface_name, interface|
109
- # if interface.packet_log_writer_pairs.include?(packet_log_writer_pair)
110
- # raise parser.error("Redefining Packet Log Writer #{packet_log_writer_name} not allowed after it is associated with an interface")
111
- # end
112
- # end
113
- # end
114
-
115
- # if params[2]
116
- # cmd_log_writer = packet_log_writer_class.new(:CMD, *params[2..-1])
117
- # tlm_log_writer = packet_log_writer_class.new(:TLM, *params[2..-1])
118
- # @packet_log_writer_pairs[packet_log_writer_name] = PacketLogWriterPair.new(cmd_log_writer, tlm_log_writer)
119
- # else
120
- # cmd_log_writer = packet_log_writer_class.new(:CMD)
121
- # tlm_log_writer = packet_log_writer_class.new(:TLM)
122
- # @packet_log_writer_pairs[packet_log_writer_name] = PacketLogWriterPair.new(cmd_log_writer, tlm_log_writer)
123
- # end
124
-
125
- when 'AUTO_INTERFACE_TARGETS'
126
- raise parser.error("#{keyword} not allowed in target #{filename}") if recursive
127
-
128
- usage = "#{keyword}"
129
- parser.verify_num_parameters(0, 0, usage)
130
- @system_config.targets.each do |target_name, target|
131
- target_filename = File.join(target.dir, 'cmd_tlm_server.txt')
132
- if File.exist?(target_filename)
133
- # Skip this target if it's already been assigned an interface
134
- next if get_target_interface_name(target.name)
135
- raise parser.error("Cannot use #{keyword} with target name substitutions: #{target.name} != #{target.original_name}") if target.name != target.original_name
136
-
137
- process_file(target_filename, true)
138
- end
139
- end
140
-
141
- when 'INTERFACE_TARGET'
142
- raise parser.error("#{keyword} not allowed in target #{filename}") if recursive
143
-
144
- usage = "#{keyword} <Target Name> <Config File (defaults to cmd_tlm_server.txt)>"
145
- parser.verify_num_parameters(1, 2, usage)
146
- target = @system_config.targets[params[0].upcase]
147
- raise parser.error("Unknown target: #{params[0].upcase}") unless target
148
-
149
- interface_name = get_target_interface_name(target.name)
150
- raise parser.error("Target #{target.name} already mapped to interface #{interface_name}") if interface_name
151
-
152
- target_filename = params[1]
153
- target_filename = 'cmd_tlm_server.txt' unless target_filename
154
- target_filename = File.join(target.dir, target_filename)
155
- if File.exist?(target_filename)
156
- process_file(target_filename, true)
157
- else
158
- raise parser.error("#{target_filename} does not exist")
159
- end
160
-
161
- when 'INTERFACE'
162
- usage = "INTERFACE <Name> <Filename> <Specific Parameters>"
163
- parser.verify_num_parameters(2, nil, usage)
164
- interface_name = params[0].upcase
165
- raise parser.error("Interface '#{interface_name}' defined twice") if @interfaces[interface_name]
166
-
167
- # interface_class = OpenC3.require_class(params[1])
168
- # if params[2]
169
- # current_interface_or_router = interface_class.new(*params[2..-1])
170
- # else
171
- # current_interface_or_router = interface_class.new
172
- # end
173
- current_interface_or_router = setup_interface_or_router()
174
- current_type = :INTERFACE
175
- current_interface_log_added = false
176
- # current_interface_or_router.packet_log_writer_pairs << @packet_log_writer_pairs['DEFAULT']
177
- current_interface_or_router.name = interface_name
178
- current_interface_or_router.config_params = params[1..-1]
179
- @interfaces[interface_name] = current_interface_or_router
180
-
181
- when 'LOG', 'LOG_STORED', 'DONT_LOG', 'TARGET'
182
- raise parser.error("No current interface for #{keyword}") unless current_interface_or_router and current_type == :INTERFACE
183
-
184
- case keyword
185
-
186
- when 'LOG'
187
- parser.verify_num_parameters(1, 1, "#{keyword} <Packet Log Writer Name>")
188
- # packet_log_writer_pair = @packet_log_writer_pairs[params[0].upcase]
189
- # raise parser.error("Unknown packet log writer: #{params[0].upcase}") unless packet_log_writer_pair
190
- # current_interface_or_router.packet_log_writer_pairs.delete(@packet_log_writer_pairs['DEFAULT']) unless current_interface_log_added
191
- current_interface_log_added = true
192
- # current_interface_or_router.packet_log_writer_pairs << packet_log_writer_pair unless current_interface_or_router.packet_log_writer_pairs.include?(packet_log_writer_pair)
193
-
194
- when 'LOG_STORED'
195
- parser.verify_num_parameters(1, 1, "#{keyword} <Packet Log Writer Name>")
196
- # packet_log_writer_pair = @packet_log_writer_pairs[params[0].upcase]
197
- # raise parser.error("Unknown packet log writer: #{params[0].upcase}") unless packet_log_writer_pair
198
- # current_interface_or_router.stored_packet_log_writer_pairs << packet_log_writer_pair unless current_interface_or_router.stored_packet_log_writer_pairs.include?(packet_log_writer_pair)
199
-
200
- when 'DONT_LOG'
201
- parser.verify_num_parameters(0, 0, "#{keyword}")
202
- # current_interface_or_router.packet_log_writer_pairs = []
203
-
204
- when 'TARGET'
205
- parser.verify_num_parameters(1, 1, "#{keyword} <Target Name>")
206
- target_name = params[0].upcase
207
- target = @system_config.targets[target_name]
208
- if target
209
- interface_name = get_target_interface_name(target.name)
210
- raise parser.error("Target #{target.name} already mapped to interface #{interface_name}") if interface_name
211
-
212
- target.interface = current_interface_or_router
213
- current_interface_or_router.target_names << target_name
214
- else
215
- raise parser.error("Unknown target #{target_name} mapped to interface #{current_interface_or_router.name}")
216
- end
217
-
218
- end # end case keyword for all keywords that require a current interface
219
-
220
- when 'DONT_CONNECT', 'DONT_RECONNECT', 'RECONNECT_DELAY', 'DISABLE_DISCONNECT', 'LOG_RAW', 'OPTION', 'PROTOCOL'
221
- raise parser.error("No current interface or router for #{keyword}") unless current_interface_or_router
222
-
223
- case keyword
224
-
225
- when 'DONT_CONNECT'
226
- parser.verify_num_parameters(0, 0, "#{keyword}")
227
- current_interface_or_router.connect_on_startup = false
228
-
229
- when 'DONT_RECONNECT'
230
- parser.verify_num_parameters(0, 0, "#{keyword}")
231
- current_interface_or_router.auto_reconnect = false
232
-
233
- when 'RECONNECT_DELAY'
234
- parser.verify_num_parameters(1, 1, "#{keyword} <Delay in Seconds>")
235
- current_interface_or_router.reconnect_delay = Float(params[0])
236
-
237
- when 'DISABLE_DISCONNECT'
238
- parser.verify_num_parameters(0, 0, "#{keyword}")
239
- current_interface_or_router.disable_disconnect = true
240
-
241
- when 'LOG_RAW',
242
- parser.verify_num_parameters(0, nil, "#{keyword} <Raw Logger Class File (optional)> <Raw Logger Parameters (optional)>")
243
- # current_interface_or_router.raw_logger_pair = RawLoggerPair.new(current_interface_or_router.name, params)
244
- # current_interface_or_router.start_raw_logging
245
-
246
- when 'OPTION'
247
- parser.verify_num_parameters(2, nil, "#{keyword} <Option Name> <Option Value 1> <Option Value 2 (optional)> <etc>")
248
- # current_interface_or_router.set_option(params[0], params[1..-1])
249
-
250
- when 'PROTOCOL'
251
- usage = "#{keyword} <READ WRITE READ_WRITE> <protocol filename or classname> <Protocol specific parameters>"
252
- parser.verify_num_parameters(2, nil, usage)
253
- unless %w(READ WRITE READ_WRITE).include? params[0].upcase
254
- raise parser.error("Invalid protocol type: #{params[0]}", usage)
255
- end
256
-
257
- begin
258
- # klass = OpenC3.require_class(params[1])
259
- # current_interface_or_router.add_protocol(klass, params[2..-1], params[0].upcase.intern)
260
- rescue LoadError, StandardError => error
261
- raise parser.error(error.message, usage)
262
- end
263
-
264
- end # end case keyword for all keywords that require a current interface or router
265
-
266
- when 'ROUTER'
267
- usage = "ROUTER <Name> <Filename> <Specific Parameters>"
268
- parser.verify_num_parameters(2, nil, usage)
269
- router_name = params[0].upcase
270
- raise parser.error("Router '#{router_name}' defined twice") if @routers[router_name]
271
-
272
- # router_class = OpenC3.require_class(params[1])
273
- # if params[2]
274
- # current_interface_or_router = router_class.new(*params[2..-1])
275
- # else
276
- # current_interface_or_router = router_class.new
277
- # end
278
- current_interface_or_router = setup_interface_or_router()
279
- current_type = :ROUTER
280
- current_interface_or_router.name = router_name
281
- @routers[router_name] = current_interface_or_router
282
-
283
- when 'ROUTE'
284
- raise parser.error("No current router for #{keyword}") unless current_interface_or_router and current_type == :ROUTER
285
-
286
- usage = "ROUTE <Interface Name>"
287
- parser.verify_num_parameters(1, 1, usage)
288
- interface_name = params[0].upcase
289
- interface = @interfaces[interface_name]
290
- raise parser.error("Unknown interface #{interface_name} mapped to router #{current_interface_or_router.name}") unless interface
291
-
292
- unless current_interface_or_router.interfaces.include? interface
293
- current_interface_or_router.interfaces << interface
294
- interface.routers << current_interface_or_router
295
- end
296
-
297
- when 'BACKGROUND_TASK'
298
- usage = "#{keyword} <Filename> <Specific Parameters>"
299
- parser.verify_num_parameters(1, nil, usage)
300
- # background_task = OpenC3.require_class(params[0])
301
- if params[1]
302
- @background_tasks << params
303
- else
304
- @background_tasks << params
305
- end
306
-
307
- when 'STOPPED'
308
- parser.verify_num_parameters(0, 0, "#{keyword}")
309
- raise parser.error("No BACKGROUND_TASK defined") if @background_tasks.empty?
310
- # @background_tasks[-1].stopped = true
311
-
312
- when 'COLLECT_METADATA'
313
- parser.verify_num_parameters(0, 0, "#{keyword}")
314
- @metadata = true
315
-
316
- else
317
- # blank lines will have a nil keyword and should not raise an exception
318
- raise parser.error("Unknown keyword: #{keyword}") unless keyword.nil?
319
- end # case
320
- end # loop
321
- end
322
- end
323
- end