Skip to content

Commit

Permalink
Fetch media config from ISAR with API call
Browse files Browse the repository at this point in the history
  • Loading branch information
andchiind committed Dec 3, 2024
1 parent 4915b7a commit 772193a
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 64 deletions.
12 changes: 12 additions & 0 deletions backend/api.test/Mocks/IsarServiceMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,17 @@ public async Task<IsarMission> StartMoveArm(Robot robot, string position)
);
return isarServiceMissionResponse;
}

public async Task<MediaConfig> GetMediaStreamConfig(Robot robot)
{
await Task.Run(() => Thread.Sleep(1));
return new MediaConfig
{
Url = "mockURL",
Token = "mockToken",
RobotId = robot.Id,
MediaConnectionType = MediaConnectionType.LiveKit
};
}
}
}
51 changes: 51 additions & 0 deletions backend/api/Controllers/MediaStreamController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Api.Controllers.Models;
using Api.Services;
using Api.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Api.Controllers
{
[ApiController]
[Route("media-stream")]
public class MediaStreamController(
ILogger<MediaStreamController> logger,
IIsarService isarService,
IRobotService robotService
) : ControllerBase
{
/// <summary>
/// Request the config for a new media stream connection from ISAR
/// </summary>
/// <remarks>
/// <para> This query gets a new media stream connection config from ISAR </para>
/// </remarks>
[HttpGet]
[Authorize(Roles = Role.Any)]
[Route("{id}")]
[ProducesResponseType(typeof(MediaConfig), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<MediaConfig>> GetMediaStreamConfig([FromRoute] string id)
{
try
{
var robot = await robotService.ReadById(id);
if (robot == null)
{
return NotFound($"Could not find robot with ID {id}");
}

var config = await isarService.GetMediaStreamConfig(robot);
return Ok(config);
}
catch (Exception e)
{
logger.LogError(e, "Error during GET of media stream config from ISAR");
throw;
}
}
}
}
22 changes: 0 additions & 22 deletions backend/api/EventHandlers/MqttEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ public override void Subscribe()
MqttService.MqttIsarPressureReceived += OnIsarPressureUpdate;
MqttService.MqttIsarPoseReceived += OnIsarPoseUpdate;
MqttService.MqttIsarCloudHealthReceived += OnIsarCloudHealthUpdate;
MqttService.MqttIsarMediaConfigReceived += OnIsarMediaConfigUpdate;
}

public override void Unsubscribe()
Expand All @@ -72,7 +71,6 @@ public override void Unsubscribe()
MqttService.MqttIsarPressureReceived -= OnIsarPressureUpdate;
MqttService.MqttIsarPoseReceived -= OnIsarPoseUpdate;
MqttService.MqttIsarCloudHealthReceived -= OnIsarCloudHealthUpdate;
MqttService.MqttIsarMediaConfigReceived -= OnIsarMediaConfigUpdate;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await stoppingToken; }
Expand Down Expand Up @@ -538,25 +536,5 @@ private async void OnIsarCloudHealthUpdate(object? sender, MqttReceivedArgs mqtt

TeamsMessageService.TriggerTeamsMessageReceived(new TeamsMessageEventArgs(message));
}

private async void OnIsarMediaConfigUpdate(object? sender, MqttReceivedArgs mqttArgs)
{
var isarTelemetyUpdate = (IsarMediaConfigMessage)mqttArgs.Message;

var robot = await RobotService.ReadByIsarId(isarTelemetyUpdate.IsarId);
if (robot == null)
{
_logger.LogInformation("Received message from unknown ISAR instance {Id} with robot name {Name}", isarTelemetyUpdate.IsarId, isarTelemetyUpdate.RobotName);
return;
}
await SignalRService.SendMessageAsync("Media stream config received", robot.CurrentInstallation,
new MediaConfig
{
Url = isarTelemetyUpdate.Url,
Token = isarTelemetyUpdate.Token,
RobotId = robot.Id,
MediaConnectionType = isarTelemetyUpdate.MediaConnectionType
});
}
}
}
25 changes: 0 additions & 25 deletions backend/api/MQTT/MessageModels/IsarMediaConfig.cs

This file was deleted.

5 changes: 0 additions & 5 deletions backend/api/MQTT/MqttService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ public MqttService(ILogger<MqttService> logger, IConfiguration config)
public static event EventHandler<MqttReceivedArgs>? MqttIsarPressureReceived;
public static event EventHandler<MqttReceivedArgs>? MqttIsarPoseReceived;
public static event EventHandler<MqttReceivedArgs>? MqttIsarCloudHealthReceived;
public static event EventHandler<MqttReceivedArgs>? MqttIsarMediaConfigReceived;

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Expand Down Expand Up @@ -153,9 +152,6 @@ private Task OnMessageReceived(MqttApplicationMessageReceivedEventArgs messageRe
case Type type when type == typeof(IsarCloudHealthMessage):
OnIsarTopicReceived<IsarCloudHealthMessage>(content);
break;
case Type type when type == typeof(IsarMediaConfigMessage):
OnIsarTopicReceived<IsarMediaConfigMessage>(content);
break;
default:
_logger.LogWarning(
"No callback defined for MQTT message type '{type}'",
Expand Down Expand Up @@ -305,7 +301,6 @@ private void OnIsarTopicReceived<T>(string content) where T : MqttMessage
_ when type == typeof(IsarPressureMessage) => MqttIsarPressureReceived,
_ when type == typeof(IsarPoseMessage) => MqttIsarPoseReceived,
_ when type == typeof(IsarCloudHealthMessage) => MqttIsarCloudHealthReceived,
_ when type == typeof(IsarMediaConfigMessage) => MqttIsarMediaConfigReceived,
_
=> throw new NotImplementedException(
$"No event defined for message type '{typeof(T).Name}'"
Expand Down
3 changes: 0 additions & 3 deletions backend/api/MQTT/MqttTopics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ public static class MqttTopics
},
{
"isar/+/cloud_health", typeof(IsarCloudHealthMessage)
},
{
"isar/+/media_config", typeof(IsarMediaConfigMessage)
}
};

Expand Down
62 changes: 62 additions & 0 deletions backend/api/Services/IsarService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public interface IIsarService
public Task<IsarControlMissionResponse> ResumeMission(Robot robot);

public Task<IsarMission> StartMoveArm(Robot robot, string armPosition);

public Task<MediaConfig> GetMediaStreamConfig(Robot robot);
}

public class IsarService(IDownstreamApi isarApi, ILogger<IsarService> logger) : IIsarService
Expand Down Expand Up @@ -275,5 +277,65 @@ private static (string, int) GetErrorDescriptionFoFailedIsarRequest(HttpResponse

return (description, (int)statusCode);
}

public async Task<MediaConfig> GetMediaStreamConfig(Robot robot)
{
string mediaStreamPath = $"/media/media-stream-config";
var response = await CallApi(
HttpMethod.Get,
robot.IsarUri,
mediaStreamPath
);

if (!response.IsSuccessStatusCode)
{
(string message, _) = GetErrorDescriptionFoFailedIsarRequest(response);
string errorResponse = await response.Content.ReadAsStringAsync();
logger.LogError("{Message}: {ErrorResponse}", message, errorResponse);
throw new ConfigException(message);
}
if (response.Content is null)
{
string errorMessage = "Could not read content from new robot media stream config";
logger.LogError("{ErrorMessage}", errorMessage);
throw new ConfigException(errorMessage);
}

IsarMediaConfigMessage? isarMediaConfigResponse;
try
{
isarMediaConfigResponse = await response.Content.ReadFromJsonAsync<IsarMediaConfigMessage>();
}
catch (JsonException)
{
string errorMessage = $"Could not parse content from new robot media stream config. {await response.Content.ReadAsStringAsync()}";
logger.LogError("{ErrorMessage}", errorMessage);
throw new ConfigException(errorMessage);
}

if (isarMediaConfigResponse == null)
{
string errorMessage = $"Parsing of robot media stream config resulted in empty config. {await response.Content.ReadAsStringAsync()}";
logger.LogError("{ErrorMessage}", errorMessage);
throw new ConfigException(errorMessage);
}

bool parseSuccess = Enum.TryParse(isarMediaConfigResponse.MediaConnectionType, out MediaConnectionType connectionType);

if (!parseSuccess)
{
string errorMessage = $"Could not parse connection type from new robot media stream config. {isarMediaConfigResponse.MediaConnectionType}";
logger.LogError("{ErrorMessage}", errorMessage);
throw new ConfigException(errorMessage);
}

return new MediaConfig
{
Url = isarMediaConfigResponse.Url,
Token = isarMediaConfigResponse.Token,
RobotId = robot.Id,
MediaConnectionType = connectionType
};
}
}
}
18 changes: 18 additions & 0 deletions backend/api/Services/Models/IsarMediaConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;

namespace Api.Services.Models
{
#nullable disable
public class IsarMediaConfigMessage
{
[JsonPropertyName("url")]
public string Url { get; set; }

[JsonPropertyName("token")]
public string Token { get; set; }

[JsonPropertyName("media_connection_type")]
public string MediaConnectionType { get; set; }

}
}
10 changes: 1 addition & 9 deletions backend/api/Services/Models/MediaConfig.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
using System.Text.Json.Serialization;
namespace Api.Services.Models
namespace Api.Services.Models
{
public struct MediaConfig
{
[JsonPropertyName("url")]
public string? Url { get; set; }

[JsonPropertyName("token")]
public string? Token { get; set; }

[JsonPropertyName("robotId")]
public string? RobotId { get; set; }

[JsonPropertyName("mediaConnectionType")]
public MediaConnectionType MediaConnectionType { get; set; }
}

Expand Down

0 comments on commit 772193a

Please sign in to comment.