Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect backend and frontend to signalR #1041

Merged
merged 18 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@ dotnet format is used to detect naming conventions and other code-related issues
dotnet format --severity info
```

## SignalR

We use SignalR to asynchronously send event updates to the frontend. Currently we only support sending
events and not receiving them, and all transmissions are sent using the SignalRService class. When
doing so it is important to make sure that the event name provided corresponds with the name expected
in the frontend.

It is also crucial that we do not await sending signalR messages in our code. Instead we ignore the
await warning. In the current version of the SignalR library, sending a message in an
asynchronous thread may cause the thread to silently exit without returning an exception, which is
avoided by letting the SignalR code run asynchronously after the current thread has executed.

## Monitoring

We use [Azure Application Insights](https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core)
Expand Down
6 changes: 4 additions & 2 deletions backend/api.test/EventHandlers/TestMissionEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class TestMissionEventHandler : IDisposable
private readonly IMissionRunService _missionRunService;
private readonly IMissionScheduling _missionScheduling;
private readonly IMissionSchedulingService _missionSchedulingService;
private readonly ISignalRService _signalRService;

#pragma warning disable IDE0052
private readonly MqttEventHandler _mqttEventHandler;
Expand All @@ -69,10 +70,11 @@ public TestMissionEventHandler(DatabaseFixture fixture)

_context = fixture.NewContext;

_signalRService = new MockSignalRService();
_mqttService = new MqttService(mqttServiceLogger, configuration);
_missionRunService = new MissionRunService(_context, missionLogger);
_missionRunService = new MissionRunService(_context, _signalRService, missionLogger);
_robotModelService = new RobotModelService(_context);
_robotService = new RobotService(_context, _robotModelService);
_robotService = new RobotService(_context, _robotModelService, _signalRService);
_robotModelService = new RobotModelService(_context);
_robotControllerMock = new RobotControllerMock();
_isarServiceMock = new MockIsarService();
Expand Down
6 changes: 3 additions & 3 deletions backend/api.test/Mocks/EchoServiceMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ public class MockEchoService : IEchoService
Tags = new List<EchoTag>()
};

public CondensedMissionDefinition MockMissionDefinition =
public CondensedEchoMissionDefinition MockMissionDefinition =
new()
{
EchoMissionId = 1,
Name = "test",
};

public async Task<IList<CondensedMissionDefinition>> GetAvailableMissions(string? installationCode)
public async Task<IList<CondensedEchoMissionDefinition>> GetAvailableMissions(string? installationCode)
{
await Task.Run(() => Thread.Sleep(1));
return new List<CondensedMissionDefinition>(new CondensedMissionDefinition[] { MockMissionDefinition });
return new List<CondensedEchoMissionDefinition>(new CondensedEchoMissionDefinition[] { MockMissionDefinition });
}

public async Task<EchoMission> GetMissionById(int missionId)
Expand Down
30 changes: 30 additions & 0 deletions backend/api.test/Mocks/SignalRServiceMock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Threading.Tasks;
namespace Api.Services
{
public class MockSignalRService : ISignalRService
{
public MockSignalRService()
{
}

public async Task SendMessageAsync<T>(string label, T messageObject)
{
await Task.CompletedTask;
}

public async Task SendMessageAsync<T>(string label, string user, T messageObject)
{
await Task.CompletedTask;
}

public async Task SendMessageAsync(string label, string message)
{
await Task.CompletedTask;
}

public async Task SendMessageAsync(string label, string user, string message)
{
await Task.CompletedTask;
}
}
}
4 changes: 3 additions & 1 deletion backend/api.test/Services/MissionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ public class MissionServiceTest : IDisposable
{
private readonly FlotillaDbContext _context;
private readonly ILogger<MissionRunService> _logger;
private readonly ISignalRService _signalRService;
private readonly MissionRunService _missionRunService;

public MissionServiceTest(DatabaseFixture fixture)
{
_context = fixture.NewContext;
_logger = new Mock<ILogger<MissionRunService>>().Object;
_missionRunService = new MissionRunService(_context, _logger);
_signalRService = new MockSignalRService();
_missionRunService = new MissionRunService(_context, _signalRService, _logger);
}

public void Dispose()
Expand Down
10 changes: 6 additions & 4 deletions backend/api.test/Services/RobotService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ public class RobotServiceTest : IDisposable
{
private readonly FlotillaDbContext _context;
private readonly RobotModelService _robotModelService;
private readonly ISignalRService _signalRService;

public RobotServiceTest(DatabaseFixture fixture)
{
_context = fixture.NewContext;
_robotModelService = new RobotModelService(_context);
_signalRService = new MockSignalRService();
}

public void Dispose()
Expand All @@ -31,7 +33,7 @@ public void Dispose()
[Fact]
public async Task ReadAll()
{
var robotService = new RobotService(_context, _robotModelService);
var robotService = new RobotService(_context, _robotModelService, _signalRService);
var robots = await robotService.ReadAll();

Assert.True(robots.Any());
Expand All @@ -40,7 +42,7 @@ public async Task ReadAll()
[Fact]
public async Task Read()
{
var robotService = new RobotService(_context, _robotModelService);
var robotService = new RobotService(_context, _robotModelService, _signalRService);
var robots = await robotService.ReadAll();
var firstRobot = robots.First();
var robotById = await robotService.ReadById(firstRobot.Id);
Expand All @@ -51,15 +53,15 @@ public async Task Read()
[Fact]
public async Task ReadIdDoesNotExist()
{
var robotService = new RobotService(_context, _robotModelService);
var robotService = new RobotService(_context, _robotModelService, _signalRService);
var robot = await robotService.ReadById("some_id_that_does_not_exist");
Assert.Null(robot);
}

[Fact]
public async Task Create()
{
var robotService = new RobotService(_context, _robotModelService);
var robotService = new RobotService(_context, _robotModelService, _signalRService);
var robotsBefore = await robotService.ReadAll();
int nRobotsBefore = robotsBefore.Count();
var videoStreamQuery = new CreateVideoStreamQuery()
Expand Down
4 changes: 2 additions & 2 deletions backend/api/Controllers/EchoController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ public EchoController(ILogger<EchoController> logger, IEchoService echoService,
/// </remarks>
[HttpGet]
[Route("available-missions/{plantCode}")]
[ProducesResponseType(typeof(List<CondensedMissionDefinition>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(List<CondensedEchoMissionDefinition>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<IList<CondensedMissionDefinition>>> GetAvailableEchoMissions([FromRoute] string? plantCode)
public async Task<ActionResult<IList<CondensedEchoMissionDefinition>>> GetAvailableEchoMissions([FromRoute] string? plantCode)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# nullable disable
namespace Api.Controllers.Models
{
public class CondensedMissionDefinition
public class CondensedEchoMissionDefinition
{
public int EchoMissionId { get; set; }

Expand Down
12 changes: 6 additions & 6 deletions backend/api/Controllers/Models/MissionDefinitionResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class CondensedMissionDefinitionResponse
[JsonPropertyName("inspectionFrequency")]
public TimeSpan? InspectionFrequency { get; set; }

[JsonPropertyName("lastRun")]
public virtual MissionRun? LastRun { get; set; }
[JsonPropertyName("lastSuccessfulRun")]
public virtual MissionRun? LastSuccessfulRun { get; set; }

[JsonPropertyName("area")]
public AreaResponse? Area { get; set; }
Expand All @@ -42,7 +42,7 @@ public CondensedMissionDefinitionResponse(MissionDefinition missionDefinition)
Comment = missionDefinition.Comment;
InspectionFrequency = missionDefinition.InspectionFrequency;
Area = missionDefinition.Area != null ? new AreaResponse(missionDefinition.Area) : null;
LastRun = missionDefinition.LastRun;
LastSuccessfulRun = missionDefinition.LastSuccessfulRun;
IsDeprecated = missionDefinition.IsDeprecated;
SourceType = missionDefinition.Source.Type;
}
Expand All @@ -68,8 +68,8 @@ public class MissionDefinitionResponse
[JsonPropertyName("inspectionFrequency")]
public TimeSpan? InspectionFrequency { get; set; }

[JsonPropertyName("lastRun")]
public virtual MissionRun? LastRun { get; set; }
[JsonPropertyName("lastSuccessfulRun")]
public virtual MissionRun? LastSuccessfulRun { get; set; }

[JsonPropertyName("area")]
public Area? Area { get; set; }
Expand All @@ -89,7 +89,7 @@ public MissionDefinitionResponse(IMissionDefinitionService service, MissionDefin
InspectionFrequency = missionDefinition.InspectionFrequency;
Area = missionDefinition.Area;
Tasks = service.GetTasksFromSource(missionDefinition.Source, missionDefinition.InstallationCode).Result!;
LastRun = missionDefinition.LastRun;
LastSuccessfulRun = missionDefinition.LastSuccessfulRun;
IsDeprecated = missionDefinition.IsDeprecated;
SourceType = missionDefinition.Source.Type;
}
Expand Down
18 changes: 9 additions & 9 deletions backend/api/Database/Context/InitDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
Source = sources[0],
Comment = "Interesting comment",
InspectionFrequency = new DateTime().AddDays(12) - new DateTime(),
LastRun = null
LastSuccessfulRun = null
};

var missionDefinition2 = new MissionDefinition
Expand All @@ -298,7 +298,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
Area = areas[1],
Source = sources[1],
InspectionFrequency = new DateTime().AddDays(7) - new DateTime(),
LastRun = null
LastSuccessfulRun = null
};

var missionDefinition3 = new MissionDefinition
Expand All @@ -308,7 +308,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
InstallationCode = areas[1].Installation!.InstallationCode,
Area = areas[1],
Source = sources[2],
LastRun = null
LastSuccessfulRun = null
};

var missionDefinition4 = new MissionDefinition
Expand All @@ -319,7 +319,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
InspectionFrequency = new DateTime().AddDays(90) - new DateTime(),
Area = areas[2],
Source = sources[2],
LastRun = null
LastSuccessfulRun = null
};

var missionDefinition5 = new MissionDefinition
Expand All @@ -330,7 +330,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
InspectionFrequency = new DateTime().AddDays(35) - new DateTime(),
Area = areas[2],
Source = sources[2],
LastRun = null
LastSuccessfulRun = null
};

var missionDefinition6 = new MissionDefinition
Expand All @@ -341,7 +341,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
InspectionFrequency = new DateTime().AddDays(4) - new DateTime(),
Area = areas[3],
Source = sources[2],
LastRun = null
LastSuccessfulRun = null
};
_ = new MissionDefinition
{
Expand All @@ -350,7 +350,7 @@ private static List<MissionDefinition> GetMissionDefinitions()
InstallationCode = areas[3].Installation.InstallationCode,
Area = areas[4],
Source = sources[2],
LastRun = null
LastSuccessfulRun = null
};

return new List<MissionDefinition>(new[]
Expand Down Expand Up @@ -473,7 +473,7 @@ private static List<MissionRun> GetMissionRuns()
Tasks = new List<MissionTask>(),
Map = new MapMetadata()
};
missionDefinitions[0].LastRun = missionRun2;
missionDefinitions[0].LastSuccessfulRun = missionRun2;

var missionRun3 = new MissionRun
{
Expand Down Expand Up @@ -556,7 +556,7 @@ private static List<MissionRun> GetMissionRuns()
Map = new MapMetadata()
};

missionDefinitions[1].LastRun = missionRun3;
missionDefinitions[1].LastSuccessfulRun = missionRun3;

return new List<MissionRun>(new[]
{
Expand Down
2 changes: 1 addition & 1 deletion backend/api/Database/Models/MissionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class MissionDefinition : SortableRecord
[Column(TypeName = "bigint")]
public TimeSpan? InspectionFrequency { get; set; }

public virtual MissionRun? LastRun { get; set; }
public virtual MissionRun? LastSuccessfulRun { get; set; }

public Area? Area { get; set; }

Expand Down
Loading