♻️ Still don't know what I am doing

This commit is contained in:
2025-07-13 23:38:57 +08:00
parent 03e26ef93c
commit cde55eb237
23 changed files with 300 additions and 170 deletions

View File

@@ -20,31 +20,6 @@ public class WebSocketService
private static readonly ConcurrentDictionary<string, string> ActiveSubscriptions = new(); // deviceId -> chatRoomId
public void SubscribeToChatRoom(string chatRoomId, string deviceId)
{
ActiveSubscriptions[deviceId] = chatRoomId;
}
public void UnsubscribeFromChatRoom(string deviceId)
{
ActiveSubscriptions.TryRemove(deviceId, out _);
}
public bool IsUserSubscribedToChatRoom(string accountId, string chatRoomId)
{
var userDeviceIds = ActiveConnections.Keys.Where(k => k.AccountId == accountId).Select(k => k.DeviceId);
foreach (var deviceId in userDeviceIds)
{
if (ActiveSubscriptions.TryGetValue(deviceId, out var subscribedChatRoomId) &&
subscribedChatRoomId == chatRoomId)
{
return true;
}
}
return false;
}
public bool TryAdd(
(string AccountId, string DeviceId) key,
WebSocket socket,
@@ -67,7 +42,11 @@ public class WebSocketService
);
data.Cts.Cancel();
ActiveConnections.TryRemove(key, out _);
UnsubscribeFromChatRoom(key.DeviceId);
}
public bool GetDeviceIsConnected(string deviceId)
{
return ActiveConnections.Any(c => c.Key.DeviceId == deviceId);
}
public bool GetAccountIsConnected(string accountId)

View File

@@ -1,15 +1,20 @@
using System.ComponentModel.DataAnnotations;
using DysonNetwork.Shared.Auth;
using DysonNetwork.Shared.Proto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
using AccountService = DysonNetwork.Shared.Proto.AccountService;
namespace DysonNetwork.Pusher.Notification;
[ApiController]
[Route("/api/notifications")]
public class NotificationController(AppDatabase db, NotificationService nty) : ControllerBase
public class NotificationController(
AppDatabase db,
PushService nty,
AccountService.AccountServiceClient accounts) : ControllerBase
{
[HttpGet("count")]
[Authorize]
@@ -17,9 +22,10 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
{
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account currentUser) return Unauthorized();
var accountId = Guid.Parse(currentUser.Id);
var count = await db.Notifications
.Where(s => s.AccountId == currentUser.Id && s.ViewedAt == null)
.Where(s => s.AccountId == accountId && s.ViewedAt == null)
.CountAsync();
return Ok(count);
}
@@ -30,24 +36,25 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
[FromQuery] int offset = 0,
// The page size set to 5 is to avoid the client pulled the notification
// but didn't render it in the screen-viewable region.
[FromQuery] int take = 5
[FromQuery] int take = 8
)
{
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account currentUser) return Unauthorized();
var accountId = Guid.Parse(currentUser.Id);
var totalCount = await db.Notifications
.Where(s => s.AccountId == currentUser.Id)
.Where(s => s.AccountId == accountId)
.CountAsync();
var notifications = await db.Notifications
.Where(s => s.AccountId == currentUser.Id)
.Where(s => s.AccountId == accountId)
.OrderByDescending(e => e.CreatedAt)
.Skip(offset)
.Take(take)
.ToListAsync();
Response.Headers["X-Total"] = totalCount.ToString();
await nty.MarkNotificationsViewed(notifications);
await nty.MarkNotificationsViewed(notifications.ToList());
return Ok(notifications);
}
@@ -55,14 +62,15 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
public class PushNotificationSubscribeRequest
{
[MaxLength(4096)] public string DeviceToken { get; set; } = null!;
public NotificationPushProvider Provider { get; set; }
public PushProvider Provider { get; set; }
}
[HttpPut("subscription")]
[Authorize]
public async Task<ActionResult<NotificationPushSubscription>> SubscribeToPushNotification(
[FromBody] PushNotificationSubscribeRequest request
)
public async Task<ActionResult<PushSubscription>>
SubscribeToPushNotification(
[FromBody] PushNotificationSubscribeRequest request
)
{
HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue);
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
@@ -72,8 +80,12 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
if (currentSession == null) return Unauthorized();
var result =
await nty.SubscribePushNotification(currentUser, request.Provider, currentSession.Challenge.DeviceId!,
request.DeviceToken);
await nty.SubscribeDevice(
currentSession.Challenge.DeviceId!,
request.DeviceToken,
request.Provider,
currentUser
);
return Ok(result);
}
@@ -88,10 +100,11 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
if (currentUser == null) return Unauthorized();
var currentSession = currentSessionValue as AuthSession;
if (currentSession == null) return Unauthorized();
var accountId = Guid.Parse(currentUser.Id);
var affectedRows = await db.NotificationPushSubscriptions
var affectedRows = await db.PushSubscriptions
.Where(s =>
s.AccountId == currentUser.Id &&
s.AccountId == accountId &&
s.DeviceId == currentSession.Challenge.DeviceId
).ExecuteDeleteAsync();
return Ok(affectedRows);
@@ -107,36 +120,11 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
public int Priority { get; set; } = 10;
}
[HttpPost("broadcast")]
[Authorize]
[RequiredPermission("global", "notifications.broadcast")]
public async Task<ActionResult> BroadcastNotification(
[FromBody] NotificationRequest request,
[FromQuery] bool save = false
)
{
await nty.BroadcastNotification(
new Notification
{
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
UpdatedAt = SystemClock.Instance.GetCurrentInstant(),
Topic = request.Topic,
Title = request.Title,
Subtitle = request.Subtitle,
Content = request.Content,
Meta = request.Meta,
Priority = request.Priority,
},
save
);
return Ok();
}
public class NotificationWithAimRequest : NotificationRequest
{
[Required] public List<Guid> AccountId { get; set; } = null!;
}
[HttpPost("send")]
[Authorize]
[RequiredPermission("global", "notifications.send")]
@@ -145,7 +133,6 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
[FromQuery] bool save = false
)
{
var accounts = await db.Accounts.Where(a => request.AccountId.Contains(a.Id)).ToListAsync();
await nty.SendNotificationBatch(
new Notification
{
@@ -157,7 +144,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C
Content = request.Content,
Meta = request.Meta,
},
accounts,
request.AccountId,
save
);
return Ok();

View File

@@ -12,14 +12,14 @@ public class PushService(IConfiguration config, AppDatabase db, IHttpClientFacto
private readonly string _notifyTopic = config["Notifications:Topic"]!;
private readonly Uri _notifyEndpoint = new(config["Notifications:Endpoint"]!);
public async Task UnsubscribePushNotifications(string deviceId)
public async Task UnsubscribeDevice(string deviceId)
{
await db.PushSubscriptions
.Where(s => s.DeviceId == deviceId)
.ExecuteDeleteAsync();
}
public async Task<PushSubscription> SubscribePushNotification(
public async Task<PushSubscription> SubscribeDevice(
string deviceId,
string deviceToken,
PushProvider provider,

View File

@@ -9,7 +9,7 @@ namespace DysonNetwork.Pusher.Services;
public class PusherServiceGrpc(
EmailService emailService,
WebSocketService webSocketService,
WebSocketService websocket,
PushService pushService
) : PusherService.PusherServiceBase
{
@@ -32,7 +32,7 @@ public class PusherServiceGrpc(
Data = request.Packet.Data,
ErrorMessage = request.Packet.ErrorMessage
};
webSocketService.SendPacketToAccount(request.UserId, packet);
websocket.SendPacketToAccount(request.UserId, packet);
return Task.FromResult(new Empty());
}
@@ -46,7 +46,7 @@ public class PusherServiceGrpc(
ErrorMessage = request.Packet.ErrorMessage
};
foreach (var userId in request.UserIds)
webSocketService.SendPacketToAccount(userId, packet);
websocket.SendPacketToAccount(userId, packet);
return Task.FromResult(new Empty());
}
@@ -60,7 +60,7 @@ public class PusherServiceGrpc(
Data = request.Packet.Data,
ErrorMessage = request.Packet.ErrorMessage
};
webSocketService.SendPacketToDevice(request.DeviceId, packet);
websocket.SendPacketToDevice(request.DeviceId, packet);
return Task.FromResult(new Empty());
}
@@ -74,7 +74,7 @@ public class PusherServiceGrpc(
ErrorMessage = request.Packet.ErrorMessage
};
foreach (var deviceId in request.DeviceIds)
webSocketService.SendPacketToDevice(deviceId, packet);
websocket.SendPacketToDevice(deviceId, packet);
return Task.FromResult(new Empty());
}
@@ -159,4 +159,22 @@ public class PusherServiceGrpc(
await pushService.SendNotificationBatch(notification, accounts, request.Notification.IsSavable);
return new Empty();
}
public override async Task<Empty> UnsubscribePushNotifications(UnsubscribePushNotificationsRequest request, ServerCallContext context)
{
await pushService.UnsubscribeDevice(request.DeviceId);
return new Empty();
}
public override Task<GetWebsocketConnectionStatusResponse> GetWebsocketConnectionStatus(GetWebsocketConnectionStatusRequest request, ServerCallContext context)
{
var isConnected = request.IdCase switch
{
GetWebsocketConnectionStatusRequest.IdOneofCase.DeviceId => websocket.GetDeviceIsConnected(request.DeviceId),
GetWebsocketConnectionStatusRequest.IdOneofCase.UserId => websocket.GetAccountIsConnected(request.UserId),
_ => false
};
return Task.FromResult(new GetWebsocketConnectionStatusResponse { IsConnected = isConnected });
}
}