Files
simplexmq/spec/modules/Simplex/FileTransfer/Client/Main.md
Evgeny @ SimpleX Chat f131531f5a xftp specs
2026-03-13 16:12:20 +00:00

2.9 KiB

Simplex.FileTransfer.Client.Main

XFTP CLI client: send, receive, delete files with parallel chunk operations and web URI encoding.

Source: FileTransfer/Client/Main.hs

Non-obvious behavior

1. Web URI encoding: base64url(deflate(YAML))

encodeWebURI compresses the YAML-encoded file description with raw DEFLATE, then base64url-encodes the result. decodeWebURI reverses this. The compressed description goes in the URL fragment (after #), which is never sent to the server — the file description stays client-side.

2. CLI receive accepts both file paths and URLs

getInputFileDescription checks if the input starts with http:// or https://. If so, it extracts the URL fragment, decodes it via decodeWebURI, and uses the resulting file description. Otherwise, it reads a YAML file from disk. This allows receiving files via web links without a browser.

3. Redirect chain depth limited to 1

receive tracks a depth parameter starting at 1. After following one redirect, depth becomes 0. A second redirect throws "Redirect chain too long". This prevents infinite redirect loops from malicious file descriptions.

4. Parallel chunk uploads with server grouping

uploadFile groups chunks by server via groupAllOn, then uses pooledForConcurrentlyN 16 to process up to 16 server-groups concurrently. Within each group, chunks are uploaded sequentially (mapM). Errors from any chunk are collected and the first one is thrown.

5. Random server selection

getXFTPServer selects a random server from the provided list for each chunk. With a single server, it's deterministic. With multiple servers, it uses StdGen in a TVar for thread-safe random selection via stateTVar.

6. withReconnect nests retry with reconnection

withReconnect wraps withRetry twice: the outer retry reconnects to the server, and the inner operation runs against the connection. On failure, the server connection is explicitly closed before retrying, forcing a fresh connection on the next attempt.

7. withRetry rejects zero retries

withRetry' 0 returns an "internal: no retry attempts" error. withRetry' 1 executes the action once without retry. This off-by-one convention means retryCount = 3 (the default) gives 3 total attempts (1 initial + 2 retries).

8. File description auto-deletion prompt

After successful receive or delete, removeFD either auto-deletes the file description (if --yes flag) or prompts the user. This prevents accidental reuse of one-time file descriptions — each receive consumes the description by ACKing chunks on the server.

9. Sender description uses first replica's server

createSndFileDescription takes the server from the first replica of each chunk for the sender's FileChunkReplica. This reflects the current limitation that each chunk is uploaded to exactly one server — the sender description records that single server.