81 lines
3.2 KiB
C#
81 lines
3.2 KiB
C#
using YD_TrainingCompetition_Api.Competition;
|
||
using YD_TrainingCompetition_Api.Hubs;
|
||
using YD_TrainingCompetition_Api.Options;
|
||
using YD_TrainingCompetition_Api.Protocols;
|
||
using YD_TrainingCompetition_Api.Serial;
|
||
using YD_TrainingCompetition_Api.Services;
|
||
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
var listenUrls = builder.Configuration["ASPNETCORE_URLS"]
|
||
?? builder.Configuration["urls"]
|
||
?? "http://*:9996";
|
||
builder.WebHost.UseUrls(listenUrls);
|
||
|
||
builder.Services.Configure<ScoringOptions>(builder.Configuration.GetSection(ScoringOptions.SectionName));
|
||
builder.Services.Configure<Serial24GOptions>(builder.Configuration.GetSection(Serial24GOptions.SectionName));
|
||
builder.Services.Configure<RosterOptions>(builder.Configuration.GetSection(RosterOptions.SectionName));
|
||
builder.Services.Configure<HikvisionOptions>(builder.Configuration.GetSection(HikvisionOptions.SectionName));
|
||
|
||
builder.Services.AddControllers();
|
||
builder.Services.AddEndpointsApiExplorer();
|
||
builder.Services.AddSwaggerGen();
|
||
builder.Services.AddSignalR();
|
||
|
||
builder.Services.AddCors(options =>
|
||
{
|
||
options.AddDefaultPolicy(policy =>
|
||
{
|
||
policy.AllowAnyHeader()
|
||
.AllowAnyMethod()
|
||
.SetIsOriginAllowed(_ => true)
|
||
.AllowCredentials();
|
||
});
|
||
});
|
||
|
||
builder.Services.AddSingleton<IDeviceStateStore, DeviceStateStore>();
|
||
builder.Services.AddSingleton<IRealtimeNotifier, SignalRRealtimeNotifier>();
|
||
builder.Services.AddSingleton<ISerialGateway, SerialGateway>();
|
||
builder.Services.AddSingleton<IJumpProtocolParser, JumpProtocolParser>();
|
||
builder.Services.AddSingleton<IRosterService, RosterService>();
|
||
builder.Services.AddSingleton<IParticipantDirectory, ParticipantDirectory>();
|
||
builder.Services.AddSingleton<ICompetitionSessionService, CompetitionSessionService>();
|
||
builder.Services.AddSingleton<IHikvisionAlarmStore, HikvisionAlarmStore>();
|
||
builder.Services.AddHostedService<SerialIngestWorker>();
|
||
builder.Services.AddHostedService<CompetitionCountdownWorker>();
|
||
builder.Services.AddHostedService<HikvisionIngestWorker>();
|
||
|
||
var app = builder.Build();
|
||
|
||
if (app.Environment.IsDevelopment())
|
||
{
|
||
app.UseSwagger();
|
||
app.UseSwaggerUI();
|
||
}
|
||
|
||
// 提供打包后内置的前端静态资源(桌面端通过 http 加载,避免 file:// 下 fetch/绝对路径失效)。
|
||
// 使用可执行文件同级的 wwwroot 绝对路径,避免内容根/工作目录差异导致静态资源 404。
|
||
var webRootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot");
|
||
var hasBundledFrontend = Directory.Exists(webRootPath);
|
||
Microsoft.Extensions.FileProviders.PhysicalFileProvider? frontendFileProvider = null;
|
||
if (hasBundledFrontend)
|
||
{
|
||
frontendFileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(webRootPath);
|
||
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = frontendFileProvider });
|
||
app.UseStaticFiles(new StaticFileOptions { FileProvider = frontendFileProvider });
|
||
}
|
||
|
||
app.UseRouting();
|
||
app.UseCors();
|
||
|
||
app.MapControllers();
|
||
app.MapHub<ScoringHub>("/hubs/scoring");
|
||
|
||
// 单页应用兜底:非 API/Hub 路由回退到 index.html(仅当存在内置前端时生效)。
|
||
if (hasBundledFrontend && frontendFileProvider is not null)
|
||
{
|
||
app.MapFallbackToFile("index.html", new StaticFileOptions { FileProvider = frontendFileProvider });
|
||
}
|
||
|
||
app.Run();
|