#pragma once ///@file #include "box_ptr.hh" #include "ref.hh" #include "logging.hh" #include "serialise.hh" #include "types.hh" #include "config.hh" #include #include namespace nix { struct FileTransferSettings : Config { Setting enableHttp2{this, true, "http2", "Whether to enable HTTP/2 support."}; Setting userAgentSuffix{this, "", "user-agent-suffix", "String appended to the user agent in HTTP requests."}; Setting httpConnections{ this, 25, "http-connections", R"( The maximum number of parallel TCP connections used to fetch files from binary caches and by other downloads. It defaults to 25. 0 means no limit. )", {"binary-caches-parallel-connections"}}; Setting connectTimeout{ this, 0, "connect-timeout", R"( The timeout (in seconds) for establishing connections in the binary cache substituter. It corresponds to `curl`’s `--connect-timeout` option. A value of 0 means no limit. )"}; Setting stalledDownloadTimeout{ this, 300, "stalled-download-timeout", R"( The timeout (in seconds) for receiving data from servers during download. Lix cancels idle downloads after this timeout's duration. )"}; Setting tries{this, 5, "download-attempts", "How often Lix will attempt to download a file before giving up."}; }; extern FileTransferSettings fileTransferSettings; struct FileTransferRequest { std::string uri; Headers headers; std::string expectedETag; bool verifyTLS = true; bool head = false; size_t tries = fileTransferSettings.tries; unsigned int baseRetryTimeMs = 250; ActivityId parentAct; std::optional data; std::string mimeType; FileTransferRequest(std::string_view uri) : uri(uri), parentAct(getCurActivity()) { } std::string verb() { return data ? "upload" : "download"; } }; struct FileTransferResult { bool cached = false; std::string etag; std::string effectiveUri; std::string data; uint64_t bodySize = 0; /* An "immutable" URL for this resource (i.e. one whose contents will never change), as returned by the `Link: ; rel="immutable"` header. */ std::optional immutableUrl; }; class Store; struct FileTransfer { virtual ~FileTransfer() { } /** * Enqueue a data transfer request, returning a future to the result of * the download. The future may throw a FileTransferError * exception. */ virtual std::future enqueueFileTransfer(const FileTransferRequest & request) = 0; /** * Synchronously transfer a file. */ FileTransferResult transfer(const FileTransferRequest & request); /** * Download a file, returning its contents through a source. Will not return * before the transfer has fully started, ensuring that any errors thrown by * the setup phase (e.g. HTTP 404 or similar errors) are not postponed to be * thrown by the returned source. The source will only throw errors detected * during the transfer itself (decompression errors, connection drops, etc). */ virtual box_ptr download(FileTransferRequest && request) = 0; enum Error { NotFound, Forbidden, Misc, Transient, Interrupted }; }; /** * @return a shared FileTransfer object. * * Using this object is preferred because it enables connection reuse * and HTTP/2 multiplexing. */ ref getFileTransfer(); /** * @return a new FileTransfer object * * Prefer getFileTransfer() to this; see its docs for why. */ ref makeFileTransfer(); class FileTransferError : public Error { public: FileTransfer::Error error; /// intentionally optional std::optional response; template FileTransferError(FileTransfer::Error error, std::optional response, const Args & ... args); }; }