openc3 6.9.1 → 6.9.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83838350c2ec54b5fcd1b6108f42fe9d7f45fd24f6de04fb7c5c98855251b9b9
4
- data.tar.gz: c1b89314a5af6f7740857228d01c0ab9e2b2e03e59c209b0e646fefb4f281425
3
+ metadata.gz: 4d4fd7006c78d3a21531579d68d42bc5cba596c92091e8cd7895c4b42ecff569
4
+ data.tar.gz: 85fdaa738dafbfafcc16fb463abb5d86517f9f1edefb4bbef9a5e7171738211c
5
5
  SHA512:
6
- metadata.gz: 35be666ae0ea4d134fa6c7d54d79ee323e5d878918c25706d17514b1db8b28b6ca05c6c0f175426f285227e6fd16d6b90ccbf21316c71057aaaf958660a7c8a7
7
- data.tar.gz: 3c0f703c797d6fbd1be90d526a91ac94a06ec6d9ad042e3ea1212da4c73557be6e4634be73ca49f17c8277f7b7052154e0283b0a994f84f91cf96422811155ac
6
+ metadata.gz: 419ddee4f6203f3500c9d3eb45347824dfa57a074527086fd8bfdaee16c4dc10ec07b3b78122e1a753a064913bbb1193f29344e260ba7a04b029cdb11682a9e7
7
+ data.tar.gz: 961d67c9c972a2cdf60c31c9279b69a7e1fc315e62813935eb66fefbbd853cf931c633c36aa6b9606cb1eedfd66ef8ba2db07b34f24acf99967aa6983755deb3
data/bin/openc3cli CHANGED
@@ -875,6 +875,22 @@ if not ARGV[0].nil? # argument(s) given
875
875
  case ARGV[0].downcase
876
876
 
877
877
  when 'irb'
878
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
879
+ puts "Usage: cli irb"
880
+ puts ""
881
+ puts "Start an interactive Ruby (IRB) session with COSMOS libraries loaded"
882
+ puts ""
883
+ puts "This provides access to all COSMOS classes and methods for interactive"
884
+ puts "debugging and exploration. Use 'exit' or Ctrl-D to quit the IRB session."
885
+ puts ""
886
+ puts "Example:"
887
+ puts " cli irb"
888
+ puts " > require 'openc3'"
889
+ puts " > OpenC3::System.targets"
890
+ puts ""
891
+ puts "Note: For IRB-specific options, start IRB first then type 'help'"
892
+ exit 0
893
+ end
878
894
  ARGV.clear
879
895
  IRB.start
880
896
 
@@ -882,6 +898,29 @@ if not ARGV[0].nil? # argument(s) given
882
898
  cli_script(ARGV[1..-1])
883
899
 
884
900
  when 'rake'
901
+ # Check for --help first, before checking for Rakefile
902
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
903
+ puts "Usage: cli rake [RAKE_OPTIONS] [TASKS...]"
904
+ puts ""
905
+ puts "Run rake tasks in the current directory"
906
+ puts ""
907
+ puts "This runs the standard Ruby rake tool with all COSMOS libraries available."
908
+ puts "A Rakefile must exist in the current directory."
909
+ puts ""
910
+ puts "Common rake options:"
911
+ puts " -T, --tasks List all available rake tasks with descriptions"
912
+ puts " -D, --describe PATTERN Describe tasks matching PATTERN"
913
+ puts " -h, --help Show rake's full help message"
914
+ puts ""
915
+ puts "Examples:"
916
+ puts " cli rake -T # List all available tasks"
917
+ puts " cli rake build # Run the 'build' task"
918
+ puts " cli rake test # Run tests"
919
+ puts ""
920
+ puts "Note: Must be run in a directory containing a Rakefile"
921
+ exit 0
922
+ end
923
+ # Now check for Rakefile existence
885
924
  if File.exist?('Rakefile')
886
925
  puts `rake #{ARGV[1..-1].join(' ')}`
887
926
  else
@@ -889,9 +928,70 @@ if not ARGV[0].nil? # argument(s) given
889
928
  end
890
929
 
891
930
  when 'validate'
931
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
932
+ puts "Usage: cli validate PLUGIN.gem [SCOPE] [VARIABLES.json]"
933
+ puts ""
934
+ puts "Validate a COSMOS plugin gem file"
935
+ puts ""
936
+ puts "Arguments:"
937
+ puts " PLUGIN.gem Plugin gem file to validate (required)"
938
+ puts " SCOPE Scope for validation (optional, default: DEFAULT)"
939
+ puts " VARIABLES.json Variables JSON file (optional)"
940
+ puts ""
941
+ puts "Options:"
942
+ puts " -h, --help Show this help message"
943
+ exit(ARGV[1].nil? ? 1 : 0)
944
+ end
892
945
  validate_plugin(ARGV[1], scope: ARGV[2], variables_file: ARGV[3])
893
946
 
894
947
  when 'load'
948
+ # Check for help flag or missing arguments
949
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
950
+ puts "Usage:"
951
+ puts " cli load PLUGIN.gem"
952
+ puts " cli load PLUGIN.gem --variables VARIABLES.json"
953
+ puts " cli load PLUGIN.gem SCOPE PLUGIN_HASH.json [force]"
954
+ puts " cli load PLUGIN.gem --variables VARIABLES.json SCOPE PLUGIN_HASH.json [force]"
955
+ puts ""
956
+ puts "Load a COSMOS plugin gem file"
957
+ puts ""
958
+ puts "Common Usage (Auto-detect):"
959
+ puts " cli load PLUGIN.gem"
960
+ puts " - Installs new plugin in DEFAULT scope"
961
+ puts " - Automatically detects and upgrades if plugin already exists"
962
+ puts " - Skips installation if same version already installed"
963
+ puts ""
964
+ puts " cli load PLUGIN.gem --variables VARIABLES.json"
965
+ puts " - Same as above, but provides variables for plugin configuration"
966
+ puts ""
967
+ puts "Advanced Usage (Manual Control):"
968
+ puts " cli load PLUGIN.gem SCOPE PLUGIN_HASH.json [force]"
969
+ puts " - Used by Admin UI for plugin create/edit/upgrade operations"
970
+ puts " - Requires PLUGIN_HASH.json (output from install_phase1)"
971
+ puts " - 'force' argument forces reinstall even if version unchanged"
972
+ puts ""
973
+ puts "Arguments:"
974
+ puts " PLUGIN.gem Plugin gem file to load (required)"
975
+ puts " SCOPE Scope to install plugin in (default: DEFAULT)"
976
+ puts " PLUGIN_HASH.json Plugin hash JSON file from install_phase1 (optional)"
977
+ puts " force Force plugin installation even if no changes (optional)"
978
+ puts ""
979
+ puts "Options:"
980
+ puts " --variables FILE Variables JSON file for plugin installation"
981
+ puts " -h, --help Show this help message"
982
+ puts ""
983
+ puts "IMPORTANT LIMITATION:"
984
+ puts " To specify SCOPE without PLUGIN_HASH.json, you must use the --variables"
985
+ puts " option (even with an empty JSON file) to prevent argument misinterpretation."
986
+ puts ""
987
+ puts "Examples:"
988
+ puts " cli load my-plugin-1.0.0.gem"
989
+ puts " cli load my-plugin-1.0.0.gem --variables vars.json"
990
+ puts " cli load my-plugin-1.0.0.gem DEFAULT plugin_hash.json"
991
+ puts " cli load my-plugin-1.0.0.gem DEFAULT plugin_hash.json force"
992
+ exit(ARGV[1].nil? ? 1 : 0)
993
+ end
994
+
895
995
  # force is a boolean so if they pass 'force' it is true
896
996
  # See plugins_controller.rb install for usage
897
997
  variables_option = ARGV.find_index('--variables')
@@ -908,15 +1008,68 @@ if not ARGV[0].nil? # argument(s) given
908
1008
  load_plugin(ARGV[1], scope: scope, plugin_hash_file: plugin_hash_file, force: force, variables_file: variables_file)
909
1009
 
910
1010
  when 'list'
1011
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1012
+ puts "Usage: cli list [SCOPE]"
1013
+ puts ""
1014
+ puts "List all installed plugins in the specified scope"
1015
+ puts ""
1016
+ puts "Arguments:"
1017
+ puts " SCOPE Scope to list plugins from (optional, default: DEFAULT)"
1018
+ puts ""
1019
+ puts "Options:"
1020
+ puts " -h, --help Show this help message"
1021
+ exit 0
1022
+ end
911
1023
  list_plugins(scope: ARGV[1])
912
1024
 
913
1025
  when 'unload'
1026
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1027
+ puts "Usage: cli unload PLUGIN_NAME [SCOPE]"
1028
+ puts ""
1029
+ puts "Unload a COSMOS plugin"
1030
+ puts ""
1031
+ puts "Arguments:"
1032
+ puts " PLUGIN_NAME Name of the plugin to unload (required)"
1033
+ puts " SCOPE Scope to unload from (optional, default: DEFAULT)"
1034
+ puts ""
1035
+ puts "Options:"
1036
+ puts " -h, --help Show this help message"
1037
+ exit(ARGV[1].nil? ? 1 : 0)
1038
+ end
914
1039
  unload_plugin(ARGV[1], scope: ARGV[2])
915
1040
 
916
1041
  when 'pkginstall', 'geminstall'
1042
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1043
+ puts "Usage: cli pkginstall PACKAGE_NAME [SCOPE]"
1044
+ puts " cli geminstall GEM_NAME [SCOPE]"
1045
+ puts ""
1046
+ puts "Install a package/gem into a loaded plugin"
1047
+ puts ""
1048
+ puts "Arguments:"
1049
+ puts " PACKAGE_NAME Name of the package to install (required)"
1050
+ puts " SCOPE Scope for installation (optional, default: DEFAULT)"
1051
+ puts ""
1052
+ puts "Options:"
1053
+ puts " -h, --help Show this help message"
1054
+ exit(ARGV[1].nil? ? 1 : 0)
1055
+ end
917
1056
  cli_pkg_install(ARGV[1], scope: ARGV[2])
918
1057
 
919
1058
  when 'pkguninstall', 'gemuninstall'
1059
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1060
+ puts "Usage: cli pkguninstall PACKAGE_NAME [SCOPE]"
1061
+ puts " cli gemuninstall GEM_NAME [SCOPE]"
1062
+ puts ""
1063
+ puts "Uninstall a package/gem from a loaded plugin"
1064
+ puts ""
1065
+ puts "Arguments:"
1066
+ puts " PACKAGE_NAME Name of the package to uninstall (required)"
1067
+ puts " SCOPE Scope for uninstallation (optional, default: DEFAULT)"
1068
+ puts ""
1069
+ puts "Options:"
1070
+ puts " -h, --help Show this help message"
1071
+ exit(ARGV[1].nil? ? 1 : 0)
1072
+ end
920
1073
  cli_pkg_uninstall(ARGV[1], scope: ARGV[2])
921
1074
 
922
1075
  when 'generate'
@@ -934,6 +1087,19 @@ if not ARGV[0].nil? # argument(s) given
934
1087
  xtce_converter(ARGV[1..-1])
935
1088
 
936
1089
  when 'bridge'
1090
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1091
+ puts "Usage: cli bridge [FILENAME] [PARAMS...]"
1092
+ puts ""
1093
+ puts "Run a COSMOS bridge from a bridge configuration file"
1094
+ puts ""
1095
+ puts "Arguments:"
1096
+ puts " FILENAME Bridge config file (optional, default: bridge.txt)"
1097
+ puts " PARAMS Additional parameters to pass to bridge"
1098
+ puts ""
1099
+ puts "Options:"
1100
+ puts " -h, --help Show this help message"
1101
+ exit 0
1102
+ end
937
1103
  ENV['OPENC3_NO_STORE'] = '1'
938
1104
  filename = ARGV[1]
939
1105
  filename = 'bridge.txt' unless filename
@@ -942,6 +1108,19 @@ if not ARGV[0].nil? # argument(s) given
942
1108
  run_bridge(filename, params)
943
1109
 
944
1110
  when 'bridgegem'
1111
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1112
+ puts "Usage: cli bridgegem GEM_NAME [PARAMS...]"
1113
+ puts ""
1114
+ puts "Run a COSMOS bridge from a gem's bridge.txt file"
1115
+ puts ""
1116
+ puts "Arguments:"
1117
+ puts " GEM_NAME Name of the gem containing bridge.txt (required)"
1118
+ puts " PARAMS Additional parameters to pass to bridge"
1119
+ puts ""
1120
+ puts "Options:"
1121
+ puts " -h, --help Show this help message"
1122
+ exit(ARGV[1].nil? ? 1 : 0)
1123
+ end
945
1124
  ENV['OPENC3_NO_STORE'] = '1'
946
1125
  filename = nil
947
1126
  gem_name = ARGV[1]
@@ -967,6 +1146,18 @@ if not ARGV[0].nil? # argument(s) given
967
1146
  run_bridge(filename, params)
968
1147
 
969
1148
  when 'bridgesetup'
1149
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1150
+ puts "Usage: cli bridgesetup [FILENAME]"
1151
+ puts ""
1152
+ puts "Generate a default bridge configuration file"
1153
+ puts ""
1154
+ puts "Arguments:"
1155
+ puts " FILENAME Output filename (optional, default: bridge.txt)"
1156
+ puts ""
1157
+ puts "Options:"
1158
+ puts " -h, --help Show this help message"
1159
+ exit 0
1160
+ end
970
1161
  ENV['OPENC3_NO_STORE'] = '1'
971
1162
  filename = ARGV[1]
972
1163
  filename = 'bridge.txt' unless filename
@@ -978,10 +1169,36 @@ if not ARGV[0].nil? # argument(s) given
978
1169
  print_usage()
979
1170
 
980
1171
  when 'redis'
1172
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1173
+ puts "Usage: cli redis COMMAND [ARGS...]"
1174
+ puts ""
1175
+ puts "Interact with the Redis database"
1176
+ puts ""
1177
+ puts "Commands:"
1178
+ puts " keys Get all Redis keys"
1179
+ puts " hget HASH KEY Get a value from a Redis hash"
1180
+ puts ""
1181
+ puts "Options:"
1182
+ puts " -h, --help Show this help message"
1183
+ exit 0
1184
+ end
981
1185
  case (ARGV[1])
982
1186
  when 'keys'
983
1187
  get_redis_keys()
984
1188
  when 'hget'
1189
+ if ARGV[2].nil? || ARGV[3].nil? || ARGV[2] == '--help' || ARGV[2] == '-h'
1190
+ puts "Usage: cli redis hget HASH KEY"
1191
+ puts ""
1192
+ puts "Get a value from a Redis hash"
1193
+ puts ""
1194
+ puts "Arguments:"
1195
+ puts " HASH Redis hash name (required)"
1196
+ puts " KEY Key within the hash (required)"
1197
+ puts ""
1198
+ puts "Options:"
1199
+ puts " -h, --help Show this help message"
1200
+ exit(ARGV[2].nil? || ARGV[3].nil? ? 1 : 0)
1201
+ end
985
1202
  redis = Redis.new(url: $redis_url, username: ENV['OPENC3_REDIS_USERNAME'], password: ENV['OPENC3_REDIS_PASSWORD'])
986
1203
  puts JSON.parse(redis.hget(ARGV[2], ARGV[3]), allow_nan: true, create_additions: true)
987
1204
  else
@@ -990,6 +1207,16 @@ if not ARGV[0].nil? # argument(s) given
990
1207
  end
991
1208
 
992
1209
  when 'removebase'
1210
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1211
+ puts "Usage: cli removebase"
1212
+ puts ""
1213
+ puts "Remove non-enterprise tool base and admin plugins from all scopes"
1214
+ puts "This is typically used to support enterprise upgrades"
1215
+ puts ""
1216
+ puts "Options:"
1217
+ puts " -h, --help Show this help message"
1218
+ exit 0
1219
+ end
993
1220
  # Used to remove tool base to better support enterprise upgrade
994
1221
  scopes = OpenC3::ScopeModel.all
995
1222
  scopes.each do |scope_name, _scope|
@@ -1005,6 +1232,16 @@ if not ARGV[0].nil? # argument(s) given
1005
1232
  end
1006
1233
 
1007
1234
  when 'removeenterprise'
1235
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1236
+ puts "Usage: cli removeenterprise"
1237
+ puts ""
1238
+ puts "Remove all enterprise plugins from all scopes"
1239
+ puts "This is typically used to support downgrades"
1240
+ puts ""
1241
+ puts "Options:"
1242
+ puts " -h, --help Show this help message"
1243
+ exit 0
1244
+ end
1008
1245
  # Used to remove enterprise plugins to better support downgrade
1009
1246
  scopes = OpenC3::ScopeModel.all
1010
1247
  scopes.each do |scope_name, _scope|
@@ -1017,6 +1254,19 @@ if not ARGV[0].nil? # argument(s) given
1017
1254
  end
1018
1255
 
1019
1256
  when 'createqueue'
1257
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1258
+ puts "Usage: cli createqueue QUEUE_NAME [SCOPE]"
1259
+ puts ""
1260
+ puts "Create a new queue in the specified scope"
1261
+ puts ""
1262
+ puts "Arguments:"
1263
+ puts " QUEUE_NAME Name of the queue to create (required)"
1264
+ puts " SCOPE Scope for the queue (optional, default: DEFAULT)"
1265
+ puts ""
1266
+ puts "Options:"
1267
+ puts " -h, --help Show this help message"
1268
+ exit(ARGV[1].nil? ? 1 : 0)
1269
+ end
1020
1270
  queue = OpenC3::QueueModel.get(name: ARGV[1], scope: ARGV[2])
1021
1271
  unless queue
1022
1272
  queue = OpenC3::QueueModel.new(name: ARGV[1], state: 'RELEASE', scope: ARGV[2])
@@ -1024,13 +1274,43 @@ if not ARGV[0].nil? # argument(s) given
1024
1274
  end
1025
1275
 
1026
1276
  when 'destroyscope'
1277
+ if ARGV[1].nil? || ARGV[1] == '--help' || ARGV[1] == '-h'
1278
+ puts "Usage: cli destroyscope SCOPE_NAME"
1279
+ puts ""
1280
+ puts "Destroy a scope and all its associated data"
1281
+ puts ""
1282
+ puts "Arguments:"
1283
+ puts " SCOPE_NAME Name of the scope to destroy (required)"
1284
+ puts ""
1285
+ puts "Options:"
1286
+ puts " -h, --help Show this help message"
1287
+ exit(ARGV[1].nil? ? 1 : 0)
1288
+ end
1027
1289
  scope = OpenC3::ScopeModel.get_model(name: ARGV[1])
1028
1290
  scope.destroy
1029
1291
 
1030
1292
  when 'localinit'
1293
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1294
+ puts "Usage: cli localinit"
1295
+ puts ""
1296
+ puts "Initialize local mode configuration"
1297
+ puts ""
1298
+ puts "Options:"
1299
+ puts " -h, --help Show this help message"
1300
+ exit 0
1301
+ end
1031
1302
  OpenC3::LocalMode.local_init()
1032
1303
 
1033
1304
  when 'initbuckets'
1305
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1306
+ puts "Usage: cli initbuckets"
1307
+ puts ""
1308
+ puts "Initialize all configured COSMOS buckets"
1309
+ puts ""
1310
+ puts "Options:"
1311
+ puts " -h, --help Show this help message"
1312
+ exit 0
1313
+ end
1034
1314
  client = OpenC3::Bucket.getClient()
1035
1315
  ENV.map do |key, value|
1036
1316
  if key.match(/^OPENC3_(.+)_BUCKET$/) && !value.empty?
@@ -1040,6 +1320,15 @@ if not ARGV[0].nil? # argument(s) given
1040
1320
  client.ensure_public(ENV['OPENC3_TOOLS_BUCKET'])
1041
1321
 
1042
1322
  when 'runmigrations'
1323
+ if ARGV[1] == '--help' || ARGV[1] == '-h'
1324
+ puts "Usage: cli runmigrations"
1325
+ puts ""
1326
+ puts "Run database migrations"
1327
+ puts ""
1328
+ puts "Options:"
1329
+ puts " -h, --help Show this help message"
1330
+ exit 0
1331
+ end
1043
1332
  run_migrations(ARGV[1])
1044
1333
 
1045
1334
  else # Unknown task
@@ -34,14 +34,16 @@ module OpenC3
34
34
  autoload(:TcpipServerInterface, 'openc3/interfaces/tcpip_server_interface.rb')
35
35
  autoload(:UdpInterface, 'openc3/interfaces/udp_interface.rb')
36
36
 
37
- autoload(:Protocol, 'openc3/interfaces/protocols/protocol.rb')
38
37
  autoload(:BurstProtocol, 'openc3/interfaces/protocols/burst_protocol.rb')
38
+ autoload(:CmdResponseProtocol, 'openc3/interfaces/protocols/cmd_response_protocol.rb')
39
+ autoload(:CobsProtocol, 'openc3/interfaces/protocols/cobs_protocol.rb')
40
+ autoload(:CrcProtocol, 'openc3/interfaces/protocols/crc_protocol.rb')
39
41
  autoload(:FixedProtocol, 'openc3/interfaces/protocols/fixed_protocol.rb')
42
+ autoload(:IgnorePacketProtocol, 'openc3/interfaces/protocols/ignore_packet_protocol.rb')
40
43
  autoload(:LengthProtocol, 'openc3/interfaces/protocols/length_protocol.rb')
41
44
  autoload(:PreidentifiedProtocol, 'openc3/interfaces/protocols/preidentified_protocol.rb')
45
+ autoload(:Protocol, 'openc3/interfaces/protocols/protocol.rb')
46
+ autoload(:SlipProtocol, 'openc3/interfaces/protocols/slip_protocol.rb')
42
47
  autoload(:TemplateProtocol, 'openc3/interfaces/protocols/template_protocol.rb')
43
48
  autoload(:TerminatedProtocol, 'openc3/interfaces/protocols/terminated_protocol.rb')
44
- autoload(:CmdResponseProtocol, 'openc3/interfaces/protocols/cmd_response_protocol.rb')
45
- autoload(:CrcProtocol, 'openc3/interfaces/protocols/crc_protocol.rb')
46
- autoload(:IgnorePacketProtocol, 'openc3/interfaces/protocols/ignore_packet_protocol.rb')
47
49
  end
@@ -231,6 +231,8 @@ module OpenC3
231
231
  cmd_name = msg_hash['cmd_name']
232
232
  manual = ConfigParser.handle_true_false(msg_hash['manual'])
233
233
  cmd_params = nil
234
+ range_check = true
235
+ raw = false
234
236
  cmd_buffer = nil
235
237
  hazardous_check = nil
236
238
  if msg_hash['cmd_params']
@@ -288,14 +290,13 @@ module OpenC3
288
290
  if @critical_commanding and @critical_commanding != 'OFF' and not release_critical
289
291
  restricted = command.restricted
290
292
  if hazardous or restricted or (@critical_commanding == 'ALL' and manual)
293
+ cmd_type = 'NORMAL'
291
294
  if hazardous
292
- type = 'HAZARDOUS'
295
+ cmd_type = 'HAZARDOUS'
293
296
  elsif restricted
294
- type = 'RESTRICTED'
295
- else
296
- type = 'NORMAL'
297
+ cmd_type = 'RESTRICTED'
297
298
  end
298
- model = CriticalCmdModel.new(name: SecureRandom.uuid, type: type, interface_name: @interface.name, username: msg_hash['username'], cmd_hash: msg_hash, scope: @scope)
299
+ model = CriticalCmdModel.new(name: SecureRandom.uuid, type: cmd_type, interface_name: @interface.name, username: msg_hash['username'], cmd_hash: msg_hash, scope: @scope)
299
300
  model.create
300
301
  @logger.info("Critical Cmd Pending: #{msg_hash['cmd_string']}", user: msg_hash['username'], scope: @scope)
301
302
  next "CriticalCmdError\n#{model.name}"
@@ -428,10 +429,12 @@ module OpenC3
428
429
  params = JSON.parse(msg_hash['params'], allow_nan: true, create_additions: true)
429
430
  end
430
431
  @router = @tlm.attempting(*params)
432
+ next 'SUCCESS'
431
433
  end
432
434
  if msg_hash['disconnect']
433
435
  @logger.info "#{@router.name}: Disconnect requested"
434
436
  @tlm.disconnect(false)
437
+ next 'SUCCESS'
435
438
  end
436
439
  if msg_hash.key?('log_stream')
437
440
  if msg_hash['log_stream'] == 'true'
@@ -441,6 +444,7 @@ module OpenC3
441
444
  @logger.info "#{@router.name}: Disable stream logging"
442
445
  @router.stop_raw_logging
443
446
  end
447
+ next 'SUCCESS'
444
448
  end
445
449
  if msg_hash.key?('router_cmd')
446
450
  params = JSON.parse(msg_hash['router_cmd'], allow_nan: true, create_additions: true)
@@ -18,6 +18,7 @@
18
18
 
19
19
  require 'openc3/microservices/microservice'
20
20
  require 'openc3/topics/queue_topic'
21
+ require 'openc3/models/queue_model'
21
22
  require 'openc3/utilities/authentication'
22
23
  require 'openc3/api/api'
23
24
 
@@ -90,15 +91,22 @@ module OpenC3
90
91
  @queue_name = @name.split('__')[2]
91
92
 
92
93
  initial_state = 'HOLD'
93
- (@config['options'] || []).each do |option|
94
- case option[0].upcase
95
- when 'QUEUE_STATE'
96
- initial_state = option[1]
97
- else
98
- @logger.error("Unknown option passed to microservice #{@name}: #{option}")
94
+ # See if the queue already exists to get its state
95
+ queue = OpenC3::QueueModel.get(name: @queue_name, scope: @scope)
96
+ if queue
97
+ initial_state = queue['state']
98
+ else
99
+ (@config['options'] || []).each do |option|
100
+ case option[0].upcase
101
+ when 'QUEUE_STATE'
102
+ initial_state = option[1]
103
+ else
104
+ @logger.error("Unknown option passed to microservice #{@name}: #{option}")
105
+ end
99
106
  end
100
107
  end
101
108
 
109
+ @logger.info "Creating QueueMicroservice in scope #{@scope} for queue #{@queue_name} with initial state #{initial_state}"
102
110
  @processor = QueueProcessor.new(name: @queue_name, state: initial_state, logger: @logger, scope: @scope)
103
111
  @processor_thread = nil
104
112
  @read_topic = true
@@ -56,6 +56,13 @@ module OpenC3
56
56
  attr_accessor :plugin_txt_lines
57
57
  attr_accessor :needs_dependencies
58
58
  attr_accessor :store_id
59
+ attr_accessor :title
60
+ attr_accessor :description
61
+ attr_accessor :licenses
62
+ attr_accessor :homepage
63
+ attr_accessor :repository
64
+ attr_accessor :keywords
65
+ attr_accessor :img_path
59
66
 
60
67
  # NOTE: The following three class methods are used by the ModelController
61
68
  # and are reimplemented to enable various Model class methods to work
@@ -179,11 +186,31 @@ module OpenC3
179
186
  raise "Invalid screen filename: #{filename}. Screen filenames must be lowercase."
180
187
  end
181
188
  end
189
+
190
+ # Process app store metadata
191
+ plugin_model.title = pkg.spec.metadata['openc3_store_title'] || pkg.spec.summary.strip
192
+ plugin_model.description = pkg.spec.metadata['openc3_store_description'] || pkg.spec.description.strip
193
+ plugin_model.licenses = pkg.spec.licenses
194
+ plugin_model.homepage = pkg.spec.homepage
195
+ plugin_model.repository = pkg.spec.metadata['source_code_uri'] # this key because it's in the official gemspec examples
196
+ plugin_model.keywords = pkg.spec.metadata['openc3_store_keywords']&.split(/, ?/)
197
+ img_path = pkg.spec.metadata['openc3_store_image']
198
+ unless img_path
199
+ default_img_path = 'public/store_img.png'
200
+ full_default_path = File.join(gem_path, default_img_path)
201
+ img_path = default_img_path if File.exist? full_default_path
202
+ end
203
+ plugin_model.img_path = File.join('gems', gem_name.split(".gem")[0], img_path) if img_path # convert this filesystem path to volumes mount path
204
+ plugin_model.update() unless validate_only
205
+
182
206
  needs_dependencies = pkg.spec.runtime_dependencies.length > 0
183
207
  needs_dependencies = true if Dir.exist?(File.join(gem_path, 'lib'))
184
208
 
185
- # Handle python requirements.txt
186
- if File.exist?(File.join(gem_path, 'requirements.txt'))
209
+ # Handle python dependencies (pyproject.toml or requirements.txt)
210
+ pyproject_path = File.join(gem_path, 'pyproject.toml')
211
+ requirements_path = File.join(gem_path, 'requirements.txt')
212
+
213
+ if File.exist?(pyproject_path) || File.exist?(requirements_path)
187
214
  begin
188
215
  pypi_url = get_setting('pypi_url', scope: scope)
189
216
  if pypi_url
@@ -202,11 +229,20 @@ module OpenC3
202
229
  end
203
230
  end
204
231
  unless validate_only
205
- Logger.info "Installing python packages from requirements.txt with pypi_url=#{pypi_url}"
206
- if ENV['PIP_ENABLE_TRUSTED_HOST'].nil?
207
- pip_args = "--no-warn-script-location -i #{pypi_url} -r #{File.join(gem_path, 'requirements.txt')}"
232
+ if File.exist?(pyproject_path)
233
+ Logger.info "Installing python packages from pyproject.toml with pypi_url=#{pypi_url}"
234
+ if ENV['PIP_ENABLE_TRUSTED_HOST'].nil?
235
+ pip_args = "--no-warn-script-location -i #{pypi_url} #{gem_path}"
236
+ else
237
+ pip_args = "--no-warn-script-location -i #{pypi_url} --trusted-host #{URI.parse(pypi_url).host} #{gem_path}"
238
+ end
208
239
  else
209
- pip_args = "--no-warn-script-location -i #{pypi_url} --trusted-host #{URI.parse(pypi_url).host} -r #{File.join(gem_path, 'requirements.txt')}"
240
+ Logger.info "Installing python packages from requirements.txt with pypi_url=#{pypi_url}"
241
+ if ENV['PIP_ENABLE_TRUSTED_HOST'].nil?
242
+ pip_args = "--no-warn-script-location -i #{pypi_url} -r #{requirements_path}"
243
+ else
244
+ pip_args = "--no-warn-script-location -i #{pypi_url} --trusted-host #{URI.parse(pypi_url).host} -r #{requirements_path}"
245
+ end
210
246
  end
211
247
  puts `/openc3/bin/pipinstall #{pip_args}`
212
248
  end
@@ -302,6 +338,13 @@ module OpenC3
302
338
  plugin_txt_lines: [],
303
339
  needs_dependencies: false,
304
340
  store_id: nil,
341
+ title: nil,
342
+ description: nil,
343
+ keywords: nil,
344
+ licenses: nil,
345
+ homepage: nil,
346
+ repository: nil,
347
+ img_path: nil,
305
348
  updated_at: nil,
306
349
  scope:
307
350
  )
@@ -310,6 +353,13 @@ module OpenC3
310
353
  @plugin_txt_lines = plugin_txt_lines
311
354
  @needs_dependencies = ConfigParser.handle_true_false(needs_dependencies)
312
355
  @store_id = store_id
356
+ @title = title
357
+ @description = description
358
+ @keywords = keywords
359
+ @licenses = licenses
360
+ @homepage = homepage
361
+ @repository = repository
362
+ @img_path = img_path
313
363
  end
314
364
 
315
365
  def create(update: false, force: false, queued: false)
@@ -329,6 +379,13 @@ module OpenC3
329
379
  'plugin_txt_lines' => @plugin_txt_lines,
330
380
  'needs_dependencies' => @needs_dependencies,
331
381
  'store_id' => @store_id,
382
+ 'title' => @title,
383
+ 'description' => @description,
384
+ 'keywords' => @keywords,
385
+ 'licenses' => @licenses,
386
+ 'homepage' => @homepage,
387
+ 'repository' => @repository,
388
+ 'img_path' => @img_path,
332
389
  'updated_at' => @updated_at
333
390
  }
334
391
  end
@@ -143,7 +143,7 @@ module OpenC3
143
143
  unless triggers.is_a?(Array)
144
144
  raise ReactionInputError.new "invalid triggers, must be array of hashes: #{triggers}"
145
145
  end
146
- trigger_hash = Hash.new()
146
+ trigger_hash = {}
147
147
  triggers.each do | trigger |
148
148
  unless trigger.is_a?(Hash)
149
149
  raise ReactionInputError.new "invalid trigger, must be hash: #{trigger}"
@@ -166,10 +166,14 @@ module OpenC3
166
166
  end
167
167
 
168
168
  def self.download(target_name, scope:)
169
+ # Validate target_name to not allow directory traversal
170
+ if target_name.include?('..') || target_name.include?('/') || target_name.include?('\\')
171
+ raise ArgumentError, "Invalid target_name: #{target_name.inspect}"
172
+ end
169
173
  tmp_dir = Dir.mktmpdir
170
174
  zip_filename = File.join(tmp_dir, "#{target_name}.zip")
171
175
  Zip.continue_on_exists_proc = true
172
- zip = Zip::File.open(zip_filename, Zip::File::CREATE)
176
+ zip = Zip::File.open(zip_filename, create: true)
173
177
 
174
178
  if ENV['OPENC3_LOCAL_MODE']
175
179
  OpenC3::LocalMode.zip_target(target_name, zip, scope: scope)
@@ -756,7 +760,7 @@ module OpenC3
756
760
  prefix = File.dirname(target_folder) + '/'
757
761
  output_file = File.join(temp_dir, @name + '_' + @id + '.zip')
758
762
  Zip.continue_on_exists_proc = true
759
- Zip::File.open(output_file, Zip::File::CREATE) do |zipfile|
763
+ Zip::File.open(output_file, create: true) do |zipfile|
760
764
  target_files.each do |target_file|
761
765
  zip_file_path = target_file.delete_prefix(prefix)
762
766
  if File.directory?(target_file)
@@ -807,7 +811,7 @@ module OpenC3
807
811
  Logger.error("Invalid text present in #{target_name} #{packet_name} tlm packet")
808
812
  raise e
809
813
  end
810
- json_hash = Hash.new
814
+ json_hash = {}
811
815
  packet.sorted_items.each do |item|
812
816
  json_hash[item.name] = nil
813
817
  TargetModel.add_to_target_allitems_list(target_name, item.name, scope: @scope)