Initial commit
This commit is contained in:
313
srcs/RobotNet10/RobotApp/RobotNet10.RobotApp/Program.cs
Normal file
313
srcs/RobotNet10/RobotApp/RobotNet10.RobotApp/Program.cs
Normal file
@@ -0,0 +1,313 @@
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MudBlazor.Services;
|
||||
using NLog.Web;
|
||||
using RobotNet10.CANOpen;
|
||||
using RobotNet10.CustomConfiguration.Extensions;
|
||||
using RobotNet10.MapManager.Extensions;
|
||||
using RobotNet10.NavigationTune.Data;
|
||||
using RobotNet10.NavigationTune.Execution;
|
||||
using RobotNet10.NavigationTune.Extensions;
|
||||
using RobotNet10.NavigationTune.Hubs;
|
||||
using RobotNet10.RobotApp.Client;
|
||||
using RobotNet10.RobotApp.Components;
|
||||
using RobotNet10.RobotApp.Components.Account;
|
||||
using RobotNet10.RobotApp.Data;
|
||||
using RobotNet10.RobotApp.Detection;
|
||||
using RobotNet10.RobotApp.Devices;
|
||||
using RobotNet10.RobotApp.Hubs;
|
||||
using RobotNet10.RobotApp.Interfaces;
|
||||
using RobotNet10.RobotApp.MarkerDetection;
|
||||
using RobotNet10.RobotApp.Modules;
|
||||
using RobotNet10.RobotApp.Motion;
|
||||
using RobotNet10.RobotApp.Services;
|
||||
using RobotNet10.RobotApp.Services.Navigation;
|
||||
using RobotNet10.RobotApp.Services.Robot;
|
||||
using RobotNet10.RobotApp.Services.NavigationMonitor;
|
||||
using RobotNet10.RobotApp.Services.Simulation;
|
||||
using RobotNet10.RobotApp.Navigation;
|
||||
using RobotNet10.RobotApp.TF3;
|
||||
using RobotNet10.RobotApp.Xloc;
|
||||
using RobotNet10.ScriptEngine;
|
||||
using RobotNet10.ScriptEngine.Helpers;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
||||
// Print Ceres library information at startup
|
||||
//CeresLibraryInfo.PrintLibraryInfo();
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var robotConfig = builder.Configuration["RobotConfig"];
|
||||
if(string.IsNullOrEmpty(robotConfig) || !File.Exists(robotConfig))
|
||||
{
|
||||
throw new Exception("RobotConfig not found");
|
||||
}
|
||||
builder.Configuration.AddJsonFile(robotConfig);
|
||||
|
||||
// Add NLog
|
||||
//builder.Logging.ClearProviders();
|
||||
//builder.Logging.SetMinimumLevel(LogLevel.Trace);
|
||||
builder.Host.UseNLog();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents()
|
||||
.AddInteractiveWebAssemblyComponents()
|
||||
.AddAuthenticationStateSerialization();
|
||||
|
||||
builder.Services.AddCascadingAuthenticationState();
|
||||
builder.Services.AddScoped<IdentityRedirectManager>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
|
||||
|
||||
builder.Services.AddAuthentication()
|
||||
.AddBearerToken(IdentityConstants.BearerScheme);
|
||||
|
||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(connectionString, b => b.MigrationsAssembly("RobotNet10.RobotApp").UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));
|
||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
|
||||
{
|
||||
options.SignIn.RequireConfirmedAccount = true;
|
||||
options.Lockout.AllowedForNewUsers = false;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.Password.RequireUppercase = false;
|
||||
options.Password.RequireLowercase = false;
|
||||
options.Password.RequireDigit = false;
|
||||
})
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddSignInManager()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
|
||||
|
||||
builder.Services.AddMudServices();
|
||||
builder.Services.AddNavigationMenu();
|
||||
|
||||
builder.Services.Configure<FormOptions>(o =>
|
||||
{
|
||||
o.MultipartBodyLengthLimit = 200L * 1024 * 1024;
|
||||
});
|
||||
builder.WebHost.ConfigureKestrel(o =>
|
||||
{
|
||||
o.Limits.MaxRequestBodySize = 200L * 1024 * 1024;
|
||||
});
|
||||
|
||||
// Add HttpClient for Blazor Server components (server-side calls into the same Kestrel app).
|
||||
// BaseAddress must be loopback: using the browser's WAN/MOXA host from this machine often fails (hairpin NAT).
|
||||
builder.Services.AddScoped(sp =>
|
||||
{
|
||||
var navigationManager = sp.GetRequiredService<Microsoft.AspNetCore.Components.NavigationManager>();
|
||||
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true
|
||||
};
|
||||
|
||||
var publicBase = new Uri(navigationManager.BaseUri);
|
||||
var loopbackBase = new UriBuilder(publicBase) { Host = "127.0.0.1" }.Uri;
|
||||
|
||||
return new HttpClient(handler) { BaseAddress = loopbackBase };
|
||||
});
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddSignalR();
|
||||
builder.Services.AddSingleton<DeviceHubContext>();
|
||||
builder.Services.AddSingleton<OdometryHubContext>();
|
||||
var scriptConnectionString = builder.Configuration.GetConnectionString("ScriptEngineConnection") ?? throw new InvalidOperationException("Connection string 'ScriptEngineConnection' not found.");
|
||||
builder.Services.AddScriptEngine<ScriptEngineResource>(options => options.UseSqlite(scriptConnectionString, b => b.MigrationsAssembly("RobotNet10.RobotApp")));
|
||||
|
||||
var mapConnectionString = builder.Configuration.GetConnectionString("MapEditorConnection") ?? throw new InvalidOperationException("Connection string 'MapEditorConnection' not found.");
|
||||
builder.Services.AddMapManager(builder.Configuration, options => options.UseSqlite(mapConnectionString, b => b.MigrationsAssembly("RobotNet10.RobotApp").UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)), "LayoutImage");
|
||||
|
||||
// var navTuneConnectionString = builder.Configuration.GetConnectionString("NavigationTuneConnection") ?? throw new InvalidOperationException("Connection string 'NavigationTuneConnection' not found.");
|
||||
// builder.Services.AddNavigationTuningWithRobot(options => options.UseSqlite(navTuneConnectionString, b => b.MigrationsAssembly("RobotNet10.RobotApp").UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));
|
||||
|
||||
// Register adapters for Navigation Tuning
|
||||
// builder.Services.AddScoped<ILocalizationProvider>(sp =>
|
||||
// {
|
||||
// var localization = sp.GetRequiredService<RobotNet10.RobotApp.Interfaces.ILocalization>();
|
||||
// return new LocalizationAdapter(
|
||||
// () => localization.X,
|
||||
// () => localization.Y,
|
||||
// () => localization.Theta
|
||||
// );
|
||||
// });
|
||||
|
||||
builder.Services.AddScoped<IVelocityProvider>(sp =>
|
||||
{
|
||||
var velocityController = sp.GetRequiredService<IVelocityController>();
|
||||
return new VelocityControllerAdapter(
|
||||
() => velocityController.RawVelocity,
|
||||
(linear, angular) => velocityController.SetVelocity(linear, angular),
|
||||
() => velocityController.GetModelConfidence(),
|
||||
acc => velocityController.SetAcceleration(acc),
|
||||
dec => velocityController.SetDeceleration(dec)
|
||||
);
|
||||
});
|
||||
|
||||
// Add Custom Configuration
|
||||
builder.Services.AddCustomConfiguration(builder.Configuration, "StorageConfig");
|
||||
|
||||
builder.Services.AddCanOpenManager();
|
||||
builder.Services.AddSingleton<DeviceProvider>();
|
||||
builder.Services.AddSingleton<IDeviceProvider>(sp => sp.GetRequiredService<DeviceProvider>());
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<DeviceProvider>());
|
||||
|
||||
builder.Services.AddSingleton(typeof(RobotNet10.RobotApp.Services.Logger<>));
|
||||
builder.Services.AddRobotSimulation();
|
||||
|
||||
// Core C API services (TF3 -> XLOC -> Navigation)
|
||||
builder.Services.AddSingleton<TF3BufferManager>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<TF3BufferManager>());
|
||||
|
||||
// XLOC integration is required by RobotLocalization.
|
||||
builder.Services.AddSingleton<XlocIntegrationService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<XlocIntegrationService>());
|
||||
builder.Services.AddHostedService<XlocAutoLocalizationHostedService>();
|
||||
|
||||
builder.Services.AddSingleton<NavigationIntegrationService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<NavigationIntegrationService>());
|
||||
|
||||
builder.Services.AddRobot();
|
||||
|
||||
// Motion services
|
||||
builder.Services.AddSingleton<DifferentialDrive>();
|
||||
builder.Services.AddSingleton<IInverseKinematics>(sp => sp.GetRequiredService<DifferentialDrive>());
|
||||
builder.Services.AddSingleton<IOdometryEstimator>(sp => sp.GetRequiredService<DifferentialDrive>());
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<DifferentialDrive>());
|
||||
builder.Services.AddSingleton<OdometryService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<OdometryService>());
|
||||
builder.Services.AddHostedService<OdometryBroadcastService>();
|
||||
|
||||
// Rotation Module services
|
||||
// builder.Services.AddSingleton<RotationModuleService>();
|
||||
// builder.Services.AddSingleton<IRotationModule>(sp => sp.GetRequiredService<RotationModuleService>());
|
||||
// builder.Services.AddHostedService(sp => sp.GetRequiredService<RotationModuleService>());
|
||||
|
||||
// Lift Module: bật khi Modules:LiftModule:Enable = true
|
||||
var liftModuleEnabled = builder.Configuration.GetValue<bool>("Modules:LiftModule:Enable");
|
||||
if (liftModuleEnabled)
|
||||
{
|
||||
builder.Services.AddSingleton<LiftModuleService>();
|
||||
builder.Services.AddSingleton<ILiftModule>(sp => sp.GetRequiredService<LiftModuleService>());
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<LiftModuleService>());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddSingleton<ILiftModule, NoOpLiftModule>();
|
||||
}
|
||||
|
||||
// Rotation Module (vẫn dùng NoOp khi chưa bật)
|
||||
builder.Services.AddSingleton<IRotationModule, NoOpRotationModule>();
|
||||
|
||||
builder.Services.AddSingleton<ManualControlService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<ManualControlService>());
|
||||
builder.Services.AddSingleton<PS5ControllerService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<PS5ControllerService>());
|
||||
|
||||
// builder.Services.AddCartographer(builder.Configuration.GetSection("Cartographer"));
|
||||
|
||||
// builder.Services.AddSingleton<IMarkerDetector, MarkerDetector>();
|
||||
|
||||
// Navigation Monitor (Telemetry & Safety)
|
||||
// builder.Services.AddSingleton<NavigationMonitorService>();
|
||||
// builder.Services.AddHostedService(sp => sp.GetRequiredService<NavigationMonitorService>());
|
||||
|
||||
#if DEBUG
|
||||
var dllPath = builder.Configuration["ScriptEngine:RuntimeDllFolder"] ?? "dlls";
|
||||
if(!Directory.Exists(dllPath))
|
||||
{
|
||||
Directory.CreateDirectory(dllPath);
|
||||
}
|
||||
var netCoreDir = Path.GetDirectoryName(typeof(object).Assembly.Location);
|
||||
if (!string.IsNullOrEmpty(netCoreDir))
|
||||
{
|
||||
var coreSrc = Path.Combine(netCoreDir, "System.Private.CoreLib.dll");
|
||||
var runtimeSrc = Path.Combine(netCoreDir, "System.Runtime.dll");
|
||||
var linqSrc = Path.Combine(netCoreDir, "System.Linq.Expressions.dll");
|
||||
var scriptSrc = typeof(RobotNet10.Script.ILogger).Assembly.Location;
|
||||
var robotAppSrc = typeof(RobotNet10.RobotApp.Script.IRobot).Assembly.Location;
|
||||
|
||||
var coreDest = Path.Combine(dllPath, "System.Private.CoreLib.dll");
|
||||
var runtimeDest = Path.Combine(dllPath, "System.Runtime.dll");
|
||||
var linqDest = Path.Combine(dllPath, "System.Linq.Expressions.dll");
|
||||
var scriptDest = Path.Combine(dllPath, "RobotNet10.Script.dll");
|
||||
var robotAppDest = Path.Combine(dllPath, "RobotNet10.RobotApp.Script.dll");
|
||||
|
||||
if(!File.Exists(coreDest)) File.Copy(coreSrc, coreDest);
|
||||
if(!File.Exists(runtimeDest)) File.Copy(runtimeSrc, runtimeDest);
|
||||
if(!File.Exists(linqDest)) File.Copy(linqSrc, linqDest);
|
||||
|
||||
File.Copy(scriptSrc, scriptDest, true);
|
||||
File.Copy(robotAppSrc, robotAppDest, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
await app.Services.SeedApplicationDbAsync();
|
||||
await app.Services.SeedScriptEngineDbAsync();
|
||||
await app.Services.SeedMapManagerAsync();
|
||||
|
||||
var serviceProbe = app.Services.GetService<IServiceProviderIsService>();
|
||||
if (serviceProbe?.IsService(typeof(TuningDbContext)) == true)
|
||||
{
|
||||
await app.Services.SeedTuningDbAsync();
|
||||
}
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseWebAssemblyDebugging();
|
||||
app.UseMigrationsEndPoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAntiforgery();
|
||||
app.MapControllers();
|
||||
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode()
|
||||
.AddInteractiveWebAssemblyRenderMode()
|
||||
.AddAdditionalAssemblies(typeof(RobotNet10.RobotApp.Client._Imports).Assembly);
|
||||
|
||||
// Add additional endpoints required by the Identity /Account Razor components.
|
||||
app.MapAdditionalIdentityEndpoints();
|
||||
app.MapScriptEngineHubs();
|
||||
app.MapHub<DeviceHub>("/hubs/devices");
|
||||
app.MapHub<BatteryHub>("/hubs/devices/battery");
|
||||
app.MapHub<InertialMeasurementUnitHub>("/hubs/devices/inertialmeasurementunit");
|
||||
app.MapHub<LidarHub>("/hubs/devices/lidar");
|
||||
app.MapHub<ModbusTcpHub>("/hubs/devices/modbustcp");
|
||||
// app.MapHub<RfHandleHub>("/hubs/devices/rfhandle");
|
||||
app.MapHub<CameraQrHub>("/hubs/devices/cameraqr");
|
||||
app.MapHub<CiA402ServoHub>("/hubs/devices/cia402servo");
|
||||
app.MapHub<MotionHub>("/hubs/motion");
|
||||
app.MapHub<OdometryHub>("/hubs/odometry");
|
||||
app.MapHub<XlocPoseHub>("/hubs/xloc/pose");
|
||||
// app.MapHub<SLAMHub>("/hubs/slam");
|
||||
// app.MapHub<TuningHub>("/tuninghub");
|
||||
app.MapHub<PlcControllerHub>("/hubs/plc/controller");
|
||||
// app.MapHub<MarkerDetectorHub>("hubs/marker-detect");
|
||||
// app.MapHub<NavigationMonitorHub>("/hubs/motion/navigation-monitor");
|
||||
// app.MapHub<RobotNet10.RobotApp.Hubs.XlocHub>("/hubs/xloc");
|
||||
|
||||
app.MapMotionApiEndpoints();
|
||||
app.MapPlcApiEndpoints();
|
||||
app.MapXlocApiEndpoints();
|
||||
app.MapNavigationApiEndpoints();
|
||||
app.MapTf3ApiEndpoints();
|
||||
app.MapMarkerDetectionApiEndpoints();
|
||||
|
||||
app.Run();
|
||||
|
||||
Reference in New Issue
Block a user