Class: Lanet::FileTransfer
- Inherits:
-
Object
- Object
- Lanet::FileTransfer
- Defined in:
- lib/lanet/file_transfer.rb
Overview
FileTransfer handles secure file transmission over the network
Defined Under Namespace
Classes: Error
Constant Summary collapse
- CHUNK_SIZE =
Use configuration constants
Config::CHUNK_SIZE
- MAX_RETRIES =
Config::MAX_RETRIES
- TIMEOUT =
Config::FILE_TRANSFER_TIMEOUT
- FILE_HEADER =
Message types
"FH"- FILE_CHUNK =
File metadata
"FC"- FILE_END =
File data chunk
"FE"- FILE_ACK =
End of transfer
"FA"- FILE_ERROR =
Acknowledgment
"FR"
Instance Attribute Summary collapse
-
#file_size ⇒ Object
readonly
Attributes for tracking progress.
-
#progress ⇒ Object
readonly
Attributes for tracking progress.
-
#transferred_bytes ⇒ Object
readonly
Attributes for tracking progress.
Instance Method Summary collapse
-
#cancel_transfer ⇒ Object
Cancel Transfer.
-
#initialize(port = nil) ⇒ FileTransfer
constructor
Initialization.
-
#receive_file(output_dir, encryption_key = nil, public_key = nil, progress_callback = nil, &block) ⇒ Object
Receive File Method.
-
#send_file(target_ip, file_path, encryption_key = nil, private_key = nil, progress_callback = nil) ⇒ Object
Send File Method.
Constructor Details
#initialize(port = nil) ⇒ FileTransfer
Initialization
37 38 39 40 41 42 43 44 |
# File 'lib/lanet/file_transfer.rb', line 37 def initialize(port = nil) @port = port || 5001 # Default port for file transfers @progress = 0.0 @file_size = 0 @transferred_bytes = 0 @sender = Lanet::Sender.new(@port) # Assumes Lanet::Sender is defined elsewhere @cancellation_requested = false end |
Instance Attribute Details
#file_size ⇒ Object (readonly)
Attributes for tracking progress
34 35 36 |
# File 'lib/lanet/file_transfer.rb', line 34 def file_size @file_size end |
#progress ⇒ Object (readonly)
Attributes for tracking progress
34 35 36 |
# File 'lib/lanet/file_transfer.rb', line 34 def progress @progress end |
#transferred_bytes ⇒ Object (readonly)
Attributes for tracking progress
34 35 36 |
# File 'lib/lanet/file_transfer.rb', line 34 def transferred_bytes @transferred_bytes end |
Instance Method Details
#cancel_transfer ⇒ Object
Cancel Transfer
163 164 165 |
# File 'lib/lanet/file_transfer.rb', line 163 def cancel_transfer @cancellation_requested = true end |
#receive_file(output_dir, encryption_key = nil, public_key = nil, progress_callback = nil, &block) ⇒ Object
Receive File Method
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/lanet/file_transfer.rb', line 120 def receive_file(output_dir, encryption_key = nil, public_key = nil, progress_callback = nil, &block) # Use the block parameter if provided and progress_callback is nil progress_callback = block if block_given? && progress_callback.nil? FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir) receiver = UDPSocket.new receiver.bind("0.0.0.0", @port) active_transfers = {} begin loop do data, addr = receiver.recvfrom(65_536) # Large buffer for chunks # Skip if we received nil data or address next if addr.nil? || data.nil? sender_ip = addr[3] result = Lanet::Encryptor.(data, encryption_key, public_key) next unless result[:content]&.length&.> 2 = result[:content][0..1] = result[:content][2..] case when FILE_HEADER handle_file_header(sender_ip, , active_transfers, encryption_key, progress_callback) when FILE_CHUNK handle_file_chunk(sender_ip, , active_transfers, progress_callback, encryption_key) when FILE_END handle_file_end(sender_ip, , active_transfers, output_dir, encryption_key, progress_callback) when FILE_ERROR handle_file_error(sender_ip, , active_transfers, progress_callback) end end rescue Interrupt puts "\nFile receiver stopped." ensure cleanup_transfers(active_transfers) receiver.close end end |
#send_file(target_ip, file_path, encryption_key = nil, private_key = nil, progress_callback = nil) ⇒ Object
Send File Method
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/lanet/file_transfer.rb', line 47 def send_file(target_ip, file_path, encryption_key = nil, private_key = nil, progress_callback = nil) # Validate file unless File.exist?(file_path) && File.file?(file_path) raise Error, "File not found or is not a regular file: #{file_path}" end # Initialize transfer state @file_size = File.size(file_path) @transferred_bytes = 0 @progress = 0.0 @cancellation_requested = false transfer_id = SecureRandom.uuid chunk_index = 0 receiver = nil begin # Send file header file_name = File.basename(file_path) file_checksum = calculate_file_checksum(file_path) header_data = { id: transfer_id, name: file_name, size: @file_size, checksum: file_checksum, timestamp: Time.now.to_i }.to_json = Lanet::Encryptor.("#{FILE_HEADER}#{header_data}", encryption_key, private_key) @sender.send_to(target_ip, ) # Wait for initial ACK receiver = UDPSocket.new receiver.bind("0.0.0.0", @port) wait_for_ack(receiver, target_ip, transfer_id, encryption_key, "initial") # Send file chunks File.open(file_path, "rb") do |file| until file.eof? || @cancellation_requested chunk = file.read(CHUNK_SIZE) chunk_data = { id: transfer_id, index: chunk_index, data: Base64.strict_encode64(chunk) }.to_json = Lanet::Encryptor.("#{FILE_CHUNK}#{chunk_data}", encryption_key, private_key) @sender.send_to(target_ip, ) chunk_index += 1 @transferred_bytes += chunk.bytesize @progress = (@transferred_bytes.to_f / @file_size * 100).round(2) progress_callback&.call(@progress, @transferred_bytes, @file_size) sleep(0.01) # Prevent overwhelming the receiver end end # Send end marker and wait for final ACK unless @cancellation_requested end_data = { id: transfer_id, total_chunks: chunk_index }.to_json = Lanet::Encryptor.("#{FILE_END}#{end_data}", encryption_key, private_key) @sender.send_to(target_ip, ) wait_for_ack(receiver, target_ip, transfer_id, encryption_key, "final") true # Transfer successful end rescue StandardError => e send_error(target_ip, transfer_id, e., encryption_key, private_key) raise Error, "File transfer failed: #{e.}" ensure receiver&.close end end |