The call ended by webhook now sends end message

This commit is contained in:
LittleSheep 2025-05-27 02:16:35 +08:00
parent b913682866
commit c21cdeba74
2 changed files with 45 additions and 19 deletions

View File

@ -15,6 +15,7 @@ public class LivekitRealtimeService : IRealtimeService
private readonly AppDatabase _db; private readonly AppDatabase _db;
private readonly ICacheService _cache; private readonly ICacheService _cache;
private readonly WebSocketService _ws; private readonly WebSocketService _ws;
private readonly ChatService _cs;
private readonly ILogger<LivekitRealtimeService> _logger; private readonly ILogger<LivekitRealtimeService> _logger;
private readonly RoomServiceClient _roomService; private readonly RoomServiceClient _roomService;
@ -26,7 +27,8 @@ public class LivekitRealtimeService : IRealtimeService
ILogger<LivekitRealtimeService> logger, ILogger<LivekitRealtimeService> logger,
AppDatabase db, AppDatabase db,
ICacheService cache, ICacheService cache,
WebSocketService ws WebSocketService ws,
ChatService cs
) )
{ {
_logger = logger; _logger = logger;
@ -46,6 +48,7 @@ public class LivekitRealtimeService : IRealtimeService
_db = db; _db = db;
_cache = cache; _cache = cache;
_ws = ws; _ws = ws;
_cs = cs;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -125,7 +128,8 @@ public class LivekitRealtimeService : IRealtimeService
RoomAdmin = isAdmin, RoomAdmin = isAdmin,
Room = sessionId Room = sessionId
}) })
.WithMetadata(JsonSerializer.Serialize(new Dictionary<string, string> { { "account_id", account.Id.ToString() } })) .WithMetadata(JsonSerializer.Serialize(new Dictionary<string, string>
{ { "account_id", account.Id.ToString() } }))
.WithTtl(TimeSpan.FromHours(1)); .WithTtl(TimeSpan.FromHours(1));
return token.ToJwt(); return token.ToJwt();
} }
@ -139,10 +143,29 @@ public class LivekitRealtimeService : IRealtimeService
{ {
case "room_finished": case "room_finished":
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var call = await _db.ChatRealtimeCall
.Where(c => c.SessionId == evt.Room.Name)
.Include(c => c.Room)
.Include(c => c.Sender)
.FirstOrDefaultAsync();
if (call is not null)
{
await _cs.SendMessageAsync(new Message
{
Type = "call.ended",
ChatRoomId = call.RoomId,
SenderId = call.SenderId,
Meta = new Dictionary<string, object>
{
{ "call_id", call.Id },
{ "duration", (call.EndedAt!.Value - call.CreatedAt).TotalSeconds }
}
}, call.Sender, call.Room);
await _db.ChatRealtimeCall await _db.ChatRealtimeCall
.Where(c => c.SessionId == evt.Room.Name) .Where(c => c.SessionId == evt.Room.Name)
.ExecuteUpdateAsync(s => s.SetProperty(p => p.EndedAt, now) .ExecuteUpdateAsync(s => s.SetProperty(p => p.EndedAt, now)
); );
}
// Also clean up participants list when the room is finished // Also clean up participants list when the room is finished
await _cache.RemoveAsync(_GetParticipantsKey(evt.Room.Name)); await _cache.RemoveAsync(_GetParticipantsKey(evt.Room.Name));
@ -160,6 +183,7 @@ public class LivekitRealtimeService : IRealtimeService
// Broadcast participant list update to all participants // Broadcast participant list update to all participants
await _BroadcastParticipantUpdate(evt.Room.Name); await _BroadcastParticipantUpdate(evt.Room.Name);
} }
break; break;
case "participant_left": case "participant_left":
@ -174,6 +198,7 @@ public class LivekitRealtimeService : IRealtimeService
// Broadcast participant list update to all participants // Broadcast participant list update to all participants
await _BroadcastParticipantUpdate(evt.Room.Name); await _BroadcastParticipantUpdate(evt.Room.Name);
} }
break; break;
} }
} }

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAccessToken_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb370f448e9f5fca62da785172d83a214319335e27ac4d51840349c6dce15d68_003FAccessToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApnSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003Fc5_003F2a1973a9_003FApnSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApnSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003Fc5_003F2a1973a9_003FApnSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationMiddleware_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003F2f_003F7ab1cc57_003FAuthenticationMiddleware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationMiddleware_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003F2f_003F7ab1cc57_003FAuthenticationMiddleware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationSchemeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003Ff0_003F595b6eda_003FAuthenticationSchemeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationSchemeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe49de78932194d52a02b07486c6d023a24600_003Ff0_003F595b6eda_003FAuthenticationSchemeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>