2024-03-20 10:32:16 +00:00
using Logging ;
2023-09-20 06:45:55 +00:00
using Newtonsoft.Json ;
using Utils ;
namespace CodexPlugin
{
public interface IMarketplaceAccess
{
2024-03-20 10:11:41 +00:00
string MakeStorageAvailable ( StorageAvailability availability ) ;
StoragePurchaseContract RequestStorage ( StoragePurchase purchase ) ;
2023-09-20 06:45:55 +00:00
}
public class MarketplaceAccess : IMarketplaceAccess
{
private readonly ILog log ;
private readonly CodexAccess codexAccess ;
public MarketplaceAccess ( ILog log , CodexAccess codexAccess )
{
this . log = log ;
this . codexAccess = codexAccess ;
}
2024-03-20 10:11:41 +00:00
public StoragePurchaseContract RequestStorage ( StoragePurchase purchase )
2023-09-20 06:45:55 +00:00
{
2024-03-20 10:11:41 +00:00
purchase . Log ( log ) ;
var request = purchase . ToApiRequest ( ) ;
2023-11-23 13:10:59 +00:00
2024-03-20 10:11:41 +00:00
var response = codexAccess . RequestStorage ( request , purchase . ContentId . Id ) ;
2023-09-20 06:45:55 +00:00
2023-11-23 13:10:59 +00:00
if ( response = = "Purchasing not available" | |
response = = "Expiry required" | |
2024-02-26 08:02:46 +00:00
response = = "Expiry needs to be in future" | |
response = = "Expiry has to be before the request's end (now + duration)" )
2023-09-20 06:45:55 +00:00
{
throw new InvalidOperationException ( response ) ;
}
Log ( $"Storage requested successfully. PurchaseId: '{response}'." ) ;
2024-03-20 10:11:41 +00:00
return new StoragePurchaseContract ( log , codexAccess , response , purchase ) ;
2023-09-20 06:45:55 +00:00
}
2024-03-20 10:11:41 +00:00
public string MakeStorageAvailable ( StorageAvailability availability )
2023-09-20 06:45:55 +00:00
{
2024-03-20 10:11:41 +00:00
availability . Log ( log ) ;
var request = availability . ToApiRequest ( ) ;
2023-09-20 06:45:55 +00:00
var response = codexAccess . SalesAvailability ( request ) ;
Log ( $"Storage successfully made available. Id: {response.id}" ) ;
return response . id ;
}
private void Log ( string msg )
{
log . Log ( $"{codexAccess.Container.Name} {msg}" ) ;
}
}
public class MarketplaceUnavailable : IMarketplaceAccess
{
2024-03-20 10:11:41 +00:00
public string MakeStorageAvailable ( StorageAvailability availability )
2023-11-23 13:10:59 +00:00
{
Unavailable ( ) ;
throw new NotImplementedException ( ) ;
}
2024-03-20 10:11:41 +00:00
public StoragePurchaseContract RequestStorage ( StoragePurchase purchase )
2023-09-20 06:45:55 +00:00
{
Unavailable ( ) ;
2024-03-20 10:11:41 +00:00
throw new NotImplementedException ( ) ;
2023-09-20 06:45:55 +00:00
}
private void Unavailable ( )
{
2023-09-20 08:51:47 +00:00
FrameworkAssert . Fail ( "Incorrect test setup: Marketplace was not enabled for this group of Codex nodes. Add 'EnableMarketplace(...)' after 'SetupCodexNodes()' to enable it." ) ;
2023-09-20 06:45:55 +00:00
throw new InvalidOperationException ( ) ;
}
}
public class StoragePurchaseContract
{
private readonly ILog log ;
private readonly CodexAccess codexAccess ;
2024-03-20 12:36:06 +00:00
private readonly TimeSpan gracePeriod = TimeSpan . FromSeconds ( 10 ) ;
2023-09-20 06:45:55 +00:00
private DateTime ? contractStartUtc ;
2024-03-20 10:11:41 +00:00
public StoragePurchaseContract ( ILog log , CodexAccess codexAccess , string purchaseId , StoragePurchase purchase )
2023-09-20 06:45:55 +00:00
{
this . log = log ;
this . codexAccess = codexAccess ;
PurchaseId = purchaseId ;
2024-03-20 10:11:41 +00:00
Purchase = purchase ;
2023-09-20 06:45:55 +00:00
}
public string PurchaseId { get ; }
2024-03-20 10:11:41 +00:00
public StoragePurchase Purchase { get ; }
2023-09-20 06:45:55 +00:00
public void WaitForStorageContractStarted ( )
{
2024-03-20 12:36:06 +00:00
var timeout = Purchase . Expiry + gracePeriod ;
WaitForStorageContractState ( timeout , "started" ) ;
contractStartUtc = DateTime . UtcNow ;
2023-09-20 06:45:55 +00:00
}
public void WaitForStorageContractFinished ( )
{
if ( ! contractStartUtc . HasValue )
{
WaitForStorageContractStarted ( ) ;
}
var currentContractTime = DateTime . UtcNow - contractStartUtc ! . Value ;
2024-03-20 10:11:41 +00:00
var timeout = ( Purchase . Duration - currentContractTime ) + gracePeriod ;
2023-09-20 06:45:55 +00:00
WaitForStorageContractState ( timeout , "finished" ) ;
}
2024-03-20 12:36:06 +00:00
public CodexStoragePurchase GetPurchaseStatus ( string purchaseId )
2023-09-20 06:45:55 +00:00
{
2024-03-20 12:36:06 +00:00
return codexAccess . GetPurchaseStatus ( purchaseId ) ;
2023-09-20 06:45:55 +00:00
}
private void WaitForStorageContractState ( TimeSpan timeout , string desiredState )
{
var lastState = "" ;
var waitStart = DateTime . UtcNow ;
log . Log ( $"Waiting for {Time.FormatDuration(timeout)} for contract '{PurchaseId}' to reach state '{desiredState}'." ) ;
while ( lastState ! = desiredState )
{
var purchaseStatus = codexAccess . GetPurchaseStatus ( PurchaseId ) ;
var statusJson = JsonConvert . SerializeObject ( purchaseStatus ) ;
if ( purchaseStatus ! = null & & purchaseStatus . state ! = lastState )
{
lastState = purchaseStatus . state ;
log . Debug ( "Purchase status: " + statusJson ) ;
}
Thread . Sleep ( 1000 ) ;
if ( lastState = = "errored" )
{
2023-09-20 08:51:47 +00:00
FrameworkAssert . Fail ( "Contract errored: " + statusJson ) ;
2023-09-20 06:45:55 +00:00
}
if ( DateTime . UtcNow - waitStart > timeout )
{
2023-10-17 11:52:04 +00:00
FrameworkAssert . Fail ( $"Contract did not reach '{desiredState}' within {Time.FormatDuration(timeout)} timeout. {statusJson}" ) ;
2023-09-20 06:45:55 +00:00
}
}
log . Log ( $"Contract '{desiredState}'." ) ;
}
}
}