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

VIH-9129 Multi participants linked to a single JVS endpoint #2152

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
31 changes: 11 additions & 20 deletions VideoWeb/VideoWeb.Common/Caching/ConferenceCache.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,36 @@
using System;
using System.Threading.Tasks;
using BookingsApi.Contract.V2.Responses;
using Microsoft.Extensions.Caching.Memory;
using VideoWeb.Common.Models;
using VideoApi.Contract.Responses;

namespace VideoWeb.Common.Caching
{
public class ConferenceCache : IConferenceCache
public class ConferenceCache(IMemoryCache memoryCache) : IConferenceCache
{
private readonly IMemoryCache _memoryCache;

public ConferenceCache(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}

public async Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse)
public async Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse, HearingDetailsResponseV2 hearingDetailsResponse)
{
var conference = ConferenceCacheMapper.MapConferenceToCacheModel(conferenceResponse);
var conference = ConferenceCacheMapper.MapConferenceToCacheModel(conferenceResponse, hearingDetailsResponse);
await UpdateConferenceAsync(conference);
}

public async Task UpdateConferenceAsync(Conference conference)
{
await _memoryCache.GetOrCreateAsync(conference.Id, entry =>
await memoryCache.GetOrCreateAsync(conference.Id, entry =>
{
entry.SlidingExpiration = TimeSpan.FromHours(4);
return Task.FromResult(conference);
});
}

public async Task<Conference> GetOrAddConferenceAsync(Guid id, Func<Task<ConferenceDetailsResponse>> addConferenceDetailsFactory)
public async Task<Conference> GetOrAddConferenceAsync(Guid id, Func<Task<(ConferenceDetailsResponse, HearingDetailsResponseV2)>> addConferenceDetailsFactory)
{
var conference = await Task.FromResult(_memoryCache.Get<Conference>(id));

var conference = await Task.FromResult(memoryCache.Get<Conference>(id));
if (conference != null) return conference;

var conferenceDetails = await addConferenceDetailsFactory();
await AddConferenceAsync(conferenceDetails);
conference = await Task.FromResult(_memoryCache.Get<Conference>(id));

var (conferenceDetails, hearingDetailsResponse) = await addConferenceDetailsFactory();
await AddConferenceAsync(conferenceDetails, hearingDetailsResponse);
conference = await Task.FromResult(memoryCache.Get<Conference>(id));
return conference;
}
}
Expand Down
40 changes: 35 additions & 5 deletions VideoWeb/VideoWeb.Common/Caching/ConferenceCacheMapper.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BookingsApi.Contract.V2.Responses;
using VideoWeb.Common.Models;
using VideoApi.Contract.Responses;

namespace VideoWeb.Common.Caching
{
public static class ConferenceCacheMapper
{
public static Conference MapConferenceToCacheModel(ConferenceDetailsResponse conferenceResponse)
public static Conference MapConferenceToCacheModel(ConferenceDetailsResponse conferenceResponse, HearingDetailsResponseV2 hearingDetailsResponse)
{
var participants = conferenceResponse
.Participants
Expand All @@ -18,12 +19,29 @@ public static Conference MapConferenceToCacheModel(ConferenceDetailsResponse con
var endpoints = conferenceResponse.Endpoints == null
? new List<Endpoint>()
: conferenceResponse.Endpoints.Select(EndpointCacheMapper.MapEndpointToCacheModel).ToList();

foreach (var endpoint in endpoints)
{
endpoint.EndpointParticipants = hearingDetailsResponse.Endpoints
.Single(x => x.Id == endpoint.Id).EndpointParticipants?
.Select(x => EndpointParticipantCacheMapper.MapEndpointParticipantToCacheModel(x, participants))
.ToList();
}

var civilianRooms = conferenceResponse.CivilianRooms == null
? new List<CivilianRoom>()
: conferenceResponse.CivilianRooms.Select(CivilianRoomCacheMapper.MapCivilianRoomToCacheModel)
.ToList();

var meetingRoom = conferenceResponse.MeetingRoom == null
? null
: new ConferenceMeetingRoom
{
ParticipantUri = conferenceResponse.MeetingRoom.ParticipantUri,
PexipNode = conferenceResponse.MeetingRoom.PexipNode,
PexipSelfTest = conferenceResponse.MeetingRoom.PexipSelfTestNode,
};

var conference = new Conference
{
Id = conferenceResponse.Id,
Expand All @@ -32,15 +50,25 @@ public static Conference MapConferenceToCacheModel(ConferenceDetailsResponse con
HearingVenueName = conferenceResponse.HearingVenueName,
Endpoints = endpoints,
CivilianRooms = civilianRooms,
CurrentStatus = conferenceResponse.CurrentStatus
CurrentStatus = conferenceResponse.CurrentStatus,
IsWaitingRoomOpen = conferenceResponse.IsWaitingRoomOpen,
CaseName = conferenceResponse.CaseName,
CaseNumber = conferenceResponse.CaseNumber,
CaseType = conferenceResponse.CaseType,
ScheduledDateTime = conferenceResponse.ScheduledDateTime,
ScheduledDuration = conferenceResponse.ScheduledDuration,
ClosedDateTime = conferenceResponse.ClosedDateTime,
AudioRecordingRequired = conferenceResponse.AudioRecordingRequired,
IsScottish = conferenceResponse.HearingVenueIsScottish,
IngestUrl = conferenceResponse.IngestUrl,
MeetingRoom = meetingRoom
};
return conference;
}

private static Participant MapParticipantToCacheModel(ParticipantDetailsResponse participant)
{
var links = (participant.LinkedParticipants ?? new List<LinkedParticipantResponse>())
.Select(MapLinkedParticipantToCacheModel).ToList();
var links = (participant.LinkedParticipants ?? new List<LinkedParticipantResponse>()).Select(MapLinkedParticipantToCacheModel).ToList();
return new Participant
{
Id = participant.Id,
Expand All @@ -57,7 +85,9 @@ private static Participant MapParticipantToCacheModel(ParticipantDetailsResponse
Username = participant.Username,
CaseTypeGroup = participant.CaseTypeGroup,
Representee = participant.Representee,
LinkedParticipants = links
LinkedParticipants = links,
CurrentRoom = RoomCacheMapper.Map(participant.CurrentRoom),
InterpreterRoom = RoomCacheMapper.Map(participant.CurrentInterpreterRoom)
};
}

Expand Down
17 changes: 12 additions & 5 deletions VideoWeb/VideoWeb.Common/Caching/DistributedConferenceCache.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using BookingsApi.Contract.V2.Responses;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using VideoWeb.Common.Models;
Expand All @@ -21,23 +22,29 @@ public DistributedConferenceCache(
};
}

public async Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse)
public async Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse, HearingDetailsResponseV2 hearingDetailsResponse)
{
var conference = ConferenceCacheMapper.MapConferenceToCacheModel(conferenceResponse);
var conference = ConferenceCacheMapper.MapConferenceToCacheModel(conferenceResponse, hearingDetailsResponse);
await UpdateConferenceAsync(conference);
}


public Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse)
{
throw new NotImplementedException();
}

public async Task UpdateConferenceAsync(Conference conference)
{
await WriteToCache(conference.Id, conference);
}

public async Task<Conference> GetOrAddConferenceAsync(Guid id, Func<Task<ConferenceDetailsResponse>> addConferenceDetailsFactory)
public async Task<Conference> GetOrAddConferenceAsync(Guid id, Func<Task<(ConferenceDetailsResponse, HearingDetailsResponseV2)>> addConferenceDetailsFactory)
{
var conference = await ReadFromCache(id);

if (conference != null) return conference;
conference = ConferenceCacheMapper.MapConferenceToCacheModel(await addConferenceDetailsFactory());
var (conferenceResponse, hearingDetailsResponse) = await addConferenceDetailsFactory();
conference = ConferenceCacheMapper.MapConferenceToCacheModel(conferenceResponse, hearingDetailsResponse);

await WriteToCache(id, conference);

Expand Down
21 changes: 18 additions & 3 deletions VideoWeb/VideoWeb.Common/Caching/EndpointCacheMapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BookingsApi.Contract.V2.Responses;
using VideoWeb.Common.Models;
using VideoApi.Contract.Responses;

Expand All @@ -12,9 +15,21 @@ public static Endpoint MapEndpointToCacheModel(EndpointResponse endpointResponse
{
Id = endpointResponse.Id,
DisplayName = endpointResponse.DisplayName,
EndpointStatus =
(EndpointStatus) Enum.Parse(typeof(EndpointStatus), endpointResponse.Status.ToString()),
DefenceAdvocateUsername = endpointResponse.DefenceAdvocate?.ToLower().Trim()
EndpointStatus = (EndpointStatus) Enum.Parse(typeof(EndpointStatus), endpointResponse.Status.ToString()),
};
}
}

public static class EndpointParticipantCacheMapper
{
public static EndpointParticipant MapEndpointParticipantToCacheModel(EndpointParticipantResponse endpointParticipantResponse, IList<Participant> participants)
{
return new EndpointParticipant
{
ParticipantId = participants.Single(x => x.RefId == endpointParticipantResponse.ParticipantId).Id,
ParticipantRefId = endpointParticipantResponse.ParticipantId,
ParticipantUsername = participants.Single(x => x.RefId == endpointParticipantResponse.ParticipantId).Username,
LinkedParticipantType = Enum.Parse<LinkType>(endpointParticipantResponse.LinkedParticipantType.ToString())
};
}
}
Expand Down
5 changes: 3 additions & 2 deletions VideoWeb/VideoWeb.Common/Caching/IConferenceCache.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System;
using System.Threading.Tasks;
using BookingsApi.Contract.V2.Responses;
using VideoWeb.Common.Models;
using VideoApi.Contract.Responses;

namespace VideoWeb.Common.Caching
{
public interface IConferenceCache
{
Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse);
Task AddConferenceAsync(ConferenceDetailsResponse conferenceResponse, HearingDetailsResponseV2 hearingDetailsResponse);
Task UpdateConferenceAsync(Conference conference);
Task <Conference>GetOrAddConferenceAsync(Guid id, Func<Task<ConferenceDetailsResponse>> addConferenceDetailsFactory);
Task <Conference> GetOrAddConferenceAsync(Guid id, Func<Task<(ConferenceDetailsResponse, HearingDetailsResponseV2)>> addConferenceDetailsFactory);
}
}
20 changes: 20 additions & 0 deletions VideoWeb/VideoWeb.Common/Caching/RoomCacheMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using VideoApi.Contract.Responses;
using VideoWeb.Common.Models;

namespace VideoWeb.Common.Caching;

public static class RoomCacheMapper
{
public static ParticipantMeetingRoom Map(RoomResponse roomResponse)
{
if(roomResponse == null)
return null;

return new ParticipantMeetingRoom
{
Id = roomResponse.Id,
Label = roomResponse.Label,
Locked = roomResponse.Locked
};
}
}
52 changes: 52 additions & 0 deletions VideoWeb/VideoWeb.Common/ConferenceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Threading.Tasks;
using BookingsApi.Client;
using BookingsApi.Contract.V2.Responses;
using VideoApi.Client;
using VideoApi.Contract.Responses;
using VideoWeb.Common.Caching;
using VideoWeb.Common.Models;

namespace VideoWeb.Common;

public interface IConferenceService
{
public Task<Conference> GetConference(Guid conferenceId);
public Task<Conference> ForceGetConference(Guid conferenceId);
public IConferenceCache ConferenceCache { get; }
}

public class ConferenceService(
IConferenceCache conferenceCache,
IVideoApiClient videoApiClient,
IBookingsApiClient bookingApiClient)
: IConferenceService
{
public IConferenceCache ConferenceCache { get; } = conferenceCache;

public async Task<Conference> GetConference(Guid conferenceId)
{
var conference = await ConferenceCache.GetOrAddConferenceAsync(conferenceId, ConferenceDetailsCallback);
return conference;

async Task<(ConferenceDetailsResponse conferenceDetails, HearingDetailsResponseV2 hearingDetails)> ConferenceDetailsCallback()
{
var conferenceDetails = await videoApiClient.GetConferenceDetailsByIdAsync(conferenceId);
var hearingDetails = await bookingApiClient.GetHearingDetailsByIdV2Async(conferenceDetails.HearingId);
return (conferenceDetails, hearingDetails);
}
}

/// <summary>
/// Force query of database and update cache
/// </summary>
/// <param name="conferenceId"></param>
/// <returns></returns>
public async Task<Conference> ForceGetConference(Guid conferenceId)
{
var conferenceDetails = await videoApiClient.GetConferenceDetailsByIdAsync(conferenceId);
var hearingDetails = await bookingApiClient.GetHearingDetailsByIdV2Async(conferenceDetails.HearingId);
await ConferenceCache.AddConferenceAsync(conferenceDetails, hearingDetails);
return await GetConference(conferenceId);
}
}
11 changes: 11 additions & 0 deletions VideoWeb/VideoWeb.Common/Models/Conference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ public Conference()
public List<CivilianRoom> CivilianRooms { get; set; }
public string HearingVenueName { get; set; }
public ConferenceState CurrentStatus { get; set; }
public string CaseName { get; set; }
public string CaseNumber { get; set; }
public string CaseType { get; set; }
public DateTime ScheduledDateTime { get; set; }
public int ScheduledDuration { get; set; }
public DateTime? ClosedDateTime { get; set; }
public bool AudioRecordingRequired {get; set; }
public bool IsWaitingRoomOpen { get; set; }
public bool IsScottish { get; set; }
public string IngestUrl { get; set; }
public ConferenceMeetingRoom MeetingRoom { get; set; }

public Participant GetJudge()
{
Expand Down
8 changes: 8 additions & 0 deletions VideoWeb/VideoWeb.Common/Models/ConfernceMeetingRoom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace VideoWeb.Common.Models;

public class ConferenceMeetingRoom
{
public string ParticipantUri { get; set; }
public string PexipNode { get; set; }
public string PexipSelfTest { get; set; }
}
13 changes: 12 additions & 1 deletion VideoWeb/VideoWeb.Common/Models/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using VideoApi.Contract.Responses;

namespace VideoWeb.Common.Models
{
Expand All @@ -7,6 +9,15 @@ public class Endpoint
public Guid Id { get; set; }
public string DisplayName { get; set; }
public EndpointStatus EndpointStatus { get; set; }
public string DefenceAdvocateUsername { get; set; }
public List<EndpointParticipant> EndpointParticipants { get; set; }
public RoomResponse CurrentRoom { get; set; }
}

public class EndpointParticipant
{
public Guid ParticipantId { get; set; }
public Guid ParticipantRefId { get; set; }
public string ParticipantUsername { get; set; }
public LinkType LinkedParticipantType { get; set; }
}
}
5 changes: 4 additions & 1 deletion VideoWeb/VideoWeb.Common/Models/LinkType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ namespace VideoWeb.Common.Models
{
public enum LinkType
{
Interpreter
Interpreter = 1,
DefenceAdvocate = 2,
Representative = 3,
Intermediary = 4
}
}
2 changes: 2 additions & 0 deletions VideoWeb/VideoWeb.Common/Models/Participant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public Participant()
public string CaseTypeGroup { get; set; }
public Guid RefId { get; set; }
public string Representee { get; set; }
public ParticipantMeetingRoom CurrentRoom { get; set; }
public ParticipantMeetingRoom InterpreterRoom { get; set; }

public List<LinkedParticipant> LinkedParticipants { get; set; }

Expand Down
17 changes: 17 additions & 0 deletions VideoWeb/VideoWeb.Common/Models/ParticipantMeetingRoom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace VideoWeb.Common.Models;

public class ParticipantMeetingRoom
{
/// <summary>
/// Room Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// Room label
/// </summary>
public string Label { get; set; }
/// <summary>
/// Is the room locked
/// </summary>
public bool Locked { get; set; }
}
Loading
Loading