2025-02-26 16:17:20 +01:00
|
|
|
|
using CodexClient;
|
|
|
|
|
|
using Logging;
|
|
|
|
|
|
using Utils;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AutoClient.Modes.FolderStore
|
|
|
|
|
|
{
|
|
|
|
|
|
public class FileSaver
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ILog log;
|
|
|
|
|
|
private readonly CodexWrapper instance;
|
2025-02-27 09:15:28 +01:00
|
|
|
|
private readonly Stats stats;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
private readonly string folderFile;
|
|
|
|
|
|
private readonly FileStatus entry;
|
|
|
|
|
|
|
2025-02-27 09:15:28 +01:00
|
|
|
|
public FileSaver(ILog log, CodexWrapper instance, Stats stats, string folderFile, FileStatus entry)
|
2025-02-26 16:17:20 +01:00
|
|
|
|
{
|
|
|
|
|
|
this.log = log;
|
|
|
|
|
|
this.instance = instance;
|
2025-02-27 09:15:28 +01:00
|
|
|
|
this.stats = stats;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
this.folderFile = folderFile;
|
|
|
|
|
|
this.entry = entry;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool HasFailed { get; private set; }
|
2025-02-27 09:22:57 +01:00
|
|
|
|
public bool Changes { get; private set; }
|
2025-02-26 16:17:20 +01:00
|
|
|
|
|
|
|
|
|
|
public void Process()
|
|
|
|
|
|
{
|
|
|
|
|
|
HasFailed = false;
|
2025-02-27 09:22:57 +01:00
|
|
|
|
Changes = false;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
if (HasRecentPurchase(entry))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"Purchase running: '{entry.PurchaseId}'");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EnsureBasicCid();
|
|
|
|
|
|
CreateNewPurchase();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void EnsureBasicCid()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsBasicCidAvailable()) return;
|
|
|
|
|
|
UploadFile();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsBasicCidAvailable()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(entry.BasicCid)) return false;
|
|
|
|
|
|
return NodeContainsBasicCid();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool HasRecentPurchase(FileStatus entry)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(entry.PurchaseId)) return false;
|
|
|
|
|
|
var purchase = GetPurchase(entry.PurchaseId);
|
|
|
|
|
|
if (purchase == null) return false;
|
|
|
|
|
|
if (!purchase.IsStarted) return false;
|
|
|
|
|
|
|
|
|
|
|
|
// Purchase is started. But, if it finishes soon, we will treat it as already finished.
|
|
|
|
|
|
var threshold = DateTime.UtcNow + TimeSpan.FromHours(3.0);
|
|
|
|
|
|
if (entry.PurchaseFinishedUtc < threshold)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"Running purchase will expire soon.");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private StoragePurchase? GetPurchase(string purchaseId)
|
|
|
|
|
|
{
|
|
|
|
|
|
return instance.GetStoragePurchase(purchaseId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool NodeContainsBasicCid()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = instance.Node.DownloadManifestOnly(new ContentId(entry.BasicCid));
|
|
|
|
|
|
return !string.IsNullOrEmpty(result.Cid.Id);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
Log("Failed to download manifest for basicCid");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UploadFile()
|
|
|
|
|
|
{
|
2025-02-27 09:22:57 +01:00
|
|
|
|
Changes = true;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
entry.BasicCid = instance.UploadFile(folderFile).Id;
|
2025-02-27 09:15:28 +01:00
|
|
|
|
stats.SuccessfulUploads++;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
Log($"Successfully uploaded. BasicCid: '{entry.BasicCid}'");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exc)
|
|
|
|
|
|
{
|
|
|
|
|
|
entry.BasicCid = string.Empty;
|
2025-02-27 09:15:28 +01:00
|
|
|
|
stats.FailedUploads++;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
log.Error("Failed to upload: " + exc);
|
|
|
|
|
|
HasFailed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CreateNewPurchase()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(entry.BasicCid)) return;
|
|
|
|
|
|
|
2025-02-27 09:22:57 +01:00
|
|
|
|
Changes = true;
|
2025-02-26 16:17:20 +01:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-02-27 09:15:28 +01:00
|
|
|
|
var request = CreateNewStorageRequest();
|
2025-02-26 16:17:20 +01:00
|
|
|
|
|
2025-02-27 09:15:28 +01:00
|
|
|
|
WaitForSubmitted(request);
|
|
|
|
|
|
WaitForStarted(request);
|
2025-02-26 16:17:20 +01:00
|
|
|
|
|
|
|
|
|
|
entry.PurchaseFinishedUtc = DateTime.UtcNow + request.Purchase.Duration;
|
2025-02-27 09:15:28 +01:00
|
|
|
|
stats.StorageRequestStats.SuccessfullyStarted++;
|
|
|
|
|
|
Log($"Successfully started new purchase: '{entry.PurchaseId}' for {Time.FormatDuration(request.Purchase.Duration)}");
|
2025-02-26 16:17:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception exc)
|
|
|
|
|
|
{
|
|
|
|
|
|
entry.EncodedCid = string.Empty;
|
|
|
|
|
|
entry.PurchaseId = string.Empty;
|
|
|
|
|
|
log.Error("Failed to start new purchase: " + exc);
|
|
|
|
|
|
HasFailed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-27 09:15:28 +01:00
|
|
|
|
private IStoragePurchaseContract CreateNewStorageRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var request = instance.RequestStorage(new ContentId(entry.BasicCid));
|
|
|
|
|
|
entry.EncodedCid = request.Purchase.ContentId.Id;
|
|
|
|
|
|
entry.PurchaseId = request.PurchaseId;
|
|
|
|
|
|
return request;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
stats.StorageRequestStats.FailedToCreate++;
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void WaitForSubmitted(IStoragePurchaseContract request)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
request.WaitForStorageContractSubmitted();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
stats.StorageRequestStats.FailedToSubmit++;
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void WaitForStarted(IStoragePurchaseContract request)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
request.WaitForStorageContractStarted();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
stats.StorageRequestStats.FailedToStart++;
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-26 16:17:20 +01:00
|
|
|
|
private void Log(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
log.Log(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|