using System.Runtime.CompilerServices;
using System.Text.Json;
using AIStudio.Tools.Rust;
namespace AIStudio.Tools.Services;
public partial class RustService
{
/// Starts a Rust media normalization job.
/// Absolute source path.
/// Absolute operation-owned output path.
/// Request cancellation token.
/// The opaque runtime job identifier.
public async Task StartMediaJobAsync(string inputPath, string outputPath, CancellationToken token = default)
{
using var response = await this.http.PostAsJsonAsync(
"/media/jobs",
new CreateMediaJobRequest(inputPath, outputPath),
this.jsonRustSerializerOptions,
token);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync(this.jsonRustSerializerOptions, token);
return result?.JobId ?? throw new InvalidOperationException("The Rust runtime did not return a media job ID.");
}
/// Streams replayed and live snapshots until the media job becomes terminal.
/// Runtime job identifier.
/// Stream cancellation token.
/// Asynchronous media job snapshots.
public async IAsyncEnumerable StreamMediaJobEventsAsync(string jobId, [EnumeratorCancellation] CancellationToken token = default)
{
using var request = new HttpRequestMessage(HttpMethod.Get, $"/media/jobs/{Uri.EscapeDataString(jobId)}/events");
using var response = await this.http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync(token);
using var reader = new StreamReader(stream);
while (!token.IsCancellationRequested)
{
var line = await reader.ReadLineAsync(token);
if (line is null)
yield break;
if (!line.StartsWith("data:", StringComparison.Ordinal))
continue;
var json = line["data:".Length..].Trim();
var mediaEvent = JsonSerializer.Deserialize(json, this.jsonRustSerializerOptions);
if (mediaEvent is not null)
yield return mediaEvent;
if (mediaEvent?.Phase is MediaJobPhase.COMPLETED or MediaJobPhase.FAILED or MediaJobPhase.CANCELLED)
yield break;
}
}
/// Requests cooperative cancellation of a Rust media job.
/// Runtime job identifier.
/// Request cancellation token.
public async Task CancelMediaJobAsync(string jobId, CancellationToken token = default)
{
using var response = await this.http.DeleteAsync($"/media/jobs/{Uri.EscapeDataString(jobId)}", token);
if (response is { IsSuccessStatusCode: false, StatusCode: not System.Net.HttpStatusCode.NotFound })
response.EnsureSuccessStatusCode();
}
}