cs-codex-dist-tests/ProjectPlugins/CodexPlugin/CodexAccess.cs

167 lines
5.3 KiB
C#
Raw Normal View History

2024-03-25 14:46:45 +00:00
using CodexOpenApi;
using Core;
using KubernetesWorkflow;
using KubernetesWorkflow.Types;
2024-04-02 12:53:45 +00:00
using Newtonsoft.Json;
using Utils;
2023-04-12 11:53:55 +00:00
namespace CodexPlugin
2023-04-12 11:53:55 +00:00
{
2023-08-15 09:01:18 +00:00
public class CodexAccess : ILogHandler
2023-04-12 11:53:55 +00:00
{
2023-09-12 08:31:55 +00:00
private readonly IPluginTools tools;
2024-03-26 07:58:16 +00:00
private readonly Mapper mapper = new Mapper();
2023-08-15 09:01:18 +00:00
private bool hasContainerCrashed;
2023-04-30 08:08:32 +00:00
2024-04-13 14:09:17 +00:00
public CodexAccess(IPluginTools tools, RunningPod container, CrashWatcher crashWatcher)
2023-04-12 11:53:55 +00:00
{
2023-09-12 08:31:55 +00:00
this.tools = tools;
2023-06-29 14:07:49 +00:00
Container = container;
2023-09-20 10:55:09 +00:00
CrashWatcher = crashWatcher;
2023-08-15 09:01:18 +00:00
hasContainerCrashed = false;
2023-09-20 10:55:09 +00:00
CrashWatcher.Start(this);
}
2024-04-13 14:09:17 +00:00
public RunningPod Container { get; }
2023-09-20 10:55:09 +00:00
public CrashWatcher CrashWatcher { get; }
2023-05-11 10:44:53 +00:00
2024-03-26 07:58:16 +00:00
public DebugInfo GetDebugInfo()
{
2024-03-26 14:12:28 +00:00
return mapper.Map(OnCodex(api => api.GetDebugInfoAsync()));
2023-06-29 14:07:49 +00:00
}
2024-03-26 09:31:49 +00:00
public DebugPeer GetDebugPeer(string peerId)
2023-06-29 14:07:49 +00:00
{
2024-03-26 09:31:49 +00:00
// Cannot use openAPI: debug/peer endpoint is not specified there.
2024-03-26 10:39:59 +00:00
var endpoint = GetEndpoint();
var str = endpoint.HttpGetString($"debug/peer/{peerId}");
2023-06-29 14:07:49 +00:00
if (str.ToLowerInvariant() == "unable to find peer!")
{
2024-03-26 09:31:49 +00:00
return new DebugPeer
2023-06-29 14:07:49 +00:00
{
IsPeerFound = false
};
}
2023-06-29 14:07:49 +00:00
2024-03-26 10:39:59 +00:00
var result = endpoint.Deserialize<DebugPeer>(str);
2023-06-29 14:07:49 +00:00
result.IsPeerFound = true;
return result;
}
2024-03-26 11:14:02 +00:00
public void ConnectToPeer(string peerId, string[] peerMultiAddresses)
{
OnCodex(api =>
{
Time.Wait(api.ConnectPeerAsync(peerId, peerMultiAddresses));
return Task.FromResult(string.Empty);
});
}
2023-06-29 14:07:49 +00:00
public string UploadFile(FileStream fileStream)
{
2024-03-26 10:39:59 +00:00
return OnCodex(api => api.UploadAsync(fileStream));
2023-06-29 14:07:49 +00:00
}
public Stream DownloadFile(string contentId)
{
2024-03-26 10:39:59 +00:00
var fileResponse = OnCodex(api => api.DownloadNetworkAsync(contentId));
if (fileResponse.StatusCode != 200) throw new Exception("Download failed with StatusCode: " + fileResponse.StatusCode);
return fileResponse.Stream;
2023-11-10 07:20:08 +00:00
}
2024-03-26 13:07:06 +00:00
public LocalDatasetList LocalFiles()
2023-11-10 07:20:08 +00:00
{
2024-03-26 14:12:28 +00:00
return mapper.Map(OnCodex(api => api.ListDataAsync()));
2023-06-29 14:07:49 +00:00
}
2024-03-26 10:39:59 +00:00
public StorageAvailability SalesAvailability(StorageAvailability request)
2023-06-29 14:07:49 +00:00
{
2024-03-26 14:12:28 +00:00
var body = mapper.Map(request);
2024-03-26 10:39:59 +00:00
var read = OnCodex<SalesAvailabilityREAD>(api => api.OfferStorageAsync(body));
2024-03-26 14:12:28 +00:00
return mapper.Map(read);
2023-06-29 14:07:49 +00:00
}
2024-03-26 10:39:59 +00:00
public string RequestStorage(StoragePurchaseRequest request)
2023-06-29 14:07:49 +00:00
{
2024-03-26 14:12:28 +00:00
var body = mapper.Map(request);
2024-03-26 13:07:06 +00:00
return OnCodex<string>(api => api.CreateStorageRequestAsync(request.ContentId.Id, body));
2023-06-29 14:07:49 +00:00
}
2024-03-26 11:23:38 +00:00
public StoragePurchase GetPurchaseStatus(string purchaseId)
2023-06-29 14:07:49 +00:00
{
2024-04-02 12:53:45 +00:00
var endpoint = GetEndpoint();
return Time.Retry(() =>
{
var str = endpoint.HttpGetString($"storage/purchases/{purchaseId}");
if (string.IsNullOrEmpty(str)) throw new Exception("Empty response.");
return JsonConvert.DeserializeObject<StoragePurchase>(str)!;
}, nameof(GetPurchaseStatus));
// TODO: current getpurchase api does not line up with its openapi spec.
// return mapper.Map(OnCodex(api => api.GetPurchaseAsync(purchaseId)));
2023-06-29 14:07:49 +00:00
}
public string GetName()
{
return Container.Name;
}
public PodInfo GetPodInfo()
{
var workflow = tools.CreateWorkflow();
return workflow.GetPodInfo(Container);
}
2024-03-25 14:46:45 +00:00
private T OnCodex<T>(Func<CodexApi, Task<T>> action)
2023-06-29 14:07:49 +00:00
{
var address = GetAddress();
2024-03-26 09:31:49 +00:00
var result = tools.CreateHttp(CheckContainerCrashed)
.OnClient(client =>
2024-03-25 14:46:45 +00:00
{
var api = new CodexApi(client);
api.BaseUrl = $"{address.Host}:{address.Port}/api/codex/v1";
return Time.Wait(action(api));
});
return result;
}
2024-03-26 09:31:49 +00:00
private IEndpoint GetEndpoint()
{
return tools
.CreateHttp(CheckContainerCrashed)
.CreateEndpoint(GetAddress(), "/api/codex/v1/", Container.Name);
}
private Address GetAddress()
{
2024-04-13 14:09:17 +00:00
return Container.Containers.Single().GetAddress(tools.GetLog(), CodexContainerRecipe.ApiPortTag);
}
private void CheckContainerCrashed(HttpClient client)
2023-08-15 09:01:18 +00:00
{
2024-06-03 09:36:48 +00:00
if (hasContainerCrashed) throw new Exception($"Container {GetName()} has crashed.");
2023-08-15 09:01:18 +00:00
}
public void Log(Stream crashLog)
{
2023-09-12 08:31:55 +00:00
var log = tools.GetLog();
2023-08-15 09:01:18 +00:00
var file = log.CreateSubfile();
log.Log($"Container {Container.Name} has crashed. Downloading crash log to '{file.FullFilename}'...");
file.Write($"Container Crash Log for {Container.Name}.");
2023-08-15 09:01:18 +00:00
using var reader = new StreamReader(crashLog);
var line = reader.ReadLine();
while (line != null)
{
file.Write(line);
line = reader.ReadLine();
}
log.Log("Crash log successfully downloaded.");
hasContainerCrashed = true;
}
}
2023-04-12 11:53:55 +00:00
}