Compare commits
10 Commits
7ce770404c
...
b2eeb8cb3f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2eeb8cb3f | ||
|
|
128600c4ed | ||
|
|
b006c5b197 | ||
|
|
4ceec9abd5 | ||
|
|
1289a6c331 | ||
|
|
f1a7be15f2 | ||
|
|
d4af3b8707 | ||
|
|
7daad2dfaf | ||
|
|
38858355e6 | ||
|
|
65217021d4 |
66
.dockerignore
Normal file
66
.dockerignore
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Build artifacts
|
||||
**/bin/
|
||||
**/obj/
|
||||
**/out/
|
||||
|
||||
# Visual Studio files
|
||||
**/.vs/
|
||||
**/.vscode/
|
||||
**/*.user
|
||||
**/*.suo
|
||||
**/*.userosscache
|
||||
**/*.sln.docstates
|
||||
|
||||
# User-specific files
|
||||
**/.user
|
||||
**/.suo
|
||||
**/.userosscache
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# NuGet packages
|
||||
**/packages/
|
||||
**/*.nupkg
|
||||
**/*.snupkg
|
||||
|
||||
# Test results
|
||||
**/[Tt]est[Rr]esult*/
|
||||
**/[Bb]uild[Ll]og.*
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
.dockerignore
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Data and logs (will be mounted as volumes)
|
||||
data/
|
||||
logs/
|
||||
|
||||
57
Dockerfile
Normal file
57
Dockerfile
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Stage 1: Build
|
||||
# Note: Project files specify net10.0, but using .NET 9.0 based on package versions (9.0.9)
|
||||
# Adjust version if needed: 8.0 (LTS), 9.0 (current), or future 10.0
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
WORKDIR /src
|
||||
|
||||
# Copy solution file
|
||||
COPY RobotApp.sln .
|
||||
|
||||
# Copy project files
|
||||
COPY RobotApp/RobotApp.csproj RobotApp/
|
||||
COPY RobotApp.Client/RobotApp.Client.csproj RobotApp.Client/
|
||||
COPY RobotApp.Common.Shares/RobotApp.Common.Shares.csproj RobotApp.Common.Shares/
|
||||
COPY RobotApp.VDA5050/RobotApp.VDA5050.csproj RobotApp.VDA5050/
|
||||
|
||||
# Restore dependencies
|
||||
RUN dotnet restore RobotApp.sln
|
||||
|
||||
# Copy all source files
|
||||
COPY RobotApp/ RobotApp/
|
||||
COPY RobotApp.Client/ RobotApp.Client/
|
||||
COPY RobotApp.Common.Shares/ RobotApp.Common.Shares/
|
||||
COPY RobotApp.VDA5050/ RobotApp.VDA5050/
|
||||
|
||||
RUN rm -rf ./RobotApp/RobotApp/bin
|
||||
RUN rm -rf ./RobotApp/RobotApp/obj
|
||||
RUN rm -rf ./RobotApp.Client/RobotApp.Client/bin
|
||||
RUN rm -rf ./RobotApp.Client/RobotApp.Client/obj
|
||||
RUN rm -rf ./RobotApp.Common.Shares/RobotApp.Common.Shares/bin
|
||||
RUN rm -rf ./RobotApp.Common.Shares/RobotApp.Common.Shares/obj
|
||||
RUN rm -rf ./RobotApp.VDA5050/RobotApp.VDA5050/bin
|
||||
RUN rm -rf ./RobotApp.VDA5050/RobotApp.VDA5050/obj
|
||||
|
||||
# Build the solution
|
||||
WORKDIR /src/RobotApp
|
||||
RUN dotnet build -c Release -o /app/build
|
||||
|
||||
# Stage 2: Publish
|
||||
FROM build AS publish
|
||||
WORKDIR /src/RobotApp
|
||||
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
# Copy published files
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish ./
|
||||
|
||||
# Set environment variables
|
||||
#ENV ASPNETCORE_URLS=http://+:8080
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
|
||||
# Run the application
|
||||
ENTRYPOINT ["dotnet", "RobotApp.dll"]
|
||||
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
}
|
||||
|
||||
public NavModel[] Navs = [
|
||||
new(){Icon = "mdi-view-dashboard", Path="/", Label = "Dashboard", Match = NavLinkMatch.All},
|
||||
new(){Icon = "mdi-view-dashboard", Path="/dashboard", Label = "Dashboard", Match = NavLinkMatch.All},
|
||||
// new(){Icon = "mdi-map-legend", Path="/maps-manager", Label = "Mapping", Match = NavLinkMatch.All},
|
||||
new(){Icon = "mdi-monitor", Path="/robot-monitor", Label = "Robot Monitor", Match = NavLinkMatch.All},
|
||||
new(){Icon = "mdi-state-machine", Path="/robot-order", Label = "order", Match = NavLinkMatch.All},
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@
|
|||
@using MudBlazor
|
||||
|
||||
@implements IDisposable
|
||||
@attribute [Authorize]
|
||||
|
||||
@inject RobotStateClient RobotStateClient
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4">
|
||||
<MudContainer MaxWidth="MaxWidth.False" Class="pa-4" Style="overflow-y:auto">
|
||||
<!-- Header Dashboard -->
|
||||
<MudPaper Class="pa-6 mb-4 d-flex align-center justify-space-between" Elevation="3">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
@page "/logs"
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
@attribute [Authorize]
|
||||
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
@using RobotApp.Client.Models
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
<PageTitle>Map Manager</PageTitle>
|
||||
|
||||
<div class="d-flex w-100 h-100 p-2 overflow-hidden flex-row">
|
||||
|
|
|
|||
|
|
@ -47,8 +47,10 @@
|
|||
|
||||
<div class="flex-grow-1">
|
||||
<MudTextField Value="@OrderJson"
|
||||
ReadOnly
|
||||
T="string"
|
||||
ValueChanged="OrderJsonChange"
|
||||
Variant="Variant.Filled"
|
||||
Immediate=true
|
||||
Lines="50"
|
||||
Style="font-family: 'Roboto Mono', Consolas, monospace;
|
||||
font-size: 0.85rem;
|
||||
|
|
@ -64,6 +66,8 @@
|
|||
[Parameter] public bool DisableCancel { get; set; }
|
||||
[Parameter] public bool? CancelSuccess { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<string> OrderJsonChanged { get; set; }
|
||||
|
||||
[Parameter] public EventCallback OnCopy { get; set; }
|
||||
[Parameter] public EventCallback OnSend { get; set; }
|
||||
[Parameter] public EventCallback OnImport { get; set; }
|
||||
|
|
@ -117,4 +121,11 @@
|
|||
_ => Icons.Material.Filled.Cancel
|
||||
};
|
||||
|
||||
|
||||
private void OrderJsonChange(string value)
|
||||
{
|
||||
OrderJson = value;
|
||||
OrderJsonChanged.InvokeAsync(OrderJson);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
@page "/robot-order"
|
||||
|
||||
@attribute [Authorize]
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
|
||||
@using System.Text.Json
|
||||
|
|
@ -46,7 +45,7 @@
|
|||
|
||||
<!-- ================= RIGHT ================= -->
|
||||
<MudItem xs="12" md="5" Class="h-100">
|
||||
<JsonOutputPanel OrderJson="@OrderJson"
|
||||
<JsonOutputPanel @bind-OrderJson="@OrderJson"
|
||||
Copied="@copied"
|
||||
SendSuccess="@sendSuccess"
|
||||
CancelSuccess="@cancelSuccess"
|
||||
|
|
@ -228,7 +227,7 @@
|
|||
sendSuccess = response.IsSuccessStatusCode;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
sendSuccess = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
@page "/robot-config"
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
@attribute [Authorize]
|
||||
|
||||
@inject HttpClient Http
|
||||
@inject ISnackbar Snackbar
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
@page "/robot-monitor"
|
||||
@rendermode InteractiveWebAssemblyNoPrerender
|
||||
@attribute [Authorize]
|
||||
@inject RobotApp.Client.Services.RobotMonitorService MonitorService
|
||||
@implements IAsyncDisposable
|
||||
|
||||
|
|
@ -39,3 +38,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -58,3 +58,5 @@ window.robotMonitor = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
@inject NavigationManager Nav
|
||||
|
||||
@code
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ namespace RobotApp.Controllers;
|
|||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
//[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class FileController(Services.Logger<FileController> Logger) : ControllerBase
|
||||
{
|
||||
private readonly string certificatesPath = "MqttCertificates";
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace RobotApp.Controllers;
|
|||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
//[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class ImagesController(Services.Logger<ImagesController> Logger) : ControllerBase
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ namespace RobotApp.Controllers;
|
|||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
//[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class LogsManagerController(Services.Logger<LogsManagerController> Logger) : ControllerBase
|
||||
{
|
||||
private readonly string LoggerDirectory = "logs";
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using RobotApp.Interfaces;
|
||||
using RobotApp.VDA5050.Order;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RobotApp.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/order")]
|
||||
public class OrderController( IOrder robotOrderController, IInstantActions instantActions) : ControllerBase
|
||||
//[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class OrderController(IOrder robotOrderController, IInstantActions instantActions) : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public IActionResult SendOrder([FromBody] OrderMsg order)
|
||||
{
|
||||
robotOrderController.UpdateOrder(order);
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ namespace RobotApp.Controllers;
|
|||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
//[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class RobotConfigsController(Services.Logger<RobotConfigsController> Logger, ApplicationDbContext AppDb, RobotConfiguration RobotConfiguration) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public static class ApplicationDbExtensions
|
|||
{
|
||||
ConfigName = "Default",
|
||||
Description = "Default robot simulation configuration",
|
||||
EnableSimulation = false,
|
||||
EnableSimulation = true,
|
||||
SimulationMaxVelocity = 1.5,
|
||||
SimulationMaxAngularVelocity = 0.5,
|
||||
SimulationAcceleration = 2,
|
||||
|
|
@ -155,6 +155,7 @@ public static class ApplicationDbExtensions
|
|||
VDA5050EnableTls = false,
|
||||
VDA5050UserName = "robotics",
|
||||
VDA5050Password = "robotics",
|
||||
VDA5050TopicPrefix = "uagv/v2",
|
||||
IsActive = true,
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ using RobotApp.Data;
|
|||
namespace RobotApp.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20251222025151_InitApplicationDb")]
|
||||
[Migration("20251222091852_InitApplicationDb")]
|
||||
partial class InitApplicationDb
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -10,3 +10,5 @@ public class RobotMonitorHub : Hub
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,22 +6,22 @@
|
|||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"workingDirectory": "$(TargetDir)",
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
//"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "http://localhost:5229",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"workingDirectory": "$(TargetDir)",
|
||||
//"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://0.0.0.0:7150;http://localhost:5229",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
//"https": {
|
||||
// "commandName": "Project",
|
||||
// "dotnetRunMessages": true,
|
||||
// "launchBrowser": true,
|
||||
// "workingDirectory": "$(TargetDir)",
|
||||
// //"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
// "applicationUrl": "https://0.0.0.0:7150;http://localhost:5229",
|
||||
// "environmentVariables": {
|
||||
// "ASPNETCORE_ENVIRONMENT": "Development"
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,17 +195,6 @@ public class MQTTClient : IAsyncDisposable
|
|||
arg.Chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
|
||||
|
||||
var isValid = arg.Chain.Build((X509Certificate2)arg.Certificate);
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
Console.WriteLine("Broker CERTIFICATE VALID");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Broker CERTIFICATE INVALID");
|
||||
foreach (var status in arg.Chain.ChainStatus)
|
||||
Console.WriteLine($" -> Chain error: {status.Status} - {status.StatusInformation}");
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ public class MQTTClientCertificatesProvider(string? CerFile, string? KeyFile) :
|
|||
var cert = X509Certificate2.CreateFromPem(File.ReadAllText(certLocal), File.ReadAllText(keyLocal));
|
||||
var pfxBytes = cert.Export(X509ContentType.Pfx);
|
||||
var pfxCert = X509CertificateLoader.LoadPkcs12(pfxBytes, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
|
||||
Console.WriteLine($"Client cert loaded: {pfxCert.Subject}, HasPrivateKey: {pfxCert.HasPrivateKey}, PrivateKey Type: {pfxCert.GetRSAPrivateKey()?.GetType()}");
|
||||
return [pfxCert];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ public abstract class RobotAction(IServiceProvider serviceProvider) : IDisposabl
|
|||
|
||||
protected virtual Task StopAction()
|
||||
{
|
||||
Console.WriteLine($"StopAction {Type}");
|
||||
Status = ActionStatus.FAILED;
|
||||
ResultDescription = "Action bị hủy bỏ.";
|
||||
return Task.CompletedTask;
|
||||
|
|
|
|||
|
|
@ -169,15 +169,10 @@ public class RobotStatePublisher : BackgroundService
|
|||
isConnected, // payload only bool
|
||||
stoppingToken
|
||||
);
|
||||
|
||||
Console.WriteLine(
|
||||
$"[RobotStatePublisher] Robot connection changed → {(isConnected ? "ONLINE" : "OFFLINE")}"
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,14 +158,12 @@ public class SimulationNavigation : INavigation, IDisposable
|
|||
|
||||
public void Pause()
|
||||
{
|
||||
Console.WriteLine($"Nav Pause");
|
||||
ResumeState = State;
|
||||
NavState = NavigationState.Paused;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
Console.WriteLine($"Nav Resume");
|
||||
NavState = ResumeState;
|
||||
}
|
||||
|
||||
|
|
|
|||
35
docker-compose.yaml
Normal file
35
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
robotapp:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: robotapp
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- ASPNETCORE_URLS=http://+:8080
|
||||
- ConnectionStrings__DefaultConnection=Data Source=/app/data/robot.db
|
||||
volumes:
|
||||
# Persist database
|
||||
- ./data:/app/data
|
||||
# Persist maps
|
||||
- ./maps:/app/maps
|
||||
# Persist logs (if needed)
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- robotapp-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
robotapp-network:
|
||||
driver: bridge
|
||||
|
||||
Loading…
Reference in New Issue
Block a user