Implement realtime chat

This commit is contained in:
2025-05-25 05:51:13 +08:00
parent 59bc9edd4b
commit 9e7ba820c4
13 changed files with 3849 additions and 33 deletions

View File

@ -1,3 +1,4 @@
using DysonNetwork.Sphere.Chat.Realtime;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -6,16 +7,60 @@ namespace DysonNetwork.Sphere.Chat;
public class RealtimeChatConfiguration
{
public string Provider { get; set; } = null!;
public string Endpoint { get; set; } = null!;
}
[ApiController]
[Route("/chat/realtime")]
public class RealtimeCallController(IConfiguration configuration, AppDatabase db, ChatService cs) : ControllerBase
public class RealtimeCallController(IConfiguration configuration, AppDatabase db, ChatService cs, IRealtimeService realtime) : ControllerBase
{
private readonly RealtimeChatConfiguration _config =
configuration.GetSection("RealtimeChat").Get<RealtimeChatConfiguration>()!;
[HttpGet("{roomId:guid}/join")]
[Authorize]
public async Task<IActionResult> JoinCall(Guid roomId)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
// Check if the user is a member of the chat room
var member = await db.ChatMembers
.Where(m => m.AccountId == currentUser.Id && m.ChatRoomId == roomId)
.FirstOrDefaultAsync();
if (member == null || member.Role < ChatMemberRole.Member)
return StatusCode(403, "You need to be a member to join a call.");
// Get ongoing call
var ongoingCall = await cs.GetCallOngoingAsync(roomId);
if (ongoingCall is null)
return NotFound("There is no ongoing call in this room.");
// Check if session ID exists
if (string.IsNullOrEmpty(ongoingCall.SessionId))
return BadRequest("Call session is not properly configured.");
var isAdmin = member.Role >= ChatMemberRole.Moderator;
var userToken = realtime.GetUserToken(currentUser, ongoingCall.SessionId, isAdmin);
// Get LiveKit endpoint from configuration
string endpoint = _config.Endpoint ??
throw new InvalidOperationException("LiveKit endpoint configuration is missing");
// Create response model
var response = new JoinCallResponse
{
Provider = realtime.ProviderName,
Endpoint = endpoint,
Token = userToken,
CallId = ongoingCall.Id,
RoomName = ongoingCall.SessionId,
IsAdmin = isAdmin
};
return Ok(response);
}
[HttpPost("{roomId:guid}")]
[Authorize]
public async Task<IActionResult> StartCall(Guid roomId)
@ -57,4 +102,38 @@ public class RealtimeCallController(IConfiguration configuration, AppDatabase db
return BadRequest(exception.Message);
}
}
}
// Response model for joining a call
public class JoinCallResponse
{
/// <summary>
/// The service provider name (e.g., "LiveKit")
/// </summary>
public string Provider { get; set; } = null!;
/// <summary>
/// The LiveKit server endpoint
/// </summary>
public string Endpoint { get; set; } = null!;
/// <summary>
/// Authentication token for the user
/// </summary>
public string Token { get; set; } = null!;
/// <summary>
/// The call identifier
/// </summary>
public Guid CallId { get; set; }
/// <summary>
/// The room name in LiveKit
/// </summary>
public string RoomName { get; set; } = null!;
/// <summary>
/// Whether the user is the admin of the call
/// </summary>
public bool IsAdmin { get; set; }
}