Speeding up visible location call
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 57s
Deploy Promiscuity Inventory API / deploy (push) Successful in 59s
Deploy Promiscuity Locations API / deploy (push) Successful in 58s
k8s smoke test / test (push) Successful in 8s
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 57s
Deploy Promiscuity Inventory API / deploy (push) Successful in 59s
Deploy Promiscuity Locations API / deploy (push) Successful in 58s
k8s smoke test / test (push) Successful in 8s
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
namespace CharacterApi.Models;
|
||||
|
||||
public class FloorInventoryItemResponse
|
||||
{
|
||||
public string ItemId { get; set; } = string.Empty;
|
||||
|
||||
public string ItemKey { get; set; } = string.Empty;
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public int? Slot { get; set; }
|
||||
}
|
||||
@@ -21,4 +21,7 @@ public class VisibleLocation
|
||||
|
||||
[BsonElement("locationObject")]
|
||||
public VisibleLocationObject? LocationObject { get; set; }
|
||||
|
||||
[BsonElement("floorItems")]
|
||||
public List<FloorInventoryItemResponse> FloorItems { get; set; } = [];
|
||||
}
|
||||
|
||||
@@ -17,6 +17,37 @@ public class InventoryController : ControllerBase
|
||||
_inventory = inventory;
|
||||
}
|
||||
|
||||
[HttpPost("internal/by-owner/{ownerType}")]
|
||||
public async Task<IActionResult> GetByOwnersInternal(string ownerType, [FromBody] InternalOwnerInventoryBatchRequest req)
|
||||
{
|
||||
var configuredKey = (HttpContext.RequestServices.GetRequiredService<IConfiguration>()["InternalApi:Key"]
|
||||
?? HttpContext.RequestServices.GetRequiredService<IConfiguration>()["Jwt:Key"]
|
||||
?? string.Empty).Trim();
|
||||
var requestKey = (Request.Headers["X-Internal-Api-Key"].FirstOrDefault() ?? string.Empty).Trim();
|
||||
if (string.IsNullOrWhiteSpace(configuredKey) || !string.Equals(configuredKey, requestKey, StringComparison.Ordinal))
|
||||
return Unauthorized();
|
||||
|
||||
var normalizedOwnerType = ownerType.Trim().ToLowerInvariant();
|
||||
if (normalizedOwnerType is not ("character" or "location"))
|
||||
return BadRequest("Unsupported ownerType");
|
||||
|
||||
var groupedItems = await _inventory.GetByOwnersAsync(normalizedOwnerType, req.OwnerIds);
|
||||
var ownerIds = req.OwnerIds
|
||||
.Where(id => !string.IsNullOrWhiteSpace(id))
|
||||
.Select(id => id.Trim())
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var response = ownerIds.Select(ownerId => new OwnerInventorySummaryResponse
|
||||
{
|
||||
OwnerType = normalizedOwnerType,
|
||||
OwnerId = ownerId,
|
||||
Items = groupedItems.GetValueOrDefault(ownerId, []).Select(InventoryItemResponse.FromModel).ToList()
|
||||
}).ToList();
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet("item-definitions")]
|
||||
[Authorize(Roles = "USER,SUPER")]
|
||||
public async Task<IActionResult> ListItemDefinitions()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace InventoryApi.Models;
|
||||
|
||||
public class InternalOwnerInventoryBatchRequest
|
||||
{
|
||||
public List<string> OwnerIds { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace InventoryApi.Models;
|
||||
|
||||
public class OwnerInventorySummaryResponse
|
||||
{
|
||||
public string OwnerType { get; set; } = string.Empty;
|
||||
|
||||
public string OwnerId { get; set; } = string.Empty;
|
||||
|
||||
public List<InventoryItemResponse> Items { get; set; } = [];
|
||||
}
|
||||
@@ -88,6 +88,32 @@ public class InventoryStore
|
||||
.ThenBy(i => i.ItemKey)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<Dictionary<string, List<InventoryItem>>> GetByOwnersAsync(string ownerType, IEnumerable<string> ownerIds)
|
||||
{
|
||||
var normalizedOwnerType = NormalizeOwnerType(ownerType);
|
||||
if (normalizedOwnerType is null)
|
||||
return [];
|
||||
|
||||
var ids = ownerIds
|
||||
.Where(id => !string.IsNullOrWhiteSpace(id))
|
||||
.Select(id => id.Trim())
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
if (ids.Count == 0)
|
||||
return [];
|
||||
|
||||
var items = await _items.Find(i => i.OwnerType == normalizedOwnerType && ids.Contains(i.OwnerId))
|
||||
.SortBy(i => i.OwnerId)
|
||||
.ThenBy(i => i.EquippedSlot)
|
||||
.ThenBy(i => i.Slot)
|
||||
.ThenBy(i => i.ItemKey)
|
||||
.ToListAsync();
|
||||
|
||||
return items
|
||||
.GroupBy(item => item.OwnerId, StringComparer.Ordinal)
|
||||
.ToDictionary(group => group.Key, group => group.ToList(), StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
public Task<List<ItemDefinition>> ListItemDefinitionsAsync() =>
|
||||
_definitions.Find(Builders<ItemDefinition>.Filter.Empty).SortBy(d => d.ItemKey).ToListAsync();
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"InternalApi": {
|
||||
"Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:5003" } } },
|
||||
"MongoDB": { "ConnectionString": "mongodb://192.168.86.50:27017", "DatabaseName": "promiscuity" },
|
||||
"InternalApi": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!" },
|
||||
"Jwt": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!", "Issuer": "promiscuity", "Audience": "promiscuity-auth-api" },
|
||||
"Logging": { "LogLevel": { "Default": "Information" } },
|
||||
"AllowedHosts": "*"
|
||||
|
||||
@@ -91,6 +91,7 @@ public class LocationsController : ControllerBase
|
||||
return BadRequest("radius must be non-negative");
|
||||
|
||||
var result = await _locations.GetOrCreateVisibleLocationsAsync(req.X, req.Y, req.Radius);
|
||||
await PopulateFloorInventoriesAsync(result);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
@@ -367,4 +368,54 @@ public class LocationsController : ControllerBase
|
||||
}
|
||||
|
||||
private static string NormalizeBiomeKey(string biomeKey) => biomeKey.Trim().ToLowerInvariant();
|
||||
|
||||
private async Task PopulateFloorInventoriesAsync(VisibleLocationWindowResponse result)
|
||||
{
|
||||
var locationIds = result.Locations
|
||||
.Where(location => !string.IsNullOrWhiteSpace(location.Id))
|
||||
.Select(location => location.Id!)
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
if (locationIds.Count == 0)
|
||||
return;
|
||||
|
||||
var inventoryBaseUrl = (_configuration["Services:InventoryApiBaseUrl"] ?? "http://localhost:5003").TrimEnd('/');
|
||||
var internalApiKey = (_configuration["InternalApi:Key"] ?? _configuration["Jwt:Key"] ?? string.Empty).Trim();
|
||||
var body = JsonSerializer.Serialize(new { ownerIds = locationIds });
|
||||
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, $"{inventoryBaseUrl}/api/inventory/internal/by-owner/location");
|
||||
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
|
||||
request.Headers.Add("X-Internal-Api-Key", internalApiKey);
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Failed to load batched floor inventories from InventoryApi. Status={StatusCode} Body={Body}",
|
||||
(int)response.StatusCode,
|
||||
responseBody);
|
||||
return;
|
||||
}
|
||||
|
||||
var parsed = JsonSerializer.Deserialize<List<OwnerInventorySummaryEnvelope>>(
|
||||
responseBody,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? [];
|
||||
var byOwnerId = parsed.ToDictionary(entry => entry.OwnerId, entry => entry.Items, StringComparer.Ordinal);
|
||||
|
||||
foreach (var location in result.Locations)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(location.Id))
|
||||
continue;
|
||||
location.FloorItems = byOwnerId.GetValueOrDefault(location.Id!, []);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class OwnerInventorySummaryEnvelope
|
||||
{
|
||||
public string OwnerId { get; set; } = string.Empty;
|
||||
|
||||
public List<FloorInventoryItemResponse> Items { get; set; } = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace LocationsApi.Models;
|
||||
|
||||
public class FloorInventoryItemResponse
|
||||
{
|
||||
public string ItemId { get; set; } = string.Empty;
|
||||
|
||||
public string ItemKey { get; set; } = string.Empty;
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public int? Slot { get; set; }
|
||||
}
|
||||
@@ -11,4 +11,6 @@ public class VisibleLocationResponse
|
||||
public string BiomeKey { get; set; } = "plains";
|
||||
|
||||
public VisibleLocationObjectResponse? LocationObject { get; set; }
|
||||
|
||||
public List<FloorInventoryItemResponse> FloorItems { get; set; } = [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user