279 lines
8.3 KiB
C#
279 lines
8.3 KiB
C#
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using Microsoft.Extensions.Logging;
|
|
using ZeroSpace.Model;
|
|
|
|
namespace ZeroSpace.Web.Services;
|
|
|
|
public class UnitsApiClient : IUnitsApiClient
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly ILogger<UnitsApiClient> _logger;
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
};
|
|
|
|
private const string AllUnitFields = @"
|
|
id
|
|
name
|
|
hexite
|
|
flux
|
|
supply
|
|
productionTime
|
|
health
|
|
energy
|
|
shields
|
|
armorRating
|
|
movementSpeed
|
|
damagePerSecond
|
|
attackRange
|
|
attributes
|
|
tier
|
|
faction
|
|
hotkey
|
|
buildAtSameTime
|
|
limit";
|
|
|
|
public UnitsApiClient(HttpClient httpClient, ILogger<UnitsApiClient> logger)
|
|
{
|
|
_httpClient = httpClient;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<UnitData>> GetUnitsAsync(string? faction = null, int? tier = null, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
Dictionary<string, object?>? whereFilter = null;
|
|
if (!string.IsNullOrWhiteSpace(faction) || tier.HasValue)
|
|
{
|
|
whereFilter = new Dictionary<string, object?>();
|
|
if (!string.IsNullOrWhiteSpace(faction))
|
|
{
|
|
whereFilter["faction"] = new Dictionary<string, object?> { ["eq"] = faction };
|
|
}
|
|
if (tier.HasValue)
|
|
{
|
|
whereFilter["tier"] = new Dictionary<string, object?> { ["eq"] = tier.Value };
|
|
}
|
|
}
|
|
|
|
var query = $@"
|
|
query GetUnits($where: UnitDataFilterInput) {{
|
|
units(where: $where) {{
|
|
{AllUnitFields}
|
|
}}
|
|
}}";
|
|
|
|
var requestBody = new
|
|
{
|
|
query,
|
|
variables = new
|
|
{
|
|
where = whereFilter
|
|
}
|
|
};
|
|
|
|
var response = await _httpClient.PostAsJsonAsync("graphql", requestBody, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<UnitsQueryResult>>(JsonOptions, cancellationToken);
|
|
if (result?.Data?.Units is not null && result.Data.Units.Count > 0)
|
|
{
|
|
return result.Data.Units;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to load units via GraphQL API service. Falling back to static units list.");
|
|
}
|
|
|
|
// Fallback to static model data if GraphQL call fails
|
|
var fallback = Units.All.AsEnumerable();
|
|
if (!string.IsNullOrWhiteSpace(faction))
|
|
{
|
|
fallback = fallback.Where(u => u.Faction.Equals(faction, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
if (tier.HasValue)
|
|
{
|
|
fallback = fallback.Where(u => u.Tier == tier.Value);
|
|
}
|
|
|
|
return fallback.ToList();
|
|
}
|
|
|
|
public async Task<UnitData?> GetUnitByIdAsync(string id, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var query = $@"
|
|
query GetUnitById($id: String!) {{
|
|
unitById(id: $id) {{
|
|
{AllUnitFields}
|
|
}}
|
|
}}";
|
|
|
|
var requestBody = new
|
|
{
|
|
query,
|
|
variables = new
|
|
{
|
|
id
|
|
}
|
|
};
|
|
|
|
var response = await _httpClient.PostAsJsonAsync("graphql", requestBody, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<UnitByIdQueryResult>>(JsonOptions, cancellationToken);
|
|
if (result?.Data?.UnitById is not null)
|
|
{
|
|
return result.Data.UnitById;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to get unit '{Id}' via GraphQL API.", id);
|
|
}
|
|
|
|
return Units.All.FirstOrDefault(u => u.Id == id);
|
|
}
|
|
|
|
public async Task<UnitData?> CreateUnitAsync(UnitData unit, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var mutation = $@"
|
|
mutation CreateUnit($input: CreateUnitInput!) {{
|
|
createUnit(input: $input) {{
|
|
{AllUnitFields}
|
|
}}
|
|
}}";
|
|
|
|
var input = new
|
|
{
|
|
id = unit.Id,
|
|
name = unit.Name,
|
|
hexite = unit.Hexite,
|
|
flux = unit.Flux,
|
|
supply = unit.Supply,
|
|
productionTime = unit.ProductionTime,
|
|
health = unit.Health,
|
|
energy = unit.Energy,
|
|
shields = unit.Shields,
|
|
armorRating = unit.ArmorRating,
|
|
movementSpeed = unit.MovementSpeed,
|
|
damagePerSecond = unit.DamagePerSecond,
|
|
attackRange = unit.AttackRange,
|
|
attributes = unit.Attributes,
|
|
tier = unit.Tier,
|
|
faction = unit.Faction,
|
|
hotkey = unit.Hotkey,
|
|
buildAtSameTime = unit.BuildAtSameTime,
|
|
limit = unit.Limit
|
|
};
|
|
|
|
var requestBody = new
|
|
{
|
|
query = mutation,
|
|
variables = new
|
|
{
|
|
input
|
|
}
|
|
};
|
|
|
|
var response = await _httpClient.PostAsJsonAsync("graphql", requestBody, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<CreateUnitMutationResult>>(JsonOptions, cancellationToken);
|
|
return result?.Data?.CreateUnit;
|
|
}
|
|
|
|
_logger.LogError("Failed to create unit via GraphQL. Status: {StatusCode}", response.StatusCode);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating unit via GraphQL.");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<bool> DeleteUnitAsync(string id, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var mutation = @"
|
|
mutation DeleteUnit($id: String!) {
|
|
deleteUnit(id: $id)
|
|
}";
|
|
|
|
var requestBody = new
|
|
{
|
|
query = mutation,
|
|
variables = new
|
|
{
|
|
id
|
|
}
|
|
};
|
|
|
|
var response = await _httpClient.PostAsJsonAsync("graphql", requestBody, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<GraphQLResponse<DeleteUnitMutationResult>>(JsonOptions, cancellationToken);
|
|
return result?.Data?.DeleteUnit ?? false;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting unit '{Id}' via GraphQL.", id);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private sealed class GraphQLResponse<T>
|
|
{
|
|
[JsonPropertyName("data")]
|
|
public T? Data { get; set; }
|
|
|
|
[JsonPropertyName("errors")]
|
|
public List<GraphQLErrorItem>? Errors { get; set; }
|
|
}
|
|
|
|
private sealed class GraphQLErrorItem
|
|
{
|
|
[JsonPropertyName("message")]
|
|
public string Message { get; set; } = string.Empty;
|
|
}
|
|
|
|
private sealed class UnitsQueryResult
|
|
{
|
|
[JsonPropertyName("units")]
|
|
public List<UnitData>? Units { get; set; }
|
|
}
|
|
|
|
private sealed class UnitByIdQueryResult
|
|
{
|
|
[JsonPropertyName("unitById")]
|
|
public UnitData? UnitById { get; set; }
|
|
}
|
|
|
|
private sealed class CreateUnitMutationResult
|
|
{
|
|
[JsonPropertyName("createUnit")]
|
|
public UnitData? CreateUnit { get; set; }
|
|
}
|
|
|
|
private sealed class DeleteUnitMutationResult
|
|
{
|
|
[JsonPropertyName("deleteUnit")]
|
|
public bool DeleteUnit { get; set; }
|
|
}
|
|
}
|