cs-codex-dist-tests/Tools/AutoClient/Runner.cs

189 lines
6.3 KiB
C#
Raw Normal View History

using CodexOpenApi;
2024-04-01 18:40:03 +00:00
using CodexPlugin;
using Logging;
using Newtonsoft.Json;
2024-04-01 18:40:03 +00:00
using Utils;
namespace AutoClient
{
public class Runner
{
private readonly ILog log;
private readonly HttpClient client;
private readonly Address address;
private readonly CodexApi codex;
2024-04-01 18:40:03 +00:00
private readonly CancellationToken ct;
private readonly Configuration config;
private readonly ImageGenerator generator;
2024-04-01 18:40:03 +00:00
public Runner(ILog log, HttpClient client, Address address, CodexApi codex, CancellationToken ct, Configuration config, ImageGenerator generator)
2024-04-01 18:40:03 +00:00
{
this.log = log;
this.client = client;
this.address = address;
2024-04-01 18:40:03 +00:00
this.codex = codex;
this.ct = ct;
this.config = config;
this.generator = generator;
2024-04-01 18:40:03 +00:00
}
public async Task Run()
2024-04-01 18:40:03 +00:00
{
while (!ct.IsCancellationRequested)
{
log.Log("New run!");
try
{
await DoRun();
2024-04-01 18:40:03 +00:00
log.Log("Run succcessful.");
}
catch (Exception ex)
{
log.Error("Exception during run: " + ex);
}
await FixedShortDelay();
2024-04-01 18:40:03 +00:00
}
}
private async Task DoRun()
2024-04-01 18:40:03 +00:00
{
var file = await CreateFile();
var cid = await UploadFile(file);
var pid = await RequestStorage(cid);
await WaitUntilStarted(pid);
2024-04-01 18:40:03 +00:00
}
private async Task<string> CreateFile()
2024-04-01 18:40:03 +00:00
{
return await generator.GenerateImage();
2024-04-01 18:40:03 +00:00
}
private async Task<ContentId> UploadFile(string filename)
2024-04-01 18:40:03 +00:00
{
// Copied from CodexNode :/
using var fileStream = File.OpenRead(filename);
2024-04-01 18:40:03 +00:00
var logMessage = $"Uploading file {filename}...";
2024-04-01 18:40:03 +00:00
log.Log(logMessage);
var response = await codex.UploadAsync(fileStream, ct);
2024-04-01 18:40:03 +00:00
if (string.IsNullOrEmpty(response)) FrameworkAssert.Fail("Received empty response.");
if (response.StartsWith("Unable to store block")) FrameworkAssert.Fail("Node failed to store block.");
log.Log($"Uploaded file. Received contentId: '{response}'.");
return new ContentId(response);
}
private async Task<string> RequestStorage(ContentId cid)
2024-04-01 18:40:03 +00:00
{
log.Log("Requesting storage for " + cid.Id);
var result = await codex.CreateStorageRequestAsync(cid.Id, new StorageRequestCreation()
2024-04-01 18:40:03 +00:00
{
Collateral = config.RequiredCollateral.ToString(),
Duration = (config.ContractDurationMinutes * 60).ToString(),
Expiry = (config.ContractExpiryMinutes * 60).ToString(),
Nodes = config.NumHosts,
Reward = config.Price.ToString(),
ProofProbability = "15",
Tolerance = config.HostTolerance
}, ct);
log.Log("Response: " + result);
return result;
}
private async Task<string?> GetPurchaseState(string pid)
{
try
{
// openapi still don't match code.
var str = await client.GetStringAsync($"{address.Host}:{address.Port}/api/codex/v1/storage/purchases/{pid}");
if (string.IsNullOrEmpty(str)) return null;
var sp = JsonConvert.DeserializeObject<StoragePurchase>(str)!;
log.Log($"Purchase {pid} is {sp.State}");
if (!string.IsNullOrEmpty(sp.Error)) log.Log($"Purchase {pid} error is {sp.Error}");
return sp.State;
}
catch (Exception ex)
{
return null;
}
2024-04-01 18:40:03 +00:00
}
private async Task WaitUntilStarted(string pid)
2024-04-01 18:40:03 +00:00
{
log.Log("Waiting till contract is started, or expired...");
try
{
var emptyResponseTolerance = 10;
2024-04-01 18:40:03 +00:00
while (true)
{
await FixedShortDelay();
var status = await GetPurchaseState(pid);
if (string.IsNullOrEmpty(status))
2024-04-01 18:40:03 +00:00
{
emptyResponseTolerance--;
if (emptyResponseTolerance == 0)
{
log.Log("Received 10 empty responses. Applying expiry delay, then carrying on.");
await ExpiryTimeDelay();
return;
}
await FixedShortDelay();
}
else
{
if (status.Contains("pending") || status.Contains("submitted"))
2024-04-01 18:40:03 +00:00
{
await FixedShortDelay();
2024-04-01 18:40:03 +00:00
}
else if (status.Contains("started"))
{
log.Log("Started.");
await FixedDurationDelay();
}
else if (status.Contains("finished"))
{
log.Log("Purchase finished.");
return;
}
else if (status.Contains("error"))
2024-04-01 18:40:03 +00:00
{
await FixedShortDelay();
return;
2024-04-01 18:40:03 +00:00
}
else
{
await FixedShortDelay();
}
2024-04-01 18:40:03 +00:00
}
}
}
catch (Exception ex)
{
log.Log($"Wait failed with exception: {ex}. Assume contract will expire: Wait expiry time.");
await ExpiryTimeDelay();
2024-04-01 18:40:03 +00:00
}
}
private async Task FixedDurationDelay()
{
await Task.Delay(config.ContractDurationMinutes * 60 * 1000);
}
private async Task ExpiryTimeDelay()
2024-04-01 18:40:03 +00:00
{
await Task.Delay(config.ContractExpiryMinutes * 60 * 1000);
2024-04-01 18:40:03 +00:00
}
private async Task FixedShortDelay()
2024-04-01 18:40:03 +00:00
{
await Task.Delay(15 * 1000);
2024-04-01 18:40:03 +00:00
}
}
}