Files

151 lines
5.0 KiB
C#

using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Pf2e.Scrapper.Helpers;
namespace Pf2e.Scrapper.Importers.Repositories;
public abstract class AbstractGitHubRepository(AbstractImporter importer)
: AbstractImporterRepository(importer)
{
public abstract string Repository { get; }
public abstract string AssetName { get; }
public override void Update(ProcessProgress progress)
{
ReleaseInformation releaseInformation = GetReleaseInformation();
string? currentVersion = GetCurrentVersion();
if (currentVersion == releaseInformation.TagName)
{
progress.Local.Complete();
progress.Information(
$"Данные {Repository} актуальны, текущая версия {currentVersion}."
);
return;
}
progress.Information(
$"Данные {Repository} устарели, обновляем {RepositoryDirPath} до версии {releaseInformation.TagName}..."
);
string assetFile = DownloadAsset(progress, releaseInformation);
ExtractAsset(assetFile, RepositoryDirPath, progress);
File.WriteAllText(
Path.Combine(RepositoryDirPath, "version.txt"),
releaseInformation.TagName
);
}
private ReleaseInformation GetReleaseInformation()
{
string releasesUrl = $"https://api.github.com/repos/{Repository}/releases/latest";
using HttpClient client = new();
client.DefaultRequestHeaders.UserAgent.Add(
new ProductInfoHeaderValue("Pf2eDataScrapper", "1.0")
);
string json = client.GetStringAsync(releasesUrl).Result;
JObject jObject = JObject.Parse(json);
return new()
{
TagName = jObject.SelectToken("tag_name")!.ToObject<string>()!,
DownloadUrl = jObject
.SelectToken("assets[?(@.name == '" + AssetName + "')].browser_download_url")!
.ToObject<string>()!,
Size = jObject
.SelectToken("assets[?(@.name == '" + AssetName + "')].size")!
.ToObject<int>()!,
};
}
private string? GetCurrentVersion()
{
string versionFilePath = Path.Combine(RepositoryDirPath, "version.txt");
if (File.Exists(versionFilePath))
{
return File.ReadAllText(versionFilePath).Trim();
}
return null;
}
private string DownloadAsset(ProcessProgress progress, ReleaseInformation releaseInformation)
{
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".zip";
using var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
progress.Local.Reset(releaseInformation.Size);
progress.Local.Start(
$"[1/2] Загрузка {releaseInformation.TagName} ({releaseInformation.Size / 1024 / 1024} МБ)..."
);
Task.Run(async () =>
{
using HttpClient client = new();
using var response = await client.GetAsync(
releaseInformation.DownloadUrl,
HttpCompletionOption.ResponseHeadersRead
);
using var download = await response.Content.ReadAsStreamAsync();
var buffer = new byte[81920];
int bytesRead;
var t = CancellationToken.None;
while ((bytesRead = await download.ReadAsync(buffer, t).ConfigureAwait(false)) != 0)
{
await fileStream
.WriteAsync(buffer.AsMemory(0, bytesRead), t)
.ConfigureAwait(false);
progress.Local.Current += bytesRead;
}
})
.Wait();
progress.Local.Complete();
return fileName;
}
private void ExtractAsset(string assetFile, string targetDir, ProcessProgress progress)
{
using var zip = ZipFile.OpenRead(assetFile);
progress.Local.Reset(zip.Entries.Count);
progress.Local.Start("[2/2] Распаковка архива...");
foreach (var entry in zip.Entries)
{
if (string.IsNullOrEmpty(entry.Name))
continue; // Skip directories
string destinationPath = Path.Combine(targetDir, entry.FullName);
string directoryPath = Path.GetDirectoryName(destinationPath)!;
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
entry.ExtractToFile(destinationPath, true);
progress.Local.Current++;
}
progress.Local.Complete();
}
private class ReleaseInformation
{
public string TagName { get; init; } = null!;
public string DownloadUrl { get; init; } = null!;
public int Size { get; init; } = 0;
}
}