openc3 5.15.0 → 5.15.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.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/data/config/widgets.yaml +1 -1
- data/lib/openc3/accessors/json_accessor.rb +11 -3
- data/lib/openc3/api/cmd_api.rb +33 -1
- data/lib/openc3/io/posix_serial_driver.rb +20 -5
- data/lib/openc3/logs/packet_log_reader.rb +8 -9
- data/lib/openc3/microservices/trigger_group_microservice.rb +9 -9
- data/lib/openc3/models/auth_model.rb +5 -7
- data/lib/openc3/script/commands.rb +2 -2
- data/lib/openc3/script/storage.rb +28 -13
- data/lib/openc3/script/web_socket_api.rb +10 -0
- data/lib/openc3/system/system.rb +4 -5
- data/lib/openc3/top_level.rb +32 -23
- data/lib/openc3/utilities/authorization.rb +1 -1
- data/lib/openc3/utilities/store_autoload.rb +11 -7
- data/lib/openc3/version.rb +5 -5
- data/templates/target/targets/TARGET/lib/target.py +2 -0
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +2 -2
- data/templates/widget/package.json +2 -2
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a39dab08bb9810376520e75a7bf3a6c63d30ad54b93566b82a849d780693a366
         | 
| 4 | 
            +
              data.tar.gz: 65d282829dba0706cbe0e32603e51ad8ab3dfc0fdaf37d9bd400787bb7a1cb03
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 12bffefe104e90e159c16bcc54ab53745e86a97bfb762c7e0e25141d6bd3c91ad6bb8827017d915dfb459b2fc69ea7365c97e7fa22236abb16ff0d73d8d485d7
         | 
| 7 | 
            +
              data.tar.gz: b2efa2780f97e2aa3392cc483534d949be4fb27032dbc3e52015ebfa89da08d234e5777c50dbfa09e477357d3b5ca67aba847f8f5d723676d2331da84e880f7f
         | 
    
        data/data/config/widgets.yaml
    CHANGED
    
    | @@ -1302,7 +1302,7 @@ Interactive Widgets: | |
| 1302 1302 |  | 
| 1303 1303 | 
             
                    Button code can get rather complex so remember to use string concatenation
         | 
| 1304 1304 | 
             
                    to make things more readable. If you use `+` newlines are inserted automatically
         | 
| 1305 | 
            -
                    during string concatenation. If you use  | 
| 1305 | 
            +
                    during string concatenation. If you use `\\` you'll need to separate lines with a
         | 
| 1306 1306 | 
             
                    single semicolon `;`. COSMOS uses double semicolon `;;` to indicate lines should
         | 
| 1307 1307 | 
             
                    be evaluated separately. Note that all OpenC3 commands (using api.cmd) must be
         | 
| 1308 1308 | 
             
                    separated by `;;`.
         | 
| @@ -18,8 +18,16 @@ | |
| 18 18 |  | 
| 19 19 | 
             
            require 'json'
         | 
| 20 20 | 
             
            require 'jsonpath'
         | 
| 21 | 
            +
            require 'openc3/io/json_rpc'
         | 
| 21 22 | 
             
            require 'openc3/accessors/accessor'
         | 
| 22 23 |  | 
| 24 | 
            +
            # Monkey patch JsonPath to enable create_additions and allow_nan to support binary strings, and NaN, Infinity, -Infinity
         | 
| 25 | 
            +
            class JsonPath
         | 
| 26 | 
            +
              def self.process_object(obj_or_str, opts = {})
         | 
| 27 | 
            +
                obj_or_str.is_a?(String) ? MultiJson.decode(obj_or_str, max_nesting: opts[:max_nesting], create_additions: true, allow_nan: true) : obj_or_str
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
             | 
| 23 31 | 
             
            module OpenC3
         | 
| 24 32 | 
             
              class JsonAccessor < Accessor
         | 
| 25 33 | 
             
                def self.read_item(item, buffer)
         | 
| @@ -33,7 +41,7 @@ module OpenC3 | |
| 33 41 |  | 
| 34 42 | 
             
                  # Convert to ruby objects
         | 
| 35 43 | 
             
                  if String === buffer
         | 
| 36 | 
            -
                    decoded = JSON.parse(buffer, :allow_nan => true)
         | 
| 44 | 
            +
                    decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
         | 
| 37 45 | 
             
                  else
         | 
| 38 46 | 
             
                    decoded = buffer
         | 
| 39 47 | 
             
                  end
         | 
| @@ -43,7 +51,7 @@ module OpenC3 | |
| 43 51 |  | 
| 44 52 | 
             
                  # Update buffer
         | 
| 45 53 | 
             
                  if String === buffer
         | 
| 46 | 
            -
                    buffer.replace(JSON.generate(decoded, :allow_nan => true))
         | 
| 54 | 
            +
                    buffer.replace(JSON.generate(decoded.as_json, :allow_nan => true))
         | 
| 47 55 | 
             
                  end
         | 
| 48 56 |  | 
| 49 57 | 
             
                  return value
         | 
| @@ -52,7 +60,7 @@ module OpenC3 | |
| 52 60 | 
             
                def self.read_items(items, buffer)
         | 
| 53 61 | 
             
                  # Prevent JsonPath from decoding every call
         | 
| 54 62 | 
             
                  if String === buffer
         | 
| 55 | 
            -
                    decoded = JSON.parse(buffer, :allow_nan => true)
         | 
| 63 | 
            +
                    decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
         | 
| 56 64 | 
             
                  else
         | 
| 57 65 | 
             
                    decoded = buffer
         | 
| 58 66 | 
             
                  end
         | 
    
        data/lib/openc3/api/cmd_api.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -41,6 +41,8 @@ module OpenC3 | |
| 41 41 | 
             
                                   'cmd_raw_no_checks',
         | 
| 42 42 | 
             
                                   'build_cmd',
         | 
| 43 43 | 
             
                                   'build_command', # DEPRECATED
         | 
| 44 | 
            +
                                   'enable_cmd',
         | 
| 45 | 
            +
                                   'disable_cmd',
         | 
| 44 46 | 
             
                                   'send_raw',
         | 
| 45 47 | 
             
                                   'get_all_cmds',
         | 
| 46 48 | 
             
                                   'get_all_commands', # DEPRECATED
         | 
| @@ -131,6 +133,30 @@ module OpenC3 | |
| 131 133 | 
             
                # build_command is DEPRECATED
         | 
| 132 134 | 
             
                alias build_command build_cmd
         | 
| 133 135 |  | 
| 136 | 
            +
                # Helper method for disable_cmd / enable_cmd
         | 
| 137 | 
            +
                def _get_and_set_cmd(method, *args, scope: $openc3_scope, token: $openc3_token)
         | 
| 138 | 
            +
                  target_name, command_name = _extract_target_command_names(method, *args)
         | 
| 139 | 
            +
                  authorize(permission: 'admin', target_name: target_name, packet_name: command_name, scope: scope, token: token)
         | 
| 140 | 
            +
                  command = yield TargetModel.packet(target_name, command_name, type: :CMD, scope: scope)
         | 
| 141 | 
            +
                  TargetModel.set_packet(target_name, command_name, command, type: :CMD, scope: scope)
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                # @since 5.15.1
         | 
| 145 | 
            +
                def enable_cmd(*args, scope: $openc3_scope, token: $openc3_token)
         | 
| 146 | 
            +
                  _get_and_set_cmd('enable_cmd', *args, scope: scope, token: token) do |command|
         | 
| 147 | 
            +
                    command['disabled'] = false
         | 
| 148 | 
            +
                    command
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                # @since 5.15.1
         | 
| 153 | 
            +
                def disable_cmd(*args, scope: $openc3_scope, token: $openc3_token)
         | 
| 154 | 
            +
                  _get_and_set_cmd('disable_cmd', *args, scope: scope, token: token) do |command|
         | 
| 155 | 
            +
                    command['disabled'] = true
         | 
| 156 | 
            +
                    command
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 134 160 | 
             
                # Send a raw binary string to the specified interface.
         | 
| 135 161 | 
             
                #
         | 
| 136 162 | 
             
                # @param interface_name [String] The interface to send the raw binary
         | 
| @@ -456,6 +482,12 @@ module OpenC3 | |
| 456 482 | 
             
                  cmd_params = cmd_params.transform_keys(&:upcase)
         | 
| 457 483 | 
             
                  authorize(permission: 'cmd', target_name: target_name, packet_name: cmd_name, scope: scope, token: token)
         | 
| 458 484 | 
             
                  packet = TargetModel.packet(target_name, cmd_name, type: :CMD, scope: scope)
         | 
| 485 | 
            +
                  if packet['disabled']
         | 
| 486 | 
            +
                    error = DisabledError.new
         | 
| 487 | 
            +
                    error.target_name = target_name
         | 
| 488 | 
            +
                    error.cmd_name = cmd_name
         | 
| 489 | 
            +
                    raise error
         | 
| 490 | 
            +
                  end
         | 
| 459 491 |  | 
| 460 492 | 
             
                  command = {
         | 
| 461 493 | 
             
                    'target_name' => target_name,
         | 
| @@ -14,10 +14,10 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, 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 'fcntl'
         | 
| @@ -82,12 +82,17 @@ module OpenC3 | |
| 82 82 | 
             
                  tio.ospeed = baud_rate
         | 
| 83 83 | 
             
                  @handle.tcflush(Termios::TCIOFLUSH)
         | 
| 84 84 | 
             
                  @handle.tcsetattr(Termios::TCSANOW, tio)
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  @pipe_reader, @pipe_writer = IO.pipe
         | 
| 87 | 
            +
                  @readers = [@handle, @pipe_reader]
         | 
| 85 88 | 
             
                end
         | 
| 86 89 |  | 
| 87 90 | 
             
                # (see SerialDriver#close)
         | 
| 88 91 | 
             
                def close
         | 
| 89 92 | 
             
                  if @handle
         | 
| 90 93 | 
             
                    # Close the serial Port
         | 
| 94 | 
            +
                    @pipe_writer.write('.')
         | 
| 95 | 
            +
                    @pipe_writer.close
         | 
| 91 96 | 
             
                    @handle.close
         | 
| 92 97 | 
             
                    @handle = nil
         | 
| 93 98 | 
             
                  end
         | 
| @@ -132,9 +137,19 @@ module OpenC3 | |
| 132 137 | 
             
                  begin
         | 
| 133 138 | 
             
                    data = @handle.read_nonblock(65535)
         | 
| 134 139 | 
             
                  rescue Errno::EAGAIN, Errno::EWOULDBLOCK
         | 
| 135 | 
            -
                     | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 140 | 
            +
                    begin
         | 
| 141 | 
            +
                      read_ready, _ = IO.fast_select(@readers, nil, nil, @read_timeout)
         | 
| 142 | 
            +
                    rescue IOError
         | 
| 143 | 
            +
                      @pipe_reader.close unless @pipe_reader.closed?
         | 
| 144 | 
            +
                      return ""
         | 
| 145 | 
            +
                    end
         | 
| 146 | 
            +
                    if read_ready
         | 
| 147 | 
            +
                      if read_ready.include?(@pipe_reader)
         | 
| 148 | 
            +
                        @pipe_reader.close unless @pipe_reader.closed?
         | 
| 149 | 
            +
                        return ""
         | 
| 150 | 
            +
                      else
         | 
| 151 | 
            +
                        retry
         | 
| 152 | 
            +
                      end
         | 
| 138 153 | 
             
                    else
         | 
| 139 154 | 
             
                      raise Timeout::Error, "Read Timeout"
         | 
| 140 155 | 
             
                    end
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -96,9 +96,9 @@ module OpenC3 | |
| 96 96 | 
             
                  @max_read_size = @file.size
         | 
| 97 97 | 
             
                  @max_read_size = MAX_READ_SIZE if @max_read_size > MAX_READ_SIZE
         | 
| 98 98 | 
             
                  return read_file_header()
         | 
| 99 | 
            -
                rescue =>  | 
| 99 | 
            +
                rescue => e
         | 
| 100 100 | 
             
                  close()
         | 
| 101 | 
            -
                  raise  | 
| 101 | 
            +
                  raise e
         | 
| 102 102 | 
             
                end
         | 
| 103 103 |  | 
| 104 104 | 
             
                # Closes the current log file
         | 
| @@ -134,9 +134,8 @@ module OpenC3 | |
| 134 134 |  | 
| 135 135 | 
             
                  if flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_JSON_PACKET_ENTRY_TYPE_MASK
         | 
| 136 136 | 
             
                    packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
         | 
| 137 | 
            -
                    next_offset = 12
         | 
| 138 137 | 
             
                    received_time_nsec_since_epoch, extra, json_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
         | 
| 139 | 
            -
                    lookup_cmd_or_tlm, target_name, packet_name,  | 
| 138 | 
            +
                    lookup_cmd_or_tlm, target_name, packet_name, _id, key_map = @packets[packet_index]
         | 
| 140 139 | 
             
                    if cmd_or_tlm != lookup_cmd_or_tlm
         | 
| 141 140 | 
             
                      raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
         | 
| 142 141 | 
             
                    end
         | 
| @@ -148,8 +147,8 @@ module OpenC3 | |
| 148 147 | 
             
                    end
         | 
| 149 148 | 
             
                  elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_RAW_PACKET_ENTRY_TYPE_MASK
         | 
| 150 149 | 
             
                    packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
         | 
| 151 | 
            -
                    received_time_nsec_since_epoch,  | 
| 152 | 
            -
                    lookup_cmd_or_tlm, target_name, packet_name,  | 
| 150 | 
            +
                    received_time_nsec_since_epoch, _extra, packet_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
         | 
| 151 | 
            +
                    lookup_cmd_or_tlm, target_name, packet_name, _id = @packets[packet_index]
         | 
| 153 152 | 
             
                    if cmd_or_tlm != lookup_cmd_or_tlm
         | 
| 154 153 | 
             
                      raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
         | 
| 155 154 | 
             
                    end
         | 
| @@ -220,9 +219,9 @@ module OpenC3 | |
| 220 219 | 
             
                  else
         | 
| 221 220 | 
             
                    raise "Invalid Entry Flags: #{flags}"
         | 
| 222 221 | 
             
                  end
         | 
| 223 | 
            -
                rescue =>  | 
| 222 | 
            +
                rescue => e
         | 
| 224 223 | 
             
                  close()
         | 
| 225 | 
            -
                  raise  | 
| 224 | 
            +
                  raise e
         | 
| 226 225 | 
             
                end
         | 
| 227 226 |  | 
| 228 227 | 
             
                # @return [Integer] The size of the log file being processed
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -418,7 +418,7 @@ module OpenC3 | |
| 418 418 | 
             
                    when 'OR'
         | 
| 419 419 | 
             
                      return left || right ? 1 : 0
         | 
| 420 420 | 
             
                    end
         | 
| 421 | 
            -
                  rescue ArgumentError | 
| 421 | 
            +
                  rescue ArgumentError
         | 
| 422 422 | 
             
                    message = "invalid evaluate: (#{left} #{operator} #{right})"
         | 
| 423 423 | 
             
                    notify(name: name, severity: 'error', message: message)
         | 
| 424 424 | 
             
                    return -1
         | 
| @@ -447,7 +447,7 @@ module OpenC3 | |
| 447 447 | 
             
                  if visited["#{head.name}__P"][trigger.name]
         | 
| 448 448 | 
             
                    # Not sure if this is posible as on create it validates that the dependents are already created
         | 
| 449 449 | 
             
                    message = "loop detected from #{head.name} -> #{trigger.name} path: #{visited["#{head.name}__P"]}"
         | 
| 450 | 
            -
                    notify(name: trigger.name, severity: 'error', message:  | 
| 450 | 
            +
                    notify(name: trigger.name, severity: 'error', message: message)
         | 
| 451 451 | 
             
                    return visited["#{trigger.name}__R"] = -1
         | 
| 452 452 | 
             
                  end
         | 
| 453 453 | 
             
                  trigger.roots.each do | root_trigger_name |
         | 
| @@ -455,7 +455,7 @@ module OpenC3 | |
| 455 455 | 
             
                    root_trigger = triggers[root_trigger_name]
         | 
| 456 456 | 
             
                    if head.name == root_trigger.name
         | 
| 457 457 | 
             
                      message = "loop detected from #{head.name} -> #{root_trigger_name} path: #{visited["#{head.name}__P"]}"
         | 
| 458 | 
            -
                      notify(name: trigger.name, severity: 'error', message:  | 
| 458 | 
            +
                      notify(name: trigger.name, severity: 'error', message: message)
         | 
| 459 459 | 
             
                      return visited["#{trigger.name}__R"] = -1
         | 
| 460 460 | 
             
                    end
         | 
| 461 461 | 
             
                    result = evaluate_trigger(
         | 
| @@ -474,9 +474,9 @@ module OpenC3 | |
| 474 474 | 
             
                    else
         | 
| 475 475 | 
             
                      right = operand_value(operand: trigger.right, other: trigger.left, visited: visited)
         | 
| 476 476 | 
             
                    end
         | 
| 477 | 
            -
                  rescue =>  | 
| 477 | 
            +
                  rescue => e
         | 
| 478 478 | 
             
                    # This will primarily happen when the user inputs a bad Regexp
         | 
| 479 | 
            -
                    notify(name: trigger.name, severity: 'error', message:  | 
| 479 | 
            +
                    notify(name: trigger.name, severity: 'error', message: e.message)
         | 
| 480 480 | 
             
                    return visited["#{trigger.name}__R"] = -1
         | 
| 481 481 | 
             
                  end
         | 
| 482 482 | 
             
                  # Convert the standard '==' and '!=' into Ruby Regexp operators
         | 
| @@ -560,7 +560,7 @@ module OpenC3 | |
| 560 560 | 
             
                  while @read_topic
         | 
| 561 561 | 
             
                    begin
         | 
| 562 562 | 
             
                      Topic.read_topics(@topics) do |topic, _msg_id, msg_hash, _redis|
         | 
| 563 | 
            -
                        @logger.debug "TriggerGroupManager block_for_updates: #{topic} #{msg_hash | 
| 563 | 
            +
                        @logger.debug "TriggerGroupManager block_for_updates: #{topic} #{msg_hash}"
         | 
| 564 564 | 
             
                        if topic != @share.trigger_base.autonomic_topic
         | 
| 565 565 | 
             
                          packet = JsonPacket.new(:TLM, msg_hash['target_name'], msg_hash['packet_name'], msg_hash['time'].to_i, false, msg_hash["json_data"])
         | 
| 566 566 | 
             
                          @share.packet_base.add(topic: topic, packet: packet)
         | 
| @@ -580,7 +580,7 @@ module OpenC3 | |
| 580 580 | 
             
                def shutdown
         | 
| 581 581 | 
             
                  @read_topic = false
         | 
| 582 582 | 
             
                  @cancel_thread = true
         | 
| 583 | 
            -
                  @worker_count.times do |  | 
| 583 | 
            +
                  @worker_count.times do | _i |
         | 
| 584 584 | 
             
                    @queue << nil
         | 
| 585 585 | 
             
                  end
         | 
| 586 586 | 
             
                end
         | 
| @@ -635,7 +635,7 @@ module OpenC3 | |
| 635 635 | 
             
                    begin
         | 
| 636 636 | 
             
                      AutonomicTopic.read_topics(@topics) do |_topic, _msg_id, msg_hash, _redis|
         | 
| 637 637 | 
             
                        break if @cancel_thread
         | 
| 638 | 
            -
                        @logger.debug "TriggerGroupMicroservice block_for_updates: #{msg_hash | 
| 638 | 
            +
                        @logger.debug "TriggerGroupMicroservice block_for_updates: #{msg_hash}"
         | 
| 639 639 | 
             
                        # Process trigger notifications created by TriggerModel notify
         | 
| 640 640 | 
             
                        if msg_hash['type'] == 'trigger'
         | 
| 641 641 | 
             
                          data = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -31,11 +31,11 @@ module OpenC3 | |
| 31 31 | 
             
                @@token_cache = nil
         | 
| 32 32 | 
             
                @@token_cache_time = nil
         | 
| 33 33 |  | 
| 34 | 
            -
                def self. | 
| 34 | 
            +
                def self.set?(key = PRIMARY_KEY)
         | 
| 35 35 | 
             
                  Store.exists(key) == 1
         | 
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
| 38 | 
            -
                def self.verify(token | 
| 38 | 
            +
                def self.verify(token)
         | 
| 39 39 | 
             
                  return false if token.nil? or token.empty?
         | 
| 40 40 |  | 
| 41 41 | 
             
                  token_hash = hash(token)
         | 
| @@ -47,7 +47,7 @@ module OpenC3 | |
| 47 47 |  | 
| 48 48 | 
             
                  # Handle a service password - Generally only used by ScriptRunner
         | 
| 49 49 | 
             
                  service_password = ENV['OPENC3_SERVICE_PASSWORD']
         | 
| 50 | 
            -
                  return true if service_password and service_password == token | 
| 50 | 
            +
                  return true if service_password and service_password == token
         | 
| 51 51 |  | 
| 52 52 | 
             
                  return false
         | 
| 53 53 | 
             
                end
         | 
| @@ -55,15 +55,13 @@ module OpenC3 | |
| 55 55 | 
             
                def self.set(token, old_token, key = PRIMARY_KEY)
         | 
| 56 56 | 
             
                  raise "token must not be nil or empty" if token.nil? or token.empty?
         | 
| 57 57 |  | 
| 58 | 
            -
                  if  | 
| 58 | 
            +
                  if set?(key)
         | 
| 59 59 | 
             
                    raise "old_token must not be nil or empty" if old_token.nil? or old_token.empty?
         | 
| 60 60 | 
             
                    raise "old_token incorrect" unless verify(old_token)
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 | 
             
                  Store.set(key, hash(token))
         | 
| 63 63 | 
             
                end
         | 
| 64 64 |  | 
| 65 | 
            -
                private
         | 
| 66 | 
            -
             | 
| 67 65 | 
             
                def self.hash(token)
         | 
| 68 66 | 
             
                  Digest::SHA2.hexdigest token
         | 
| 69 67 | 
             
                end
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -96,7 +96,7 @@ module OpenC3 | |
| 96 96 |  | 
| 97 97 | 
             
                  # Get the command and validate the parameters
         | 
| 98 98 | 
             
                  command = $api_server.get_cmd(target_name, cmd_name, scope: scope)
         | 
| 99 | 
            -
                  cmd_params.each do |param_name,  | 
| 99 | 
            +
                  cmd_params.each do |param_name, _param_value|
         | 
| 100 100 | 
             
                    param = command['items'].find { |item| item['name'] == param_name }
         | 
| 101 101 | 
             
                    unless param
         | 
| 102 102 | 
             
                      raise "Packet item '#{target_name} #{cmd_name} #{param_name}' does not exist"
         | 
| @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -43,8 +43,8 @@ module OpenC3 | |
| 43 43 | 
             
                    if response.nil? || response.status != 200
         | 
| 44 44 | 
             
                      raise "Failed to delete #{delete_path}"
         | 
| 45 45 | 
             
                    end
         | 
| 46 | 
            -
                  rescue =>  | 
| 47 | 
            -
                    raise "Failed deleting #{path} due to #{ | 
| 46 | 
            +
                  rescue => e
         | 
| 47 | 
            +
                    raise "Failed deleting #{path} due to #{e.message}"
         | 
| 48 48 | 
             
                  end
         | 
| 49 49 | 
             
                  nil
         | 
| 50 50 | 
             
                end
         | 
| @@ -84,8 +84,8 @@ module OpenC3 | |
| 84 84 | 
             
                        end
         | 
| 85 85 | 
             
                      end
         | 
| 86 86 | 
             
                    end
         | 
| 87 | 
            -
                  rescue =>  | 
| 88 | 
            -
                    raise "Failed to write #{upload_path} due to #{ | 
| 87 | 
            +
                  rescue => e
         | 
| 88 | 
            +
                    raise "Failed to write #{upload_path} due to #{e.message}"
         | 
| 89 89 | 
             
                  end
         | 
| 90 90 | 
             
                  nil
         | 
| 91 91 | 
             
                end
         | 
| @@ -115,19 +115,33 @@ module OpenC3 | |
| 115 115 | 
             
                      end
         | 
| 116 116 |  | 
| 117 117 | 
             
                      return _get_storage_file("#{part}/#{path}", scope: scope)
         | 
| 118 | 
            -
                    rescue =>  | 
| 118 | 
            +
                    rescue => e
         | 
| 119 119 | 
             
                      if part == "targets_modified"
         | 
| 120 120 | 
             
                        part = "targets"
         | 
| 121 121 | 
             
                        redo
         | 
| 122 122 | 
             
                      else
         | 
| 123 | 
            -
                        raise  | 
| 123 | 
            +
                        raise e
         | 
| 124 124 | 
             
                      end
         | 
| 125 125 | 
             
                    end
         | 
| 126 126 | 
             
                    break
         | 
| 127 127 | 
             
                  end
         | 
| 128 128 | 
             
                end
         | 
| 129 129 |  | 
| 130 | 
            -
                 | 
| 130 | 
            +
                def get_download_url(path, scope: $openc3_scope)
         | 
| 131 | 
            +
                  targets = "targets_modified" # First try targets_modified
         | 
| 132 | 
            +
                  response = $api_server.request('get', "/openc3-api/storage/exists/#{scope}/#{targets}/#{path}", query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
         | 
| 133 | 
            +
                  if response.status != 200
         | 
| 134 | 
            +
                    targets = "targets" # Next try targets
         | 
| 135 | 
            +
                    response = $api_server.request('get', "/openc3-api/storage/exists/#{scope}/#{targets}/#{path}", query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
         | 
| 136 | 
            +
                    if response.status != 200
         | 
| 137 | 
            +
                      raise "File not found: #{path} in scope: #{scope}"
         | 
| 138 | 
            +
                    end
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                  endpoint = "/openc3-api/storage/download/#{scope}/#{targets}/#{path}"
         | 
| 141 | 
            +
                  # external must be true because we're using this URL from the frontend
         | 
| 142 | 
            +
                  result = _get_presigned_request(endpoint, external: true, scope: scope)
         | 
| 143 | 
            +
                  return result['url']
         | 
| 144 | 
            +
                end
         | 
| 131 145 |  | 
| 132 146 | 
             
                # These are helper methods ... should not be used directly
         | 
| 133 147 |  | 
| @@ -161,7 +175,8 @@ module OpenC3 | |
| 161 175 | 
             
                  if $openc3_in_cluster
         | 
| 162 176 | 
             
                    case ENV['OPENC3_CLOUD']
         | 
| 163 177 | 
             
                    when 'local'
         | 
| 164 | 
            -
                       | 
| 178 | 
            +
                      bucket_url = ENV["OPENC3_BUCKET_URL"] || "http://openc3-minio:9000"
         | 
| 179 | 
            +
                      URI.parse("#{bucket_url}#{url}")
         | 
| 165 180 | 
             
                    when 'aws'
         | 
| 166 181 | 
             
                      URI.parse("https://s3.#{ENV['AWS_REGION']}.amazonaws.com" + url)
         | 
| 167 182 | 
             
                    when 'gcp'
         | 
| @@ -175,11 +190,11 @@ module OpenC3 | |
| 175 190 | 
             
                  end
         | 
| 176 191 | 
             
                end
         | 
| 177 192 |  | 
| 178 | 
            -
                def _get_presigned_request(endpoint, scope: $openc3_scope)
         | 
| 179 | 
            -
                  if  | 
| 180 | 
            -
                    response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET', internal: true }, scope: scope)
         | 
| 181 | 
            -
                  else
         | 
| 193 | 
            +
                def _get_presigned_request(endpoint, external: nil, scope: $openc3_scope)
         | 
| 194 | 
            +
                  if external or !$openc3_in_cluster
         | 
| 182 195 | 
             
                    response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
         | 
| 196 | 
            +
                  else
         | 
| 197 | 
            +
                    response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET', internal: true }, scope: scope)
         | 
| 183 198 | 
             
                  end
         | 
| 184 199 | 
             
                  if response.nil? || response.status != 201
         | 
| 185 200 | 
             
                    raise "Failed to get presigned URL for #{endpoint}"
         | 
| @@ -215,6 +215,16 @@ module OpenC3 | |
| 215 215 | 
             
                end
         | 
| 216 216 | 
             
              end
         | 
| 217 217 |  | 
| 218 | 
            +
              # All Scripts WebSocket
         | 
| 219 | 
            +
              class AllScriptsWebSocketApi < ScriptWebSocketApi
         | 
| 220 | 
            +
                def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
         | 
| 221 | 
            +
                  @identifier = {
         | 
| 222 | 
            +
                    channel: "AllScriptsChannel",
         | 
| 223 | 
            +
                  }
         | 
| 224 | 
            +
                  super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
              end
         | 
| 227 | 
            +
             | 
| 218 228 | 
             
              # Log Messages WebSocket
         | 
| 219 229 | 
             
              class MessagesWebSocketApi < CmdTlmWebSocketApi
         | 
| 220 230 | 
             
                def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
         | 
    
        data/lib/openc3/system/system.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -31,7 +31,6 @@ require 'openc3/system/target' | |
| 31 31 | 
             
            require 'openc3/utilities/bucket'
         | 
| 32 32 | 
             
            require 'openc3/utilities/zip'
         | 
| 33 33 | 
             
            require 'openc3/topics/limits_event_topic'
         | 
| 34 | 
            -
            require 'thread'
         | 
| 35 34 | 
             
            require 'fileutils'
         | 
| 36 35 |  | 
| 37 36 | 
             
            module OpenC3
         | 
| @@ -109,7 +108,7 @@ module OpenC3 | |
| 109 108 | 
             
                      # target.txt must be configured to either use all files in cmd_tlm folder (default)
         | 
| 110 109 | 
             
                      # or have a predetermined empty file like dynamic_tlm.txt
         | 
| 111 110 | 
             
                      bucket_path = "#{scope}/targets_modified/#{target_name}/cmd_tlm"
         | 
| 112 | 
            -
                       | 
| 111 | 
            +
                      _, files = bucket.list_files(bucket: ENV['OPENC3_CONFIG_BUCKET'], path: bucket_path)
         | 
| 113 112 | 
             
                      files.each do |file|
         | 
| 114 113 | 
             
                        bucket_key = File.join(bucket_path, file['name'])
         | 
| 115 114 | 
             
                        local_path = "#{base_dir}/targets/#{target_name}/cmd_tlm/#{file['name']}"
         | 
| @@ -180,8 +179,8 @@ module OpenC3 | |
| 180 179 | 
             
                  errors = [] # Store all errors processing the cmd_tlm files
         | 
| 181 180 | 
             
                  target.cmd_tlm_files.each do |cmd_tlm_file|
         | 
| 182 181 | 
             
                    @packet_config.process_file(cmd_tlm_file, target.name, target.language)
         | 
| 183 | 
            -
                  rescue Exception =>  | 
| 184 | 
            -
                    errors << "Error processing #{cmd_tlm_file}:\n#{ | 
| 182 | 
            +
                  rescue Exception => e
         | 
| 183 | 
            +
                    errors << "Error processing #{cmd_tlm_file}:\n#{e.message}"
         | 
| 185 184 | 
             
                  end
         | 
| 186 185 | 
             
                  unless errors.empty?
         | 
| 187 186 | 
             
                    raise errors.join("\n")
         | 
    
        data/lib/openc3/top_level.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ | |
| 14 14 | 
             
            # GNU Affero General Public License for more details.
         | 
| 15 15 |  | 
| 16 16 | 
             
            # Modified by OpenC3, Inc.
         | 
| 17 | 
            -
            # All changes Copyright  | 
| 17 | 
            +
            # All changes Copyright 2024, OpenC3, Inc.
         | 
| 18 18 | 
             
            # All Rights Reserved
         | 
| 19 19 | 
             
            #
         | 
| 20 20 | 
             
            # This file may also be used under the terms of a commercial license
         | 
| @@ -22,7 +22,6 @@ | |
| 22 22 |  | 
| 23 23 | 
             
            # This file contains top level functions in the OpenC3 namespace
         | 
| 24 24 |  | 
| 25 | 
            -
            require 'thread'
         | 
| 26 25 | 
             
            require 'digest'
         | 
| 27 26 | 
             
            require 'open3'
         | 
| 28 27 | 
             
            require 'openc3/core_ext'
         | 
| @@ -50,6 +49,16 @@ class HazardousError < StandardError | |
| 50 49 | 
             
              end
         | 
| 51 50 | 
             
            end
         | 
| 52 51 |  | 
| 52 | 
            +
            # If a disabled command is sent through the {OpenC3::Api} this error is raised.
         | 
| 53 | 
            +
            class DisabledError < StandardError
         | 
| 54 | 
            +
              attr_accessor :target_name
         | 
| 55 | 
            +
              attr_accessor :cmd_name
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def to_s
         | 
| 58 | 
            +
                "#{target_name} #{cmd_name} is Disabled"
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
            end
         | 
| 61 | 
            +
             | 
| 53 62 | 
             
            # OpenC3 is almost
         | 
| 54 63 | 
             
            # wholly contained within the OpenC3 module. OpenC3 also extends some of the
         | 
| 55 64 | 
             
            # core Ruby classes to add additional functionality.
         | 
| @@ -102,18 +111,18 @@ module OpenC3 | |
| 102 111 | 
             
                  file.write(OPENC3_MARSHAL_HEADER)
         | 
| 103 112 | 
             
                  file.write(Marshal.dump(obj))
         | 
| 104 113 | 
             
                end
         | 
| 105 | 
            -
              rescue Exception =>  | 
| 114 | 
            +
              rescue Exception => e
         | 
| 106 115 | 
             
                begin
         | 
| 107 116 | 
             
                  File.delete(marshal_filename)
         | 
| 108 117 | 
             
                rescue Exception
         | 
| 109 118 | 
             
                  # Oh well - we tried
         | 
| 110 119 | 
             
                end
         | 
| 111 | 
            -
                if  | 
| 112 | 
            -
                  original_backtrace =  | 
| 113 | 
            -
                   | 
| 114 | 
            -
                   | 
| 120 | 
            +
                if e.class == TypeError and e.message =~ /Thread::Mutex/
         | 
| 121 | 
            +
                  original_backtrace = e.backtrace
         | 
| 122 | 
            +
                  e = e.exception("Mutex exists in a packet.  Note: Packets must not be read during class initializers for Conversions, Limits Responses, etc.: #{e}")
         | 
| 123 | 
            +
                  e.set_backtrace(original_backtrace)
         | 
| 115 124 | 
             
                end
         | 
| 116 | 
            -
                self.handle_fatal_exception( | 
| 125 | 
            +
                self.handle_fatal_exception(e)
         | 
| 117 126 | 
             
              end
         | 
| 118 127 |  | 
| 119 128 | 
             
              # Loads the marshal file back into a Ruby object
         | 
| @@ -132,9 +141,9 @@ module OpenC3 | |
| 132 141 | 
             
                  Logger.warn "Marshal load failed with invalid marshal file: #{marshal_filename}"
         | 
| 133 142 | 
             
                  return nil
         | 
| 134 143 | 
             
                end
         | 
| 135 | 
            -
              rescue Exception =>  | 
| 144 | 
            +
              rescue Exception => e
         | 
| 136 145 | 
             
                if File.exist?(marshal_filename)
         | 
| 137 | 
            -
                  Logger.error "Marshal load failed with exception: #{marshal_filename}\n#{ | 
| 146 | 
            +
                  Logger.error "Marshal load failed with exception: #{marshal_filename}\n#{e.formatted}"
         | 
| 138 147 | 
             
                else
         | 
| 139 148 | 
             
                  Logger.info "Marshal file does not exist: #{marshal_filename}"
         | 
| 140 149 | 
             
                end
         | 
| @@ -145,7 +154,7 @@ module OpenC3 | |
| 145 154 | 
             
                rescue Exception
         | 
| 146 155 | 
             
                  # Oh well - we tried
         | 
| 147 156 | 
             
                end
         | 
| 148 | 
            -
                self.handle_fatal_exception( | 
| 157 | 
            +
                self.handle_fatal_exception(e) if File.exist?(marshal_filename)
         | 
| 149 158 | 
             
                return nil
         | 
| 150 159 | 
             
              end
         | 
| 151 160 |  | 
| @@ -354,7 +363,7 @@ module OpenC3 | |
| 354 363 | 
             
              #
         | 
| 355 364 | 
             
              # @param error [Exception] The exception to handle
         | 
| 356 365 | 
             
              # @param try_gui [Boolean] Whether to try and create a GUI exception popup
         | 
| 357 | 
            -
              def self.handle_fatal_exception(error,  | 
| 366 | 
            +
              def self.handle_fatal_exception(error, _try_gui = true)
         | 
| 358 367 | 
             
                unless SystemExit === error or SignalException === error
         | 
| 359 368 | 
             
                  $openc3_fatal_exception = error
         | 
| 360 369 | 
             
                  self.write_exception_file(error)
         | 
| @@ -380,7 +389,7 @@ module OpenC3 | |
| 380 389 | 
             
              #
         | 
| 381 390 | 
             
              # @param error [Exception] The exception to handle
         | 
| 382 391 | 
             
              # @param try_gui [Boolean] Whether to try and create a GUI exception popup
         | 
| 383 | 
            -
              def self.handle_critical_exception(error,  | 
| 392 | 
            +
              def self.handle_critical_exception(error, _try_gui = true)
         | 
| 384 393 | 
             
                Logger.error "Critical Exception! #{error.formatted}"
         | 
| 385 394 | 
             
                self.write_exception_file(error)
         | 
| 386 395 | 
             
              end
         | 
| @@ -397,15 +406,15 @@ module OpenC3 | |
| 397 406 | 
             
                  retry_count = 0
         | 
| 398 407 | 
             
                  begin
         | 
| 399 408 | 
             
                    yield
         | 
| 400 | 
            -
                  rescue =>  | 
| 409 | 
            +
                  rescue => e
         | 
| 401 410 | 
             
                    Logger.error "#{name} thread unexpectedly died. Retries: #{retry_count} of #{retry_attempts}"
         | 
| 402 | 
            -
                    Logger.error  | 
| 411 | 
            +
                    Logger.error e.formatted
         | 
| 403 412 | 
             
                    retry_count += 1
         | 
| 404 413 | 
             
                    if retry_count <= retry_attempts
         | 
| 405 | 
            -
                      self.write_exception_file( | 
| 414 | 
            +
                      self.write_exception_file(e)
         | 
| 406 415 | 
             
                      retry
         | 
| 407 416 | 
             
                    end
         | 
| 408 | 
            -
                    handle_fatal_exception( | 
| 417 | 
            +
                    handle_fatal_exception(e)
         | 
| 409 418 | 
             
                  end
         | 
| 410 419 | 
             
                end
         | 
| 411 420 | 
             
              end
         | 
| @@ -440,15 +449,15 @@ module OpenC3 | |
| 440 449 | 
             
              # @param log_error [Boolean] Whether to log an error if we can't require the class
         | 
| 441 450 | 
             
              def self.require_file(filename, log_error = true)
         | 
| 442 451 | 
             
                require filename
         | 
| 443 | 
            -
              rescue Exception =>  | 
| 444 | 
            -
                msg = "Unable to require #{filename} due to #{ | 
| 452 | 
            +
              rescue Exception => e
         | 
| 453 | 
            +
                msg = "Unable to require #{filename} due to #{e.message}. "\
         | 
| 445 454 | 
             
                      "Ensure #{filename} is in the OpenC3 lib directory."
         | 
| 446 455 | 
             
                Logger.error msg if log_error
         | 
| 447 456 | 
             
                raise $!, msg, $!.backtrace
         | 
| 448 457 | 
             
              end
         | 
| 449 458 |  | 
| 450 459 | 
             
              # @param filename [String] Name of the file to open in the web browser
         | 
| 451 | 
            -
              def self.open_in_web_browser( | 
| 460 | 
            +
              def self.open_in_web_browser(_filename)
         | 
| 452 461 | 
             
                puts "open_in_web_browser is DEPRECATED"
         | 
| 453 462 | 
             
              end
         | 
| 454 463 |  | 
| @@ -456,12 +465,12 @@ module OpenC3 | |
| 456 465 | 
             
              # Working directory is global, so this can make other threads wait
         | 
| 457 466 | 
             
              # Ruby Dir.chdir with block always throws an error if multiple threads
         | 
| 458 467 | 
             
              # call Dir.chdir
         | 
| 459 | 
            -
              def self.set_working_dir(working_dir, & | 
| 468 | 
            +
              def self.set_working_dir(working_dir, &)
         | 
| 460 469 | 
             
                if $openc3_chdir_mutex.owned?
         | 
| 461 | 
            -
                  set_working_dir_internal(working_dir, & | 
| 470 | 
            +
                  set_working_dir_internal(working_dir, &)
         | 
| 462 471 | 
             
                else
         | 
| 463 472 | 
             
                  $openc3_chdir_mutex.synchronize do
         | 
| 464 | 
            -
                    set_working_dir_internal(working_dir, & | 
| 473 | 
            +
                    set_working_dir_internal(working_dir, &)
         | 
| 465 474 | 
             
                  end
         | 
| 466 475 | 
             
                end
         | 
| 467 476 | 
             
              end
         | 
| @@ -42,7 +42,7 @@ rescue LoadError | |
| 42 42 |  | 
| 43 43 | 
             
                    if $openc3_authorize
         | 
| 44 44 | 
             
                      raise AuthError.new("Token is required") unless token
         | 
| 45 | 
            -
                      unless OpenC3::AuthModel.verify(token | 
| 45 | 
            +
                      unless OpenC3::AuthModel.verify(token)
         | 
| 46 46 | 
             
                        raise AuthError.new("Password is invalid for '#{permission}' permission")
         | 
| 47 47 | 
             
                      end
         | 
| 48 48 | 
             
                    end
         | 
| @@ -37,13 +37,17 @@ module OpenC3 | |
| 37 37 | 
             
                NO_OPTIONS = {}
         | 
| 38 38 |  | 
| 39 39 | 
             
                def pipelined
         | 
| 40 | 
            -
                   | 
| 41 | 
            -
                     | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
                         | 
| 40 | 
            +
                  if $openc3_redis_cluster
         | 
| 41 | 
            +
                    yield # TODO: Update keys to support pipelining in cluster
         | 
| 42 | 
            +
                  else
         | 
| 43 | 
            +
                    with(NO_OPTIONS) do |redis|
         | 
| 44 | 
            +
                      redis.pipelined do |pipeline|
         | 
| 45 | 
            +
                        Thread.current[:pipeline] = pipeline
         | 
| 46 | 
            +
                        begin
         | 
| 47 | 
            +
                          yield
         | 
| 48 | 
            +
                        ensure
         | 
| 49 | 
            +
                          Thread.current[:pipeline] = nil
         | 
| 50 | 
            +
                        end
         | 
| 47 51 | 
             
                      end
         | 
| 48 52 | 
             
                    end
         | 
| 49 53 | 
             
                  end
         | 
    
        data/lib/openc3/version.rb
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            # encoding: ascii-8bit
         | 
| 2 2 |  | 
| 3 | 
            -
            OPENC3_VERSION = '5.15. | 
| 3 | 
            +
            OPENC3_VERSION = '5.15.2'
         | 
| 4 4 | 
             
            module OpenC3
         | 
| 5 5 | 
             
              module Version
         | 
| 6 6 | 
             
                MAJOR = '5'
         | 
| 7 7 | 
             
                MINOR = '15'
         | 
| 8 | 
            -
                PATCH = ' | 
| 8 | 
            +
                PATCH = '2'
         | 
| 9 9 | 
             
                OTHER = ''
         | 
| 10 | 
            -
                BUILD = ' | 
| 10 | 
            +
                BUILD = '460e13eadf313640ad089597bee233ecdafd2ffa'
         | 
| 11 11 | 
             
              end
         | 
| 12 | 
            -
              VERSION = '5.15. | 
| 13 | 
            -
              GEM_VERSION = '5.15. | 
| 12 | 
            +
              VERSION = '5.15.2'
         | 
| 13 | 
            +
              GEM_VERSION = '5.15.2'
         | 
| 14 14 | 
             
            end
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "<%= tool_name %>",
         | 
| 3 | 
            -
              "version": "5.15. | 
| 3 | 
            +
              "version": "5.15.2",
         | 
| 4 4 | 
             
              "scripts": {
         | 
| 5 5 | 
             
                "ng": "ng",
         | 
| 6 6 | 
             
                "start": "ng serve",
         | 
| @@ -12,7 +12,7 @@ | |
| 12 12 | 
             
              },
         | 
| 13 13 | 
             
              "private": true,
         | 
| 14 14 | 
             
              "dependencies": {
         | 
| 15 | 
            -
                "@openc3/tool-common": "5.15. | 
| 15 | 
            +
                "@openc3/tool-common": "5.15.2",
         | 
| 16 16 | 
             
                "@angular/animations": "^17.0.8",
         | 
| 17 17 | 
             
                "@angular/cdk": "^17.0.4",
         | 
| 18 18 | 
             
                "@angular/common": "^17.0.8",
         | 
| @@ -11,7 +11,7 @@ | |
| 11 11 | 
             
                "smui-theme": "smui-theme compile build/smui.css -i src/theme"
         | 
| 12 12 | 
             
              },
         | 
| 13 13 | 
             
              "dependencies": {
         | 
| 14 | 
            -
                "@openc3/tool-common": "5.15. | 
| 14 | 
            +
                "@openc3/tool-common": "5.15.2",
         | 
| 15 15 | 
             
                "@astrouxds/astro-web-components": "7.20.0",
         | 
| 16 16 | 
             
                "@smui/button": "^7.0.0-beta.16",
         | 
| 17 17 | 
             
                "@smui/card": "^7.0.0-beta.16",
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "<%= tool_name %>",
         | 
| 3 | 
            -
              "version": "5.15. | 
| 3 | 
            +
              "version": "5.15.2",
         | 
| 4 4 | 
             
              "private": true,
         | 
| 5 5 | 
             
              "scripts": {
         | 
| 6 6 | 
             
                "serve": "vue-cli-service serve",
         | 
| @@ -11,7 +11,7 @@ | |
| 11 11 | 
             
                "test:components": "vue-cli-service test:components"
         | 
| 12 12 | 
             
              },
         | 
| 13 13 | 
             
              "dependencies": {
         | 
| 14 | 
            -
                "@openc3/tool-common": "5.15. | 
| 14 | 
            +
                "@openc3/tool-common": "5.15.2",
         | 
| 15 15 | 
             
                "@astrouxds/astro-web-components": "7.20.0",
         | 
| 16 16 | 
             
                "axios": "1.6.5",
         | 
| 17 17 | 
             
                "date-fns": "2.30.0",
         | 
| @@ -1,12 +1,12 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "widget",
         | 
| 3 | 
            -
              "version": "5.15. | 
| 3 | 
            +
              "version": "5.15.2",
         | 
| 4 4 | 
             
              "private": true,
         | 
| 5 5 | 
             
              "scripts": {
         | 
| 6 6 | 
             
                "build": "vue-cli-service build --target lib --dest tools/widgets/<%= widget_name %> --formats umd-min <%= widget_path %> --name <%= widget_name %>"
         | 
| 7 7 | 
             
              },
         | 
| 8 8 | 
             
              "dependencies": {
         | 
| 9 | 
            -
                "@openc3/tool-common": "5.15. | 
| 9 | 
            +
                "@openc3/tool-common": "5.15.2",
         | 
| 10 10 | 
             
                "@astrouxds/astro-web-components": "7.20.0",
         | 
| 11 11 | 
             
                "vue": "2.7.16",
         | 
| 12 12 | 
             
                "vuetify": "2.7.1"
         | 
    
        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.15. | 
| 4 | 
            +
              version: 5.15.2
         | 
| 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: 2024- | 
| 12 | 
            +
            date: 2024-04-01 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: bundler
         |