Add seed-fetching service

This commit is contained in:
2025-02-26 15:58:45 -06:00
parent 387e00f160
commit b7230950b2
7 changed files with 123 additions and 27 deletions

View File

@@ -0,0 +1,57 @@
namespace ALttPRandomizer.Azure {
using global::Azure.Storage.Blobs;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
public class AzureStorage {
public AzureStorage(BlobContainerClient blobClient, ILogger<AzureStorage> logger) {
this.BlobClient = blobClient;
this.Logger = logger;
}
private ILogger<AzureStorage> Logger { get; }
private BlobContainerClient BlobClient { get; }
public async Task UploadFile(string name, Stream data) {
await BlobClient.UploadBlobAsync(name, data);
}
public async Task UploadFileAndDelete(string name, string filepath) {
using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) {
this.Logger.LogDebug("Uploading file {filepath} -> {name}", filepath, name);
await this.UploadFile(name, stream);
}
this.Logger.LogDebug("Deleting file {filepath}", filepath);
File.Delete(filepath);
}
public async Task<Dictionary<string, BinaryData>> GetFiles(string seedId) {
var prefix = seedId + "/";
var blobs = this.BlobClient.GetBlobsAsync(prefix: prefix);
var data = new Dictionary<string, BinaryData>();
await foreach (var blob in blobs) {
var result = await this.BlobClient.GetBlobClient(blob.Name).DownloadContentAsync();
if (result.Value.Details.ContentLength == 0) {
continue;
}
if (!blob.Name.StartsWith(prefix)) {
this.Logger.LogWarning("Found prefix mismatch for seed id {seedId}, blob name {blobName}", seedId, blob.Name);
continue;
}
var suffix = blob.Name.Substring(prefix.Length);
data[suffix] = result.Value.Content;
}
return data;
}
}
}

View File

@@ -1,19 +1,30 @@
namespace ALttPRandomizer { namespace ALttPRandomizer {
using ALttPRandomizer.Model; using ALttPRandomizer.Model;
using ALttPRandomizer.Service;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
public class GenerateController : Controller { public class GenerateController : Controller {
public GenerateController(Randomizer randomizer) { public GenerateController(Randomizer randomizer, SeedService seedService) {
this.Randomizer = randomizer; this.Randomizer = randomizer;
this.SeedService = seedService;
} }
private Randomizer Randomizer { get; } private Randomizer Randomizer { get; }
private SeedService SeedService { get; }
[Route("/generate")] [Route("/generate")]
[HttpPost] [HttpPost]
public ActionResult Generate(SeedSettings settings) { public ActionResult Generate(SeedSettings settings) {
var result = this.Randomizer.Randomize(); var result = this.Randomizer.Randomize();
return Content(result); return Ok(result);
}
[Route("/seed/{id}")]
[HttpGet]
public async Task<ActionResult> GetSeed(string id) {
var result = await this.SeedService.GetSeed(id);
return Ok(result);
} }
} }
} }

View File

@@ -4,7 +4,7 @@
public class IdGenerator { public class IdGenerator {
private const string chars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; private const string chars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
private const int length = 10; private const int length = 10;
private static Random random = new Random(); private static readonly Random random = new Random();
public string GenerateId() { public string GenerateId() {
var str = new char[length]; var str = new char[length];

View File

@@ -1,9 +1,11 @@
namespace ALttPRandomizer namespace ALttPRandomizer
{ {
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using ALttPRandomizer.Azure;
using ALttPRandomizer.Options; using ALttPRandomizer.Options;
using Azure.Identity; using ALttPRandomizer.Service;
using Azure.Storage.Blobs; using global::Azure.Identity;
using global::Azure.Storage.Blobs;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@@ -36,8 +38,10 @@
var seedClient = new BlobContainerClient(settings.AzureSettings.BlobstoreEndpoint, token); var seedClient = new BlobContainerClient(settings.AzureSettings.BlobstoreEndpoint, token);
builder.Services.AddSingleton(seedClient); builder.Services.AddSingleton(seedClient);
builder.Services.AddScoped<Randomizer, Randomizer>(); builder.Services.AddSingleton<AzureStorage>();
builder.Services.AddScoped<IdGenerator, IdGenerator>(); builder.Services.AddScoped<Randomizer>();
builder.Services.AddScoped<SeedService>();
builder.Services.AddScoped<IdGenerator>();
var app = builder.Build(); var app = builder.Build();

View File

@@ -0,0 +1,9 @@
{
"profiles": {
"https": {
"applicationUrl": "localhost:5000/swagger",
"commandName": "Project",
"launchBrowser": true
}
}
}

View File

@@ -1,26 +1,25 @@
namespace ALttPRandomizer { namespace ALttPRandomizer {
using ALttPRandomizer.Azure;
using ALttPRandomizer.Options; using ALttPRandomizer.Options;
using Azure.Storage.Blobs;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
public class Randomizer { public class Randomizer {
public Randomizer( public Randomizer(
IdGenerator idGenerator, IdGenerator idGenerator,
BlobContainerClient seedClient, AzureStorage azureStorage,
IOptionsMonitor<ServiceOptions> optionsMonitor, IOptionsMonitor<ServiceOptions> optionsMonitor,
ILogger<Randomizer> logger) { ILogger<Randomizer> logger) {
this.IdGenerator = idGenerator; this.IdGenerator = idGenerator;
this.SeedClient = seedClient; this.AzureStorage = azureStorage;
this.OptionsMonitor = optionsMonitor; this.OptionsMonitor = optionsMonitor;
this.Logger = logger; this.Logger = logger;
} }
private BlobContainerClient SeedClient { get; } private AzureStorage AzureStorage { get; }
private IOptionsMonitor<ServiceOptions> OptionsMonitor { get; } private IOptionsMonitor<ServiceOptions> OptionsMonitor { get; }
private IdGenerator IdGenerator { get; } private IdGenerator IdGenerator { get; }
private ILogger<Randomizer> Logger { get; } private ILogger<Randomizer> Logger { get; }
@@ -81,26 +80,17 @@
var spoilerIn = Path.Join(Path.GetTempPath(), string.Format("DR_{0}_Spoiler.txt", id)); var spoilerIn = Path.Join(Path.GetTempPath(), string.Format("DR_{0}_Spoiler.txt", id));
var spoilerOut = string.Format("{0}/spoiler.txt", id); var spoilerOut = string.Format("{0}/spoiler.txt", id);
var uploadPatch = UploadFile(bpsOut, bpsIn); var uploadPatch = this.AzureStorage.UploadFileAndDelete(bpsOut, bpsIn);
var uploadSpoiler = UploadFile(spoilerOut, spoilerIn); var uploadSpoiler = this.AzureStorage.UploadFileAndDelete(spoilerOut, spoilerIn);
await Task.WhenAll(uploadPatch, uploadSpoiler); await Task.WhenAll(uploadPatch, uploadSpoiler);
this.Logger.LogDebug("Deleting file {filepath}", rom);
File.Delete(rom); File.Delete(rom);
this.Logger.LogDebug("Finished uploading seed id {id}", id); this.Logger.LogDebug("Finished uploading seed id {id}", id);
} }
private async Task UploadFile(string name, string filepath) {
using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read)) {
this.Logger.LogDebug("Uploading file {filepath} -> {name}", filepath, name);
await this.SeedClient.UploadBlobAsync(name, stream);
}
this.Logger.LogDebug("Deleting file {filepath}", filepath);
File.Delete(filepath);
}
private void GenerationFailed(string id, int exitcode) { private void GenerationFailed(string id, int exitcode) {
} }
} }

View File

@@ -0,0 +1,25 @@
namespace ALttPRandomizer.Service {
using ALttPRandomizer.Azure;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class SeedService {
public SeedService(AzureStorage azureStorage) {
this.AzureStorage = azureStorage;
}
private AzureStorage AzureStorage { get; }
public async Task<IDictionary<string, string>> GetSeed(string seedId) {
var files = await this.AzureStorage.GetFiles(seedId);
var result = new Dictionary<string, string>();
foreach (var file in files) {
result[file.Key] = Convert.ToBase64String(file.Value.ToMemory().ToArray());
}
return result;
}
}
}