Files
Swarm/DysonNetwork.Sphere/Connection/WebsocketHandler.cs
2025-07-18 16:12:34 +08:00

129 lines
4.1 KiB
C#

using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Sphere.Chat;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
namespace DysonNetwork.Sphere.Connection;
public class WebSocketHandlerGrpc(PusherService.PusherServiceClient pusher, ChatRoomService crs)
: PusherHandlerService.PusherHandlerServiceBase
{
public override async Task<Empty> ReceiveWebSocketPacket(
ReceiveWebSocketPacketRequest request,
ServerCallContext context
)
{
switch (request.Packet.Type)
{
case "messages.read":
await HandleMessageRead(request, context);
break;
case "messages.typing":
await HandleMessageTyping(request, context);
break;
}
return new Empty();
}
private async Task HandleMessageRead(ReceiveWebSocketPacketRequest request, ServerCallContext context)
{
var currentUser = request.Account;
var packet = request.Packet;
if (packet.Data == null)
{
await SendErrorResponse(request,
"Mark message as read requires you to provide the ChatRoomId and MessageId");
return;
}
var requestData = GrpcTypeHelper.ConvertValueToClass<ChatController.MarkMessageReadRequest>(packet.Data);
if (requestData == null)
{
await SendErrorResponse(request, "Invalid request data");
return;
}
var sender = await crs.GetRoomMember(
Guid.Parse(currentUser.Id),
requestData.ChatRoomId
);
if (sender == null)
{
await SendErrorResponse(request, "User is not a member of the chat room.");
return;
}
var readReceipt = new MessageReadReceipt { SenderId = sender.Id };
var bufferService = context.GetHttpContext().RequestServices.GetRequiredService<FlushBufferService>();
bufferService.Enqueue(readReceipt);
}
private async Task HandleMessageTyping(ReceiveWebSocketPacketRequest request, ServerCallContext context)
{
var currentUser = request.Account;
var packet = request.Packet;
if (packet.Data == null)
{
await SendErrorResponse(request, "messages.typing requires you to provide the ChatRoomId");
return;
}
var requestData = GrpcTypeHelper.ConvertValueToClass<ChatController.ChatRoomWsUniversalRequest>(packet.Data);
if (requestData == null)
{
await SendErrorResponse(request, "Invalid request data");
return;
}
var sender = await crs.GetRoomMember(
Guid.Parse(currentUser.Id),
requestData.ChatRoomId
);
if (sender == null)
{
await SendErrorResponse(request, "User is not a member of the chat room.");
return;
}
var responsePacket = new WebSocketPacket
{
Type = "messages.typing",
Data = GrpcTypeHelper.ConvertObjectToValue(new
{
room_id = sender.ChatRoomId,
sender_id = sender.Id,
sender = sender
})
};
// Broadcast typing indicator to other room members
var otherMembers = (await crs.ListRoomMembers(requestData.ChatRoomId))
.Where(m => m.AccountId != Guid.Parse(currentUser.Id))
.Select(m => m.AccountId.ToString())
.ToList();
var respRequest = new PushWebSocketPacketToUsersRequest() { Packet = responsePacket };
respRequest.UserIds.AddRange(otherMembers);
await pusher.PushWebSocketPacketToUsersAsync(respRequest);
}
private async Task SendErrorResponse(ReceiveWebSocketPacketRequest request, string message)
{
await pusher.PushWebSocketPacketToDeviceAsync(new PushWebSocketPacketToDeviceRequest
{
DeviceId = request.DeviceId,
Packet = new WebSocketPacket
{
Type = "error",
ErrorMessage = message
}
});
}
}