made file downloading and caching smarter
tries eTag and ContentDisposition headers for file name+format catches offline and server error/url error scenarios creates a "recent" file copy if successful, and returns that as a fallback in an error scenario, if it exists
This commit is contained in:
parent
230b7338a6
commit
ba0cbbd5c8
@ -12,49 +12,96 @@ namespace TED.Utils
|
|||||||
internal class FileUtilities
|
internal class FileUtilities
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads a file from a specified URL and saves it to a cache.
|
/// Downloads a file from a specified URL and saves it to a local cache.
|
||||||
/// If the file already exists in the cache, the function returns the path to the cached file.
|
/// If the file already exists in the cache, the function returns the path to the cached file.
|
||||||
/// If the file does not exist in the cache, the function downloads the file, saves it to the cache, and then returns the path to the cached file.
|
/// If the file does not exist in the cache, the function downloads the file, saves it to the cache, and then returns the path to the cached file.
|
||||||
|
/// In the event of an error with file retrieval, the most recently used file will be returned, if it exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url">The URL of the file to download.</param>
|
/// <param name="url">The URL of the file to download.</param>
|
||||||
/// <returns>A task that represents the asynchronous operation. The task result is the path to the downloaded (or cached) file.</returns>
|
/// <returns>A task that represents the asynchronous operation. The task result is the path to the downloaded (or cached) file.</returns>
|
||||||
public static async Task<string> DownloadAndCacheFileAsync(string url)
|
public static async Task<string> DownloadAndCacheFileAsync(string url)
|
||||||
{
|
{
|
||||||
using (var client = new HttpClient()
|
var tedDirectory = Path.Combine(Path.GetTempPath(), "TED");
|
||||||
|
var recentPath = Path.Combine(tedDirectory, "recent.png");
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Timeout = TimeSpan.FromSeconds(10)
|
using (var client = new HttpClient()
|
||||||
})
|
|
||||||
{
|
|
||||||
var response = await client.GetAsync(url);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
var etag = response.Headers.ETag?.Tag.Replace("\"", string.Empty) ?? "untagged";
|
|
||||||
if (!Directory.Exists(Path.Combine(Path.GetTempPath(), "TED")))
|
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "TED"));
|
Timeout = TimeSpan.FromSeconds(10)
|
||||||
}
|
})
|
||||||
var path = Path.Combine(Path.GetTempPath(), "TED", $"{etag}.png");
|
|
||||||
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
{
|
||||||
return path;
|
var response = await client.GetAsync(url);
|
||||||
}
|
|
||||||
|
|
||||||
var filesToDelete = Directory.GetFiles(Path.Combine(Path.GetTempPath(), "TED"), "*.png")
|
try
|
||||||
.Where(filePath => Path.GetFileNameWithoutExtension(filePath) != etag);
|
|
||||||
foreach (var fileToDelete in filesToDelete)
|
|
||||||
{
|
|
||||||
File.Delete(fileToDelete);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
|
||||||
{
|
|
||||||
using (var fileStream = new FileStream(path, FileMode.CreateNew))
|
|
||||||
{
|
{
|
||||||
await stream.CopyToAsync(fileStream);
|
response.EnsureSuccessStatusCode();
|
||||||
return path;
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
// If we catch here, it's a URL error or server-side issue.
|
||||||
|
if (File.Exists(recentPath))
|
||||||
|
{
|
||||||
|
return recentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = "ted.png";
|
||||||
|
|
||||||
|
if (response.Headers.ETag != null)
|
||||||
|
{
|
||||||
|
fileName = $"{response.Headers.ETag?.Tag.Replace("\"", string.Empty)}.png";
|
||||||
|
}
|
||||||
|
else if (response.Content.Headers.ContentDisposition != null)
|
||||||
|
{
|
||||||
|
fileName = $"{response.Content.Headers.ContentDisposition.FileName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(tedDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(tedDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var downloadPath = Path.Combine(tedDirectory, fileName);
|
||||||
|
|
||||||
|
|
||||||
|
if (File.Exists(downloadPath))
|
||||||
|
{
|
||||||
|
return downloadPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filesToDelete = Directory.GetFiles(tedDirectory)
|
||||||
|
.Where(filePath => Path.GetFileNameWithoutExtension(filePath) != fileName && Path.GetFileNameWithoutExtension(filePath) != "recent");
|
||||||
|
foreach (var fileToDelete in filesToDelete)
|
||||||
|
{
|
||||||
|
File.Delete(fileToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||||
|
{
|
||||||
|
using (var fileStream = new FileStream(downloadPath, FileMode.CreateNew))
|
||||||
|
{
|
||||||
|
await stream.CopyToAsync(fileStream);
|
||||||
|
if(File.Exists(recentPath))
|
||||||
|
{
|
||||||
|
File.Delete(recentPath);
|
||||||
|
}
|
||||||
|
File.Copy(downloadPath, recentPath);
|
||||||
|
return downloadPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(HttpRequestException e)
|
||||||
|
{
|
||||||
|
// If we catch here, we're offline.
|
||||||
|
if (File.Exists(recentPath))
|
||||||
|
{
|
||||||
|
return recentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user