109 lines
4.2 KiB
C#
109 lines
4.2 KiB
C#
using System.Text.Json;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Options;
|
|
using MiGu.Server.Auth;
|
|
using MiGu.Server.Launcher;
|
|
|
|
namespace MiGu.Server.Controllers;
|
|
|
|
/// <summary>
|
|
/// 读取 SimpleLite 地图固定目录下的 JSON 原文,供平台「地图管理」右侧预览。
|
|
/// 先向 SimpleLite 拉取 maps 列表拿到 directory,再读本机同路径文件(与 SimpleLite 同机部署)。
|
|
/// </summary>
|
|
[ApiController]
|
|
[Authorize]
|
|
[Route("api/maps")]
|
|
public class MapsContentController : ControllerBase
|
|
{
|
|
private readonly IHttpClientFactory _httpFactory;
|
|
private readonly InternalTokenStore _internalToken;
|
|
private readonly SimpleLiteOptions _sl;
|
|
private readonly ILogger<MapsContentController> _log;
|
|
|
|
public MapsContentController(
|
|
IHttpClientFactory httpFactory,
|
|
InternalTokenStore internalToken,
|
|
IOptions<SimpleLiteOptions> sl,
|
|
ILogger<MapsContentController> log)
|
|
{
|
|
_httpFactory = httpFactory;
|
|
_internalToken = internalToken;
|
|
_sl = sl.Value;
|
|
_log = log;
|
|
}
|
|
|
|
[HttpGet("{name}/content")]
|
|
public async Task<IActionResult> GetContent(string name, CancellationToken ct)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(name)
|
|
|| name.Contains("..", StringComparison.Ordinal)
|
|
|| name.IndexOfAny(['/', '\\', ':', '*', '?', '"', '<', '>', '|']) >= 0)
|
|
{
|
|
return BadRequest(new { message = "地图名称非法" });
|
|
}
|
|
|
|
try
|
|
{
|
|
var directory = await FetchMapsDirectoryAsync(ct);
|
|
if (string.IsNullOrWhiteSpace(directory))
|
|
return StatusCode(503, new { message = "无法从 SimpleLite 获取地图目录" });
|
|
|
|
var fileName = name.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ? name : $"{name}.json";
|
|
var fullPath = Path.GetFullPath(Path.Combine(directory, fileName));
|
|
var root = Path.GetFullPath(directory);
|
|
if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
|
|
return BadRequest(new { message = "路径校验失败" });
|
|
|
|
if (!System.IO.File.Exists(fullPath))
|
|
return NotFound(new { message = $"地图文件不存在:{fileName}" });
|
|
|
|
var content = await System.IO.File.ReadAllTextAsync(fullPath, ct);
|
|
return Ok(new
|
|
{
|
|
name,
|
|
fileName,
|
|
path = fullPath,
|
|
content
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_log.LogWarning(ex, "读取地图 JSON 失败 name={Name}", name);
|
|
return StatusCode(500, new { message = $"读取地图 JSON 失败:{ex.Message}" });
|
|
}
|
|
}
|
|
|
|
private async Task<string?> FetchMapsDirectoryAsync(CancellationToken ct)
|
|
{
|
|
var client = _httpFactory.CreateClient();
|
|
client.Timeout = TimeSpan.FromSeconds(8);
|
|
var url = $"http://127.0.0.1:{_sl.ProjectionPort}/projection/map-edit/maps";
|
|
using var msg = new HttpRequestMessage(HttpMethod.Get, url);
|
|
if (!string.IsNullOrEmpty(_internalToken.Token))
|
|
msg.Headers.TryAddWithoutValidation("X-Platform-Internal-Token", _internalToken.Token);
|
|
|
|
using var resp = await client.SendAsync(msg, ct);
|
|
var body = await resp.Content.ReadAsStringAsync(ct);
|
|
if (!resp.IsSuccessStatusCode)
|
|
throw new InvalidOperationException($"SimpleLite maps 列表返回 {(int)resp.StatusCode}");
|
|
|
|
using var doc = JsonDocument.Parse(body);
|
|
var root = doc.RootElement;
|
|
if (root.TryGetProperty("success", out var ok) && ok.ValueKind == JsonValueKind.False)
|
|
{
|
|
var message = root.TryGetProperty("message", out var m) ? m.GetString() : "maps 列表失败";
|
|
throw new InvalidOperationException(message ?? "maps 列表失败");
|
|
}
|
|
|
|
JsonElement data = root;
|
|
if (root.TryGetProperty("data", out var d) && d.ValueKind == JsonValueKind.Object)
|
|
data = d;
|
|
|
|
if (data.TryGetProperty("directory", out var dir) && dir.ValueKind == JsonValueKind.String)
|
|
return dir.GetString();
|
|
|
|
return null;
|
|
}
|
|
}
|