|
4 | 4 | using System.Net.Http; |
5 | 5 | using System.Security.Cryptography; |
6 | 6 | using System.Text; |
| 7 | +using System.Threading; |
7 | 8 | using System.Threading.Tasks; |
8 | 9 | using Semmle.Util.Logging; |
9 | 10 |
|
@@ -99,19 +100,49 @@ public static string ComputeFileHash(string filePath) |
99 | 100 | return hex.ToString(); |
100 | 101 | } |
101 | 102 |
|
102 | | - private static async Task DownloadFileAsync(string address, string filename) |
| 103 | + private static async Task DownloadFileAsync(string address, string filename, HttpClient httpClient, CancellationToken token) |
103 | 104 | { |
104 | | - using var httpClient = new HttpClient(); |
105 | | - using var contentStream = await httpClient.GetStreamAsync(address); |
| 105 | + using var contentStream = await httpClient.GetStreamAsync(address, token); |
106 | 106 | using var stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true); |
107 | | - await contentStream.CopyToAsync(stream); |
| 107 | + await contentStream.CopyToAsync(stream, token); |
| 108 | + } |
| 109 | + |
| 110 | + private static void DownloadFileWithRetry(string address, string fileName, int tryCount, int timeoutMilliSeconds, ILogger logger) |
| 111 | + { |
| 112 | + logger.LogDebug($"Downloading {address} to {fileName}."); |
| 113 | + using HttpClient client = new(); |
| 114 | + |
| 115 | + for (var i = 0; i < tryCount; i++) |
| 116 | + { |
| 117 | + logger.LogDebug($"Attempt {i + 1} of {tryCount}. Timeout: {timeoutMilliSeconds} ms."); |
| 118 | + using var cts = new CancellationTokenSource(); |
| 119 | + cts.CancelAfter(timeoutMilliSeconds); |
| 120 | + try |
| 121 | + { |
| 122 | + DownloadFileAsync(address, fileName, client, cts.Token).GetAwaiter().GetResult(); |
| 123 | + logger.LogDebug($"Downloaded {address} to {fileName}."); |
| 124 | + return; |
| 125 | + } |
| 126 | + catch (Exception exc) |
| 127 | + { |
| 128 | + logger.LogDebug($"Failed to download {address} to {fileName}. Exception: {exc.Message}"); |
| 129 | + timeoutMilliSeconds *= 2; |
| 130 | + |
| 131 | + if (i == tryCount - 1) |
| 132 | + { |
| 133 | + logger.LogDebug($"Failed to download {address} to {fileName} after {tryCount} attempts."); |
| 134 | + // Rethrowing the last exception |
| 135 | + throw; |
| 136 | + } |
| 137 | + } |
| 138 | + } |
108 | 139 | } |
109 | 140 |
|
110 | 141 | /// <summary> |
111 | 142 | /// Downloads the file at <paramref name="address"/> to <paramref name="fileName"/>. |
112 | 143 | /// </summary> |
113 | | - public static void DownloadFile(string address, string fileName) => |
114 | | - DownloadFileAsync(address, fileName).GetAwaiter().GetResult(); |
| 144 | + public static void DownloadFile(string address, string fileName, ILogger logger) => |
| 145 | + DownloadFileWithRetry(address, fileName, tryCount: 3, timeoutMilliSeconds: 10000, logger); |
115 | 146 |
|
116 | 147 | public static string ConvertPathToSafeRelativePath(string path) |
117 | 148 | { |
|
0 commit comments