Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a direct way to get asynchronous results #7855

Open
glassez opened this issue Feb 9, 2025 · 3 comments
Open

Add a direct way to get asynchronous results #7855

glassez opened this issue Feb 9, 2025 · 3 comments

Comments

@glassez
Copy link
Contributor

glassez commented Feb 9, 2025

(It's something a bit like #7558. But unlike it, it should not depend on alerts.)

Now, to get some data from libtorrent, we have two options - either use a blocking call or receive the result asynchronously through alerts.
The first way is bad for interactive applications, because it either blocks the main thread, which can cause GUI to hang, or we have to workaround this by using some tricks with additional threads (as if making it asynchronous).
The second way is also inconvenient, as it makes the code confusing and requires additional tricks. IMO, alerts are good for use within the Observer pattern (for example, when tracking some internal events or when it makes sense to have a request and receive data in different piece of logic), but they look unsuitable when requesting data directly.
Earlier, I suggested simply implementing direct access to such data from app thread with mutex-based protection, but this was rejected due to the reluctance to mess with mutexes in libtorrent in order to ensure correct multithreaded access. I agree, it could look more complicated than the current event-based access way.
But nevertheless, I would highly like to get a friendlier way of getting the data.
Now I believe that futures could be a good option in this matter. Leaving libtorrent to its current method of implementing data access through an event queue, futures could provide the user side with a direct way to obtain the results of these access requests, deciding on its own whether to do it synchronously or asynchronously.
So all methods like torrent_handle::get_peer_info(), torrent_handle::url_seeds(), session_handle::is_listening(), session_handle::listen_port(), torrent_handle::piece_availability(), torrent_handle::get_download_queue(), torrent_handle::trackers(), torrent_handle::status() (and maybe some other similar ones not mentioned here) should return std::future instantiation with appropriate result. (This will also make previously added post_* methods and their corresponding alerts unnecessary.)
Some other methods that would make sense to use in different patterns (e.g. torrent_handle::save_resume_data()) could have both a return value of type std::future and a corresponding alert.

@glassez
Copy link
Contributor Author

glassez commented Feb 14, 2025

Honestly, I was impressed by QFuture when I made my suggestions above. I thought std::future had comparable functionality. Unfortunately std::future turned out to suck completely. But maybe Boost can still provide what I need.

@arvidn
Copy link
Owner

arvidn commented Feb 15, 2025

I imagine the main challenge with a future-like object (or any other kind of message/notification) is that it needs to play well with some message loop. I don't think future can easily be combined with other things to wait for. e.g. a socket, a Qt event, epoll, etc.

@glassez
Copy link
Contributor Author

glassez commented Feb 15, 2025

@arvidn
Let's imagine that I need to get some data (for example, trackers) in order to do something with them. Now I can either call torrent_handle::trackers(), which leaves the logic straightforward, but it is highly undesirable to use it in a GUI thread, because it can be blocked indefinitely. Or I can use torrent_handle::post_trackers() and do the rest of the work when I receive the corresponding alert. This makes the logic more complex, especially if the same data is requested for different tasks from multiple code locations.
Using futures (provided that their implementation supports continuations), I could have straightforward logic, but not use blocking calls (unless absolutely necessary). For example:

t.get_trackers().then([]
{
    // do something
});

... or:

t.get_resume_data().then([]
{
    // export torrent file
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants