Skip to content
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
65 changes: 65 additions & 0 deletions .github/workflows/develop_edge-dev-01-dittobox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy ASP.Net Core app to Azure Web App - edge-dev-01-dittobox

on:
push:
branches:
- develop
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'

- name: Build with dotnet
run: dotnet build --configuration Release

- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp

- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: .net-app
path: ${{env.DOTNET_ROOT}}/myapp

deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
permissions:
id-token: write #This is required for requesting the JWT

steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: .net-app

- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_233090D111F94CF38A1844536FC9A017 }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_C1F177FC6AF84878AEF8459FD4E0E6C7 }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_85141903D76C46FC8AE3CB521739A05E }}

- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: 'edge-dev-01-dittobox'
slot-name: 'Production'
package: .

10 changes: 10 additions & 0 deletions ContainerManagement/Application/ContainerSelfRegisterCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;

namespace DittoBox.EdgeServer.ContainerManagement.Application
{
public record ContainerSelfRegisterCommand
{
[Required]
public string Uiid { get; set; }
}
}
21 changes: 15 additions & 6 deletions ContainerManagement/Application/ContainerStatusReportCommand.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
using System.ComponentModel.DataAnnotations;
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.ValueObjects;

namespace DittoBox.EdgeServer.ContainerManagement.Application
{
public record ContainerStatusReportCommand
{
[Required]
public int ContainerId { get; set; }
[Required]
public int ContainerId;
public string? DeviceId { get; set; }
[Required]
public double? Temperature { get; set; }
[Required]
public double? Humidity { get; set; }
[Required]
public double? Oxygen { get; set; }
public double? GasOxygen { get; set; }
[Required]
public double? Dioxide { get; set; }
public double? GasCO2 { get; set; }
[Required]
public double? Ethylene { get; set; }
public double? GasEthylene { get; set; }
[Required]
public double? Ammonia { get; set; }
public double? GasAmmonia { get; set; }
[Required]
public double? SulfurDioxide { get; set; }
public double? GasSO2 { get; set; }
[Required]
public HealthMonitor GasHealthMonitor { get; set; } = new HealthMonitor();
[Required]
public HealthMonitor TemperatureHealthMonitor { get; set; } = new HealthMonitor();
[Required]
public HealthMonitor HumidityHealthMonitor { get; set; } = new HealthMonitor();
}
}
8 changes: 8 additions & 0 deletions ContainerManagement/Application/GetContainersQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.ComponentModel.DataAnnotations;

namespace DittoBox.EdgeServer.ContainerManagement.Application
{
public record GetContainersQuery
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using DittoBox.EdgeServer.ContainerManagement.Application.Resources;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces
{
public interface IContainerSelfRegisterCommandHandler
{
Task<ContainerRegistrationResource> Handle(ContainerSelfRegisterCommand command);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces
{
public interface IContainerStatusReportCommandHandler
{
Task Handle(ContainerStatusReportCommand command);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.Entities;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces
{
public interface IGetContainersQueryHandler
{
Task<IEnumerable<Container>> Handle();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces;
using DittoBox.EdgeServer.ContainerManagement.Application.Resources;
using DittoBox.EdgeServer.ContainerManagement.Domain.Services;
using DittoBox.EdgeServer.ContainerManagement.Infrastructure.Configuration;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Internal
{
public class ContainerSelfRegisterCommandHandler(
ICloudService cloudService,
IUnitOfWork unitOfWork
) : IContainerSelfRegisterCommandHandler
{
public async Task<ContainerRegistrationResource> Handle(ContainerSelfRegisterCommand command)
{
var result = await cloudService.RegisterContainer(command.Uiid);
await unitOfWork.CommitAsync();
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces;
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.Entities;
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.ValueObjects;
using DittoBox.EdgeServer.ContainerManagement.Domain.Services;
using DittoBox.EdgeServer.ContainerManagement.Infrastructure.Configuration;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Internal
{
public class ContainerStatusReportCommandHandler(
IContainerService containerService,
ICloudService cloudService,
IUnitOfWork unitOfWork
) : IContainerStatusReportCommandHandler
{
private readonly int _maxMillisecondsBetweenReports = Convert.ToInt32(Environment.GetEnvironmentVariable("MAX_MILLISECONDS_BETWEEN_REPORTS") ?? "60000");

public async Task Handle(ContainerStatusReportCommand command)
{
Container? container = await containerService.GetContainerById(command.ContainerId);

// If not found by Id, try to find by DeviceId
if (container == null && !string.IsNullOrEmpty(command.DeviceId))
{
container = await containerService.GetContainerByUIID(command.DeviceId);
}

// If still not found, throw an exception
if (container == null)
{
throw new Exception("Container not found. Couldn't create a new container.");
}

// Generate the status report
var statusRecord = new ContainerStatusRecord
{
ContainerId = container.Id,
Temperature = command.Temperature,
Humidity = command.Humidity,
GasOxygen = command.GasOxygen,
GasCO2 = command.GasCO2,
GasEthylene = command.GasEthylene,
GasAmmonia = command.GasAmmonia,
GasSO2 = command.GasSO2,
SavedAt = DateTime.Now
};

// Generate the health reports
var healthRecords = new List<ContainerHealthRecord>
{
new() {
ContainerId = container.Id,
SensorType = SensorType.GAS_SENSOR,
FailuresSinceStartup = command.GasHealthMonitor.FailuresSinceStartup,
FailuresSinceLastCheck = command.GasHealthMonitor.FailuresSinceLastCheck,
RequestsSinceLastCheck = command.GasHealthMonitor.RequestsSinceLastCheck,
RequestsSinceStartup = command.GasHealthMonitor.RequestsSinceStartup,
FailingRate = command.GasHealthMonitor.FailingRate,
SavedAt = DateTime.Now
},
new() {
ContainerId = container.Id,
SensorType = SensorType.TEMPERATURE_SENSOR,
FailuresSinceStartup = command.TemperatureHealthMonitor.FailuresSinceStartup,
FailuresSinceLastCheck = command.TemperatureHealthMonitor.FailuresSinceLastCheck,
RequestsSinceLastCheck = command.TemperatureHealthMonitor.RequestsSinceLastCheck,
RequestsSinceStartup = command.TemperatureHealthMonitor.RequestsSinceStartup,
FailingRate = command.TemperatureHealthMonitor.FailingRate,
SavedAt = DateTime.Now
},
new() {
ContainerId = container.Id,
SensorType = SensorType.HUMIDITY_SENSOR,
FailuresSinceStartup = command.HumidityHealthMonitor.FailuresSinceStartup,
FailuresSinceLastCheck = command.HumidityHealthMonitor.FailuresSinceLastCheck,
RequestsSinceLastCheck = command.HumidityHealthMonitor.RequestsSinceLastCheck,
RequestsSinceStartup = command.HumidityHealthMonitor.RequestsSinceStartup,
FailingRate = command.HumidityHealthMonitor.FailingRate,
SavedAt = DateTime.Now
}
};

// Save the health reports
foreach (var healthRecord in healthRecords)
{
await containerService.SaveHealthReport(healthRecord);
}

// Save the status report
await containerService.SaveStatusReport(statusRecord);

// Commit the changes
await unitOfWork.CommitAsync();

// ----

// Send the report to the cloud if necessary
if (container.LastSentStatusReport == null || container.LastSentStatusReport < DateTime.Now.AddMilliseconds(-_maxMillisecondsBetweenReports))
{
await containerService.SendReportToCloud(container.Id, _maxMillisecondsBetweenReports);

}

await unitOfWork.CommitAsync();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Interfaces;
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.Entities;
using DittoBox.EdgeServer.ContainerManagement.Domain.Services;
using DittoBox.EdgeServer.ContainerManagement.Infrastructure.Configuration;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Handlers.Internal
{
public class GetContainersQueryHandler(
IContainerService containerService
) : IGetContainersQueryHandler
{
public async Task<IEnumerable<Container>> Handle()
{
return await containerService.GetContainers();
}
}
}
16 changes: 16 additions & 0 deletions ContainerManagement/Application/HealthMonitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

using DittoBox.EdgeServer.ContainerManagement.Domain.Models.ValueObjects;

namespace DittoBox.EdgeServer.ContainerManagement.Application
{
public class HealthMonitor
{
public SensorType? SensorType { get; set; }
public int FailuresSinceStartup { get; set; }
public int FailuresSinceLastCheck { get; set; }
public int RequestsSinceLastCheck { get; set; }
public int RequestsSinceStartup { get; set; }
public double FailingRate { get; set; }
public DateTime SavedAt { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace DittoBox.EdgeServer.ContainerManagement.Application.Resources
{
public record ContainerRegistrationResource
{
public int Id { get; init; }
public string Uiid { get; init; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using DittoBox.EdgeServer.ContainerManagement.Domain.Models.Entities;

namespace DittoBox.EdgeServer.ContainerManagement.Application.Resources.Outbound
{
public record ContainerMetricsResource
{
public double? Temperature { get; init; }
public double? Humidity { get; init; }
public double? Oxygen { get; init; }
public double? Dioxide { get; init; }
public double? Ethylene { get; init; }
public double? Ammonia { get; init; }
public double? SulfurDioxide { get; init; }

public static ContainerMetricsResource FromContainerStatusRecord(ContainerStatusRecord containerStatusReport)
{
return new ContainerMetricsResource()
{
Temperature = containerStatusReport.Temperature,
Humidity = containerStatusReport.Humidity,
Oxygen = containerStatusReport.GasOxygen,
Dioxide = containerStatusReport.GasCO2,
Ethylene = containerStatusReport.GasEthylene,
Ammonia = containerStatusReport.GasAmmonia,
SulfurDioxide = containerStatusReport.GasSO2
};
}
}
}
5 changes: 3 additions & 2 deletions ContainerManagement/Application/Services/BaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
public abstract class BaseService
{
protected string BaseUrl { get; set; } = "https://app-dev-01-dittobox-a8bpd5bkh4dnh3g7.eastus-01.azurewebsites.net/";
}
protected string BaseUrl { get; set; } = "https://app-prod-01-dittobox-argeesg8era0c7ex.eastus-01.azurewebsites.net/api/v1/";

}
}
Loading