新增 OTA WatchDog 编排与车队健康/报警后端。
覆盖包库回传、任务下发、CDM 任务同步与报警采集,并为包/任务 ID 与上传文件名加上路径安全校验。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+59
-5
@@ -7,6 +7,7 @@ using MiGu.Server.Auth;
|
||||
using MiGu.Server.Configs;
|
||||
using MiGu.Server.Launcher;
|
||||
using MiGu.Server.OpenApi;
|
||||
using MiGu.Server.Ota;
|
||||
using MiGu.Server.Persistence;
|
||||
using Yarp.ReverseProxy.Transforms;
|
||||
|
||||
@@ -31,12 +32,27 @@ var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
||||
ContentRootPath = FindSourceContentRoot(AppContext.BaseDirectory) ?? AppContext.BaseDirectory
|
||||
});
|
||||
|
||||
if (string.IsNullOrWhiteSpace(builder.Configuration["urls"])
|
||||
&& string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ASPNETCORE_URLS"))
|
||||
&& string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("DOTNET_URLS")))
|
||||
// 管理面默认 :8080;WatchDog 拉包回传写死 :8000/upload-mdcs/*,必须额外监听 ReceivePort。
|
||||
{
|
||||
// 直接运行 MiGu.Server.exe 不读取 launchSettings.json;保持与 dotnet run / 文档一致默认监听 8080。
|
||||
builder.WebHost.UseUrls("http://0.0.0.0:8080");
|
||||
var receivePort = builder.Configuration.GetValue("Ota:ReceivePort", 8000);
|
||||
var urls = builder.Configuration["urls"]
|
||||
?? Environment.GetEnvironmentVariable("ASPNETCORE_URLS")
|
||||
?? Environment.GetEnvironmentVariable("DOTNET_URLS");
|
||||
if (string.IsNullOrWhiteSpace(urls))
|
||||
urls = "http://0.0.0.0:8080";
|
||||
|
||||
var parts = urls.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
var hasReceive = parts.Any(u =>
|
||||
u.Contains($":{receivePort}", StringComparison.OrdinalIgnoreCase)
|
||||
|| u.EndsWith($":{receivePort}/", StringComparison.OrdinalIgnoreCase));
|
||||
if (!hasReceive)
|
||||
{
|
||||
urls = string.Join(';', parts.Append($"http://0.0.0.0:{receivePort}"));
|
||||
// 安全提示:该端口挂匿名 upload-mdcs/upload-history(WatchDog 写死回传)。
|
||||
// upload-mdcs 仅在有进行中的拉取会话时可写入,其余管理端点仍需 JWT。请确保本机处于可信内网。
|
||||
Console.WriteLine($"[MiGu.Server] OTA 回传端口 {receivePort} 已监听(0.0.0.0):匿名接收车辆包,仅限可信内网。");
|
||||
}
|
||||
builder.WebHost.UseUrls(urls);
|
||||
}
|
||||
|
||||
// S2 根治 (会话45):让 MiGu.Server 启动时自动优先把 frontends/apps/simple-platform-vue/dist/
|
||||
@@ -95,6 +111,11 @@ builder.Services.AddControllers()
|
||||
opt.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull;
|
||||
opt.JsonSerializerOptions.WriteIndented = false;
|
||||
});
|
||||
// WatchDog 回传 M/D/C 可较大;放宽 multipart 默认 128MB 限制
|
||||
builder.Services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(o =>
|
||||
{
|
||||
o.MultipartBodyLengthLimit = 512_000_000;
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
@@ -207,6 +228,25 @@ builder.Services.AddReverseProxy()
|
||||
var store = rt.HttpContext.RequestServices.GetRequiredService<InternalTokenStore>();
|
||||
rt.ProxyRequest.Headers.Remove("X-Platform-Internal-Token");
|
||||
rt.ProxyRequest.Headers.Add("X-Platform-Internal-Token", store.Token);
|
||||
|
||||
var user = rt.HttpContext.User;
|
||||
var username = user.FindFirst("unique_name")?.Value
|
||||
?? user.Identity?.Name
|
||||
?? user.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
|
||||
?? user.FindFirst("sub")?.Value;
|
||||
var userId = user.FindFirst("sub")?.Value
|
||||
?? user.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||||
var scope = user.FindFirst("scope")?.Value;
|
||||
|
||||
rt.ProxyRequest.Headers.Remove("X-Platform-User");
|
||||
rt.ProxyRequest.Headers.Remove("X-Platform-User-Id");
|
||||
rt.ProxyRequest.Headers.Remove("X-Platform-Scope");
|
||||
if (!string.IsNullOrWhiteSpace(username))
|
||||
rt.ProxyRequest.Headers.TryAddWithoutValidation("X-Platform-User", username);
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
rt.ProxyRequest.Headers.TryAddWithoutValidation("X-Platform-User-Id", userId);
|
||||
if (!string.IsNullOrWhiteSpace(scope))
|
||||
rt.ProxyRequest.Headers.TryAddWithoutValidation("X-Platform-Scope", scope);
|
||||
return ValueTask.CompletedTask;
|
||||
});
|
||||
});
|
||||
@@ -224,6 +264,20 @@ builder.Services.AddPlatformPersistence(builder.Configuration);
|
||||
builder.Services.Configure<SimpleLiteOptions>(builder.Configuration.GetSection("SimpleLite"));
|
||||
builder.Services.AddSingleton<SimpleLiteLauncher>();
|
||||
|
||||
// OTA(WatchDog 编排):包库 / 任务 / 出站客户端
|
||||
builder.Services.Configure<OtaOptions>(builder.Configuration.GetSection("Ota"));
|
||||
builder.Services.AddSingleton<OtaStore>();
|
||||
builder.Services.AddSingleton<InternalTokenStoreAccessor>();
|
||||
builder.Services.AddSingleton<OtaVehicleSource>();
|
||||
builder.Services.AddSingleton<WatchDogClient>();
|
||||
builder.Services.AddSingleton<OtaJobRunner>();
|
||||
builder.Services.AddSingleton<MiGu.Server.Fleet.FleetHealthService>();
|
||||
builder.Services.AddSingleton<MiGu.Server.Fleet.CdmTaskSyncer>();
|
||||
builder.Services.AddHostedService<MiGu.Server.Fleet.CdmTaskSyncService>();
|
||||
builder.Services.AddSingleton<MiGu.Server.Fleet.AlarmCollector>();
|
||||
builder.Services.AddHostedService<MiGu.Server.Fleet.AlarmCollectorService>();
|
||||
builder.Services.AddHttpClient(nameof(WatchDogClient));
|
||||
|
||||
var app = builder.Build();
|
||||
await app.Services.EnsurePlatformDatabaseAsync();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user