host.transfer.base¶
-
class otto.host.transfer.base.TransferContext(transfer: str, host_name: str, max_filename_len: int =
255, exec_cmd: collections.abc.Callable[..., Coroutine[Any, Any, CommandStatus]] | None =None, connections: ConnectionManager | None =None, nc_options: NcOptions | None =None, scp_options: ScpOptions | None =None, get_local_ip: collections.abc.Callable[[], str] | None =None, filesystem: EmbeddedFileSystem | None =None)¶ Bases:
objectConstruction inputs a host provides to build its transfer backend via
BaseFileTransfer.create(). The frozen public seam for custom transfer backends. Carries the union of what any family’s built-ins receive at their call sites; a unix backend reads the unix fields, an embedded backend the embedded ones. Selector validation (host-family applicability) runs before construction, so a backend never sees a ctx missing the fields it needs.-
exec_cmd : Callable[..., Coroutine[Any, Any, CommandStatus]] | None =
None¶
-
connections : ConnectionManager | None =
None¶
-
scp_options : ScpOptions | None =
None¶
-
filesystem : EmbeddedFileSystem | None =
None¶
-
exec_cmd : Callable[..., Coroutine[Any, Any, CommandStatus]] | None =
- otto.host.transfer.base.validate_filename_lengths(files: list[Path], limit: int, host_name: str) tuple[Status, str]¶
Reject files whose basename exceeds the host’s filesystem cap.
Shared by
UnixFileTransfer(Unix) andEmbeddedFileTransfer(embedded) so every backend surfaces the same self-explaining error. Without this guard the failure modes are:Unix SCP/SFTP/FTP: server returns
File name too long(errno 36), mid-transfer, after the local file is already read.Embedded FAT (8.3, no LFN) or LittleFS over
NAME_MAX: device failsfs_openwith-ENOENT, giving no hint that the name was the problem.
Returns
(Status.Success, '')when every basename fits.
-
class otto.host.transfer.base.BaseFileTransfer(name: str, max_filename_len: int =
255)¶ Bases:
ABCShared API + progress plumbing for any file-transfer backend.
The public
put_files/get_filessurface (filename-length validation, shared Rich progress acquisition) is owned by this base. Concrete backends (Unix’sUnixFileTransfersubclasses (ScpFileTransfer,SftpFileTransfer,FtpFileTransfer,NcFileTransfer), embedded’sEmbeddedFileTransfersubclasses (ConsoleFileTransfer,TftpFileTransfer), and any future ones) implement two abstract methods —_run_putand_run_get— both of which receive aTransferProgressFactoryand are responsible for invoking it at least once per source file, terminating withbytes_done == bytes_totalto mark completion.The progress-bar capability is enforced at the type system level:
abc.abstractmethodrefuses to instantiate a subclass that omits either method, so a new backend cannot be defined without supplying a way to report progress. The runtime contract test (TestTransferProgressContract) verifies the factory is actually invoked, not just that the methods exist.-
host_families : frozenset[str] =
frozenset({})¶ Host-family selectors this backend serves — a subset of
{'unix', 'embedded'}. Subclasses declare it; the spec field_validator rejects a backend on a host of the wrong family. A backend with an empty set can never validate and is rejected at registration.
- classmethod create(ctx: TransferContext) BaseFileTransfer¶
Build a transfer backend from a
TransferContext.The uniform construction seam (WS#4). Concrete backends override this to run their exact construction against the ctx fields they need. Not an
abstractmethoddeliberately: only registered built-ins are ever constructed throughcreate, and test doubles that subclassBaseFileTransferonly to exercise the progress contract must not be forced to implement it.
-
host_families : frozenset[str] =
- otto.host.transfer.base.NcPortStrategy¶
Strategy for finding free ports on the remote host for netcat transfers.
Available strategies:
'auto'(default) — try each built-in strategy in order (ss → netstat → python → proc) and cache the first one that succeeds.'ss'— parsess -tlnoutput to find unused ports.'netstat'— parsenetstat -tlnoutput (fallback for hosts without ss).'python'— bind a socket to port 0 via apython/python3one-liner and let the OS assign a free port.'proc'— read/proc/net/tcpdirectly (Linux-only, always available as a last resort).'custom'— run the shell command specified innc_port_cmd; the command must print a free port number to stdout.
alias of
Literal[‘auto’, ‘ss’, ‘netstat’, ‘python’, ‘proc’, ‘custom’]
- otto.host.transfer.base.NcListenerCheck¶
Strategy for checking if a remote nc listener is ready.
Available strategies:
'auto'(default) — probe for ss, then netstat, falling back to proc. The first tool found is cached and reused for subsequent checks.'ss'— check for a LISTEN socket viass -tln sport = :<port>.'netstat'— grepnetstat -tlnoutput for the port.'proc'— scan/proc/net/tcpfor LISTEN state (0A) on the port (Linux-only, always available as a last resort).'custom'— run the shell command specified innc_listener_cmdwith a{port}placeholder. Must exit 0 when the port is listening.
alias of
Literal[‘auto’, ‘ss’, ‘netstat’, ‘proc’, ‘custom’]