WebAPI/WebUI: Add support for downloading completed torrent files#23743
WebAPI/WebUI: Add support for downloading completed torrent files#23743Piccirello wants to merge 2 commits intoqbittorrent:masterfrom
Conversation
| struct Response | ||
| { | ||
| ResponseStatus status; | ||
| HeaderMap headers; | ||
| QByteArray content; | ||
| std::optional<StreamingInfo> streaming; |
There was a problem hiding this comment.
This PR raises some big architectural questions around how we want to handle streaming. I opted for adding an optional streaming struct to the existing Response struct, to ensure that non-streaming requests aren't impacted in terms of performance or memory usage. There are other ways to do this, but this seemed like the best balance of being able to integrate streaming into our existing architecture with minimal changes (see src/base/http/connection.cpp).
|
@Piccirello
|
I agree in the abstract, though I think this change preserves the simplicity well. Nevertheless if you'd prefer a different approach then I would appreciate a more specific suggestion when you have the time.
This is true of spinning HDDs but generally does not apply to modern SSDs. SSDs handle parallelism well, especially in the small chunks that this code reads. If this remains a concern we can limit the server to one concurrent stream, or make it configurable. |
To be honest, the idea of fetching files over qbt webserver crossed my mind more than a few times before jagannatharjun presented his work. However over the time, I'm leaning more to delegate that work to some specific application that is designed to do that job well, instead of shoving it into the simple qbt webserver. I suppose there are a few reasons. |
|
I generally agree with the first part of the @Chocobo1 comment above. |
This is a good point to bring up. I think this question describes the WebUI in general. There was a WebUI implementation with a limited feature set, and over the last 8 years myself and other devs have added more and more functionality. Technically none of this is related to core torrent operations either, but a dedicated group of individuals focuses on it. We (@Chocobo1 included) fix bugs and address feature requests that we think are reasonable. It doesn't mean we have to build everything users ask for. The tight integration of this feature directly in qBittorrent makes for a much better experience than an equivalent, external piece of software could provide. It works especially well on remote seedboxes. For that reason, deluge supports this via the "deluge-streaming" plugin and ruTorrent via the File Manager plugin and MediaStream plugin. |
|
I'd really love to get some early feedback on this PR so that it doesn't grow too stale. |
This PR adds a new WebAPI endpoint for downloading individual torrent files directly from the WebUI. This allows users to retrieve completed files without needing a separate file server/access mechanism. It also supports streaming files directly to a media player, like VLC.
qBittorrent's HTTP server doesn't currently support the concept of streaming. Any data must be fully loaded into memory before it can be sent to the client. But this approach is impractical for large files. Now, qBittorrent's HTTP server additionally supports thread-based streaming. When a download is requested, the HTTP headers are sent on the main thread. The
QTcpSocketis then moved to a dedicated worker thread that handles the file streaming synchronously, to avoid blocking. Once the download completes, the worker thread is cleaned up. This approach allows for a relatively simple implementation and reliable flow control viawaitForBytesWritten(). (I also explored implementing this with async streaming but the code was much more complicated and I couldn't get flow control working correctly)To keep memory usage low, file data is read in 256KB chunks with a 512KB socket buffer limit. The streaming thread blocks when the buffer is full, ensuring memory usage stays constant regardless of file size or transfer rate. We currently limit the server to 3 concurrent file downloads to bound total resource usage, but this is just an arbitrary limit.
Closes #15561.
Closes #15729.