Skip to content

Commit 772193a

Browse files
committed
Fetch media config from ISAR with API call
1 parent 4915b7a commit 772193a

File tree

9 files changed

+144
-64
lines changed

9 files changed

+144
-64
lines changed

backend/api.test/Mocks/IsarServiceMock.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,17 @@ public async Task<IsarMission> StartMoveArm(Robot robot, string position)
5151
);
5252
return isarServiceMissionResponse;
5353
}
54+
55+
public async Task<MediaConfig> GetMediaStreamConfig(Robot robot)
56+
{
57+
await Task.Run(() => Thread.Sleep(1));
58+
return new MediaConfig
59+
{
60+
Url = "mockURL",
61+
Token = "mockToken",
62+
RobotId = robot.Id,
63+
MediaConnectionType = MediaConnectionType.LiveKit
64+
};
65+
}
5466
}
5567
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Api.Controllers.Models;
2+
using Api.Services;
3+
using Api.Services.Models;
4+
using Microsoft.AspNetCore.Authorization;
5+
using Microsoft.AspNetCore.Mvc;
6+
7+
namespace Api.Controllers
8+
{
9+
[ApiController]
10+
[Route("media-stream")]
11+
public class MediaStreamController(
12+
ILogger<MediaStreamController> logger,
13+
IIsarService isarService,
14+
IRobotService robotService
15+
) : ControllerBase
16+
{
17+
/// <summary>
18+
/// Request the config for a new media stream connection from ISAR
19+
/// </summary>
20+
/// <remarks>
21+
/// <para> This query gets a new media stream connection config from ISAR </para>
22+
/// </remarks>
23+
[HttpGet]
24+
[Authorize(Roles = Role.Any)]
25+
[Route("{id}")]
26+
[ProducesResponseType(typeof(MediaConfig), StatusCodes.Status200OK)]
27+
[ProducesResponseType(StatusCodes.Status400BadRequest)]
28+
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
29+
[ProducesResponseType(StatusCodes.Status403Forbidden)]
30+
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
31+
public async Task<ActionResult<MediaConfig>> GetMediaStreamConfig([FromRoute] string id)
32+
{
33+
try
34+
{
35+
var robot = await robotService.ReadById(id);
36+
if (robot == null)
37+
{
38+
return NotFound($"Could not find robot with ID {id}");
39+
}
40+
41+
var config = await isarService.GetMediaStreamConfig(robot);
42+
return Ok(config);
43+
}
44+
catch (Exception e)
45+
{
46+
logger.LogError(e, "Error during GET of media stream config from ISAR");
47+
throw;
48+
}
49+
}
50+
}
51+
}

backend/api/EventHandlers/MqttEventHandler.cs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ public override void Subscribe()
5959
MqttService.MqttIsarPressureReceived += OnIsarPressureUpdate;
6060
MqttService.MqttIsarPoseReceived += OnIsarPoseUpdate;
6161
MqttService.MqttIsarCloudHealthReceived += OnIsarCloudHealthUpdate;
62-
MqttService.MqttIsarMediaConfigReceived += OnIsarMediaConfigUpdate;
6362
}
6463

6564
public override void Unsubscribe()
@@ -72,7 +71,6 @@ public override void Unsubscribe()
7271
MqttService.MqttIsarPressureReceived -= OnIsarPressureUpdate;
7372
MqttService.MqttIsarPoseReceived -= OnIsarPoseUpdate;
7473
MqttService.MqttIsarCloudHealthReceived -= OnIsarCloudHealthUpdate;
75-
MqttService.MqttIsarMediaConfigReceived -= OnIsarMediaConfigUpdate;
7674
}
7775

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

539537
TeamsMessageService.TriggerTeamsMessageReceived(new TeamsMessageEventArgs(message));
540538
}
541-
542-
private async void OnIsarMediaConfigUpdate(object? sender, MqttReceivedArgs mqttArgs)
543-
{
544-
var isarTelemetyUpdate = (IsarMediaConfigMessage)mqttArgs.Message;
545-
546-
var robot = await RobotService.ReadByIsarId(isarTelemetyUpdate.IsarId);
547-
if (robot == null)
548-
{
549-
_logger.LogInformation("Received message from unknown ISAR instance {Id} with robot name {Name}", isarTelemetyUpdate.IsarId, isarTelemetyUpdate.RobotName);
550-
return;
551-
}
552-
await SignalRService.SendMessageAsync("Media stream config received", robot.CurrentInstallation,
553-
new MediaConfig
554-
{
555-
Url = isarTelemetyUpdate.Url,
556-
Token = isarTelemetyUpdate.Token,
557-
RobotId = robot.Id,
558-
MediaConnectionType = isarTelemetyUpdate.MediaConnectionType
559-
});
560-
}
561539
}
562540
}

backend/api/MQTT/MessageModels/IsarMediaConfig.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

backend/api/MQTT/MqttService.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ public MqttService(ILogger<MqttService> logger, IConfiguration config)
9191
public static event EventHandler<MqttReceivedArgs>? MqttIsarPressureReceived;
9292
public static event EventHandler<MqttReceivedArgs>? MqttIsarPoseReceived;
9393
public static event EventHandler<MqttReceivedArgs>? MqttIsarCloudHealthReceived;
94-
public static event EventHandler<MqttReceivedArgs>? MqttIsarMediaConfigReceived;
9594

9695
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
9796
{
@@ -153,9 +152,6 @@ private Task OnMessageReceived(MqttApplicationMessageReceivedEventArgs messageRe
153152
case Type type when type == typeof(IsarCloudHealthMessage):
154153
OnIsarTopicReceived<IsarCloudHealthMessage>(content);
155154
break;
156-
case Type type when type == typeof(IsarMediaConfigMessage):
157-
OnIsarTopicReceived<IsarMediaConfigMessage>(content);
158-
break;
159155
default:
160156
_logger.LogWarning(
161157
"No callback defined for MQTT message type '{type}'",
@@ -305,7 +301,6 @@ private void OnIsarTopicReceived<T>(string content) where T : MqttMessage
305301
_ when type == typeof(IsarPressureMessage) => MqttIsarPressureReceived,
306302
_ when type == typeof(IsarPoseMessage) => MqttIsarPoseReceived,
307303
_ when type == typeof(IsarCloudHealthMessage) => MqttIsarCloudHealthReceived,
308-
_ when type == typeof(IsarMediaConfigMessage) => MqttIsarMediaConfigReceived,
309304
_
310305
=> throw new NotImplementedException(
311306
$"No event defined for message type '{typeof(T).Name}'"

backend/api/MQTT/MqttTopics.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ public static class MqttTopics
4242
},
4343
{
4444
"isar/+/cloud_health", typeof(IsarCloudHealthMessage)
45-
},
46-
{
47-
"isar/+/media_config", typeof(IsarMediaConfigMessage)
4845
}
4946
};
5047

backend/api/Services/IsarService.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public interface IIsarService
1717
public Task<IsarControlMissionResponse> ResumeMission(Robot robot);
1818

1919
public Task<IsarMission> StartMoveArm(Robot robot, string armPosition);
20+
21+
public Task<MediaConfig> GetMediaStreamConfig(Robot robot);
2022
}
2123

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

276278
return (description, (int)statusCode);
277279
}
280+
281+
public async Task<MediaConfig> GetMediaStreamConfig(Robot robot)
282+
{
283+
string mediaStreamPath = $"/media/media-stream-config";
284+
var response = await CallApi(
285+
HttpMethod.Get,
286+
robot.IsarUri,
287+
mediaStreamPath
288+
);
289+
290+
if (!response.IsSuccessStatusCode)
291+
{
292+
(string message, _) = GetErrorDescriptionFoFailedIsarRequest(response);
293+
string errorResponse = await response.Content.ReadAsStringAsync();
294+
logger.LogError("{Message}: {ErrorResponse}", message, errorResponse);
295+
throw new ConfigException(message);
296+
}
297+
if (response.Content is null)
298+
{
299+
string errorMessage = "Could not read content from new robot media stream config";
300+
logger.LogError("{ErrorMessage}", errorMessage);
301+
throw new ConfigException(errorMessage);
302+
}
303+
304+
IsarMediaConfigMessage? isarMediaConfigResponse;
305+
try
306+
{
307+
isarMediaConfigResponse = await response.Content.ReadFromJsonAsync<IsarMediaConfigMessage>();
308+
}
309+
catch (JsonException)
310+
{
311+
string errorMessage = $"Could not parse content from new robot media stream config. {await response.Content.ReadAsStringAsync()}";
312+
logger.LogError("{ErrorMessage}", errorMessage);
313+
throw new ConfigException(errorMessage);
314+
}
315+
316+
if (isarMediaConfigResponse == null)
317+
{
318+
string errorMessage = $"Parsing of robot media stream config resulted in empty config. {await response.Content.ReadAsStringAsync()}";
319+
logger.LogError("{ErrorMessage}", errorMessage);
320+
throw new ConfigException(errorMessage);
321+
}
322+
323+
bool parseSuccess = Enum.TryParse(isarMediaConfigResponse.MediaConnectionType, out MediaConnectionType connectionType);
324+
325+
if (!parseSuccess)
326+
{
327+
string errorMessage = $"Could not parse connection type from new robot media stream config. {isarMediaConfigResponse.MediaConnectionType}";
328+
logger.LogError("{ErrorMessage}", errorMessage);
329+
throw new ConfigException(errorMessage);
330+
}
331+
332+
return new MediaConfig
333+
{
334+
Url = isarMediaConfigResponse.Url,
335+
Token = isarMediaConfigResponse.Token,
336+
RobotId = robot.Id,
337+
MediaConnectionType = connectionType
338+
};
339+
}
278340
}
279341
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Api.Services.Models
4+
{
5+
#nullable disable
6+
public class IsarMediaConfigMessage
7+
{
8+
[JsonPropertyName("url")]
9+
public string Url { get; set; }
10+
11+
[JsonPropertyName("token")]
12+
public string Token { get; set; }
13+
14+
[JsonPropertyName("media_connection_type")]
15+
public string MediaConnectionType { get; set; }
16+
17+
}
18+
}

backend/api/Services/Models/MediaConfig.cs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1-
using System.Text.Json.Serialization;
2-
namespace Api.Services.Models
1+
namespace Api.Services.Models
32
{
43
public struct MediaConfig
54
{
6-
[JsonPropertyName("url")]
75
public string? Url { get; set; }
8-
9-
[JsonPropertyName("token")]
106
public string? Token { get; set; }
11-
12-
[JsonPropertyName("robotId")]
137
public string? RobotId { get; set; }
14-
15-
[JsonPropertyName("mediaConnectionType")]
168
public MediaConnectionType MediaConnectionType { get; set; }
179
}
1810

0 commit comments

Comments
 (0)