Lean  $LEAN_TAG$
BaseDownloaderDataProvider.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15 */
16 
17 using System;
18 using System.IO;
19 using QuantConnect.Util;
20 
22 {
23  /// <summary>
24  /// Base downloader implementation with some helper methods
25  /// </summary>
27  {
28  /// <summary>
29  /// Synchronizer in charge of guaranteeing a single download per path request
30  /// </summary>
31  private readonly KeyStringSynchronizer _singleDownloadSynchronizer = new();
32 
33  /// <summary>
34  /// Helper method which guarantees each requested key is downloaded only once concurrently if required based on <see cref="NeedToDownload"/>
35  /// </summary>
36  /// <param name="key">A string representing where the data is stored</param>
37  /// <param name="download">The download operation we want to perform once concurrently per key</param>
38  /// <returns>A <see cref="Stream"/> of the data requested</returns>
39  protected Stream DownloadOnce(string key, Action<string> download)
40  {
41  // If we don't already have this file or its out of date, download it
42  if (NeedToDownload(key))
43  {
44  // only the first thread will download the rest will wait for him to finish
45  _singleDownloadSynchronizer.Execute(key, singleExecution: true, () => download(key));
46  // single download finished, let's get the stream!
47  return GetStream(key);
48  }
49 
50  // even if we are not downloading the file because it exists we need to synchronize because the download might still be updating the file on disk
51  return _singleDownloadSynchronizer.Execute(key, () => GetStream(key));
52  }
53 
54  /// <summary>
55  /// Get's the stream for a given file path
56  /// </summary>
57  protected virtual Stream GetStream(string key)
58  {
59  return base.Fetch(key);
60  }
61 
62  /// <summary>
63  /// Main filter to determine if this file needs to be downloaded
64  /// </summary>
65  /// <param name="filePath">File we are looking at</param>
66  /// <returns>True if should download</returns>
67  protected abstract bool NeedToDownload(string filePath);
68  }
69 }