Add timeout to download_sd_blob
Created by: kaykurokawa
Fixes https://github.com/lbryio/lbry/issues/716 and https://github.com/lbryio/lbry/issues/504 by adding a timeout argument to function download_sd_blob(). The timeout detects if the blob has been downloaded within a specified time, and if not, it throws DownloadTimeoutError and cleans everything up.
As a side effect, the timeout behaviour when calling API command get is a bit different now. Now it will wait 180 seconds (or whatever the timeout is set to) for the sd blob to download, and if it does , waits another 180 seconds for the first blob to download. Before it waited 180 seconds for both the sd blob and first blob.
f1845c1 In SingleProgressManager, which we will add the timeout mechanism, use twisted's LoopingCall mechanism instead of reactor.callLater to do looping calls as it is much simpler. safe_start_looping_call and safe_stop_looping_call is added to lbrynet.utils and should be used by other classes which need looping calls.
ccb7991 Add timeout do download_sd_blob(). Make SingleProgressManager , which checks when a single blob is downloaded, also responsible for keeping track of the timeout. Create DownloadTimeoutError in lbrynet.Error to use as a standard exception for indicating timeouts.
a5f4396 Use the newly added timeout mechanism for download_sd_blob in GetStream class. Note that GetStream still has its own timeout mechanism for checking when a single blob (that is not the sd blob) is downloaded. Getstream's timeout mechanism is started after download_sd_blob() is finished.
345a1f2 Just breaking up GetStream for unit testing
6995169 use DownloadTimeoutError instead of generic Exception
0452338 use safe_start_looping_call in lbrynet.utils
7ee0489 added unit tests for GetStream
eba854a Use timeout mechanism in download_sd_blob() instead of creating its own in Daemon._download_blob()
f058f18 This is a fix for test_double_download in function/test_misc. It was revealed in test_double_download that when starting the DownloadManager, progress_manager.start() could stop the download (due to it already having the blobs), but then after it would call connection_manager.start() and leave the ConnectionManager running (the tests would then fail as Reactor is unclean).
So have ConnectionManager start up first , and then start the progress manager. Also simplify the resume_downloading() and stop_downloading() command by using inline callbacks instead of Deferred lists.
Note also here the complexity and exception swallowing in CryptStreamDownloader that uses resume_downloading() and stop_downloading(). This should be fixed in a future PR.