pw_transfer

Attention

pw_transfer is under construction and so is its documentation.

Usage

Python

Provides a simple interface for transferring bulk data over pw_rpc.

exception pw_transfer.transfer.Error(transfer_id: int, status: pw_status.Status)

Exception raised when a transfer fails.

Stores the ID of the failed transfer and the error that occurred.

__init__(transfer_id: int, status: pw_status.Status)
class pw_transfer.transfer.Manager(rpc_transfer_service, default_response_timeout_s: float = 2.0)

A manager for transmitting data through an RPC TransferService.

This should be initialized with an active Manager over an RPC channel. Only one instance of this class should exist for a configured RPC TransferService – the Manager supports multiple simultaneous transfers.

When created, a Manager starts a separate thread in which transfer communications and events are handled.

__init__(rpc_transfer_service, default_response_timeout_s: float = 2.0)

Initializes a Manager on top of a TransferService.

read(transfer_id: int) bytes

Receives (“downloads”) data from the server.

Raises

Error – the transfer failed to complete

write(transfer_id: int, data: bytes) None

Transmits (“uploads”) data to the server.

Raises

Error – the transfer failed to complete

Example

from pw_transfer import transfer

# Initialize a Pigweed RPC client; see pw_rpc docs for more info.
rpc_client = CustomRpcClient()
rpcs = rpc_client.channel(1).rpcs

transfer_service = rpcs.pw.transfer.Transfer
transfer_manager = transfer.Manager(transfer_service)

try:
  # Read transfer_id 3 from the server.
  data = transfer_manager.read(3)
except transfer.Error as err:
  print('Failed to read:', err.status)

try:
  # Send some data to the server. The transfer manager does not have to be
  # reinitialized.
  transfer_manager.write(2, b'hello, world')
except transfer.Error as err:
  print('Failed to write:', err.status)

Protocol

Protocol buffer definition

syntax = "proto3";

package pw.transfer;

// The transfer RPC service is used to send data between the client and server.
service Transfer {
  // Transfer data from the server to the client; a "download" from the client's
  // perspective.
  rpc Read(stream Chunk) returns (stream Chunk);

  // Transfer data from the client to the server; an "upload" from the client's
  // perspective.
  rpc Write(stream Chunk) returns (stream Chunk);
}

// Represents a chunk of data sent by the transfer service. Includes fields for
// configuring the transfer parameters.
//
// Notation: (Read|Write) (→|←)
//   X → Means client sending data to the server.
//   X ← Means server sending data to the client.
message Chunk {
  // Represents the source or destination of the data. May be ephemeral or
  // stable depending on the implementation. Sent in every request to identify
  // the transfer target.
  //
  //  Read → ID of transfer
  //  Read ← ID of transfer
  // Write → ID of transfer
  // Write ← ID of transfer
  uint32 transfer_id = 1;

  // Used by the receiver to indicate how many bytes it can accept. The
  // transmitter sends this much data, divided into chunks no larger than
  // max_chunk_size_bytes. The receiver then starts another window by sending
  // request_bytes again with a new offset.
  //
  //  Read → The client requests this many bytes to be sent.
  //  Read ← N/A
  // Write → N/A
  // Write ← The server requests this many bytes to be sent.
  optional uint32 pending_bytes = 2;

  // Maximum size of an individual chunk. The transmitter may send smaller
  // chunks if required.
  //
  //  Read → Set maximum size for subsequent chunks.
  //  Read ← N/A
  // Write → N/A
  // Write ← Set maximum size for subsequent chunks.
  optional uint32 max_chunk_size_bytes = 3;

  // Minimum required delay between chunks. The transmitter may delay longer if
  // desired.
  //
  //  Read → Set minimum delay for subsequent chunks.
  //  Read ← N/A
  // Write → N/A
  // Write ← Set minimum delay for subsequent chunks.
  optional uint32 min_delay_microseconds = 4;

  // On writes, the offset of the data. On reads, the offset at which to read.
  //
  //  Read → Read data starting at this offset.
  //  Read ← Offset of the data.
  // Write → Offset of the data.
  // Write ← Write data starting at this offset.
  uint64 offset = 5;

  // The data that was read or the data to write.
  //
  //  Read → N/A
  //  Read ← Data read
  // Write → Data to write
  // Write ← N/A
  bytes data = 6;

  // Estimated bytes remaining to read/write. Optional except for the last data
  // chunk, for which remaining_bytes must be set to 0.
  //
  // The sender can set remaining_bytes at the beginning of a read/write so that
  // the receiver can track progress or cancel the transaction if the value is
  // too large.
  //
  //  Read → N/A
  //  Read ← Remaining bytes to read, excluding any data in this chunk. Set to
  //         0 for the last chunk.
  // Write → Reamining bytes to write, excluding any data in is chunk. Set to
  //         0 for the last chunk.
  // Write ← N/A
  optional uint64 remaining_bytes = 7;

  // Pigweed status code indicating the completion of a transfer. This is only
  // present in the final packet sent by either the transmitter or receiver.
  //
  // The possible status codes and their meanings are listed below:
  //
  //   OK: Transfer completed successfully.
  //   DATA_LOSS: Transfer data could not be read/written (e.g. corruption).
  //   NOT_FOUND: The requested transfer ID is not registered (read/write).
  //   OUT_OF_RANGE: The requested offset is larger than the data (read/write).
  //
  //  Read → Transfer complete.
  //  Read ← Transfer complete.
  // Write → Transfer complete.
  // Write ← Transfer complete.
  optional uint32 status = 8;
}

Server to client transfer (read)

blockdiag client server transfer_id offset pending_bytes max_chunk_size chunk_delay transfer_id offset data (remaining_bytes) transfer_id offset pending_bytes (max_chunk_size) (chunk_delay) transfer_id offset data remaining_bytes=0 transfer_id status=OK set transfer parameters requested bytes (zero or more chunks) update transfer parameters (as needed) final chunk acknowledge completion

Client to server transfer (write)

blockdiag client server transfer_id transfer_id offset pending_bytes max_chunk_size chunk_delay transfer_id offset data (remaining_bytes) transfer_id offset pending_bytes (max_chunk_size) (chunk_delay) transfer_id offset data remaining_bytes=0 transfer_id status=OK start set transfer parameters requested bytes (zero or more chunks) update transfer parameters (as needed) final chunk acknowledge completion

Errors

At any point, either the client or server may terminate the transfer by sending an error chunk with the transfer ID and a non-OK status.

Transmitter flow

graph TD start([Client initiates<br>transfer]) -->data_request data_request[Receive transfer<br>parameters]-->send_chunk send_chunk[Send chunk]-->sent_all sent_all{Sent final<br>chunk?} -->|yes|wait sent_all-->|no|sent_requested sent_requested{Sent all<br>pending?}-->|yes|data_request sent_requested-->|no|send_chunk wait[Wait for receiver]-->is_done is_done{Received<br>final chunk?}-->|yes|done is_done-->|no|data_request done([Transfer complete])

Receiver flow

graph TD start([Client initiates<br>transfer]) -->request_bytes request_bytes[Set transfer<br>parameters]-->wait wait[Wait for chunk]-->received_chunk received_chunk{Received<br>chunk by<br>deadline?}-->|no|request_bytes received_chunk-->|yes|check_chunk check_chunk{Correct<br>offset?} -->|yes|process_chunk check_chunk --> |no|request_bytes process_chunk[Process chunk]-->final_chunk final_chunk{Final<br>chunk?}-->|yes|signal_completion final_chunk{Final<br>chunk?}-->|no|received_requested received_requested{Received all<br>pending?}-->|yes|request_bytes received_requested-->|no|wait signal_completion[Signal completion]-->done done([Transfer complete])