🐛 Dozens of fixes
This commit is contained in:
@@ -6,11 +6,13 @@ namespace DysonNetwork.Gateway;
|
||||
|
||||
public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private readonly IEtcdClient _etcdClient;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<RegistryProxyConfigProvider> _logger;
|
||||
private readonly CancellationTokenSource _watchCts = new();
|
||||
private CancellationTokenSource _cts = new();
|
||||
private CancellationTokenSource _cts;
|
||||
private IProxyConfig _config;
|
||||
|
||||
public RegistryProxyConfigProvider(IEtcdClient etcdClient, IConfiguration configuration,
|
||||
ILogger<RegistryProxyConfigProvider> logger)
|
||||
@@ -18,19 +20,33 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
|
||||
_etcdClient = etcdClient;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
_cts = new CancellationTokenSource();
|
||||
_config = LoadConfig();
|
||||
|
||||
// Watch for changes in etcd
|
||||
_etcdClient.WatchRange("/services/", _ =>
|
||||
{
|
||||
_logger.LogInformation("Etcd configuration changed. Reloading proxy config.");
|
||||
_cts.Cancel();
|
||||
_cts = new CancellationTokenSource();
|
||||
ReloadConfig();
|
||||
}, cancellationToken: _watchCts.Token);
|
||||
}
|
||||
|
||||
public IProxyConfig GetConfig()
|
||||
public IProxyConfig GetConfig() => _config;
|
||||
|
||||
private void ReloadConfig()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var oldCts = _cts;
|
||||
_cts = new CancellationTokenSource();
|
||||
_config = LoadConfig();
|
||||
oldCts.Cancel();
|
||||
oldCts.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private IProxyConfig LoadConfig()
|
||||
{
|
||||
// This will be called by YARP when it needs a new config
|
||||
_logger.LogInformation("Generating new proxy config.");
|
||||
var response = _etcdClient.GetRange("/services/");
|
||||
var kvs = response.Kvs;
|
||||
@@ -184,17 +200,15 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
|
||||
_logger.LogInformation(" Added Path-based Route: {Path}", pathRoute.Match.Path);
|
||||
}
|
||||
|
||||
return new CustomProxyConfig(routes, clusters);
|
||||
return new CustomProxyConfig(routes, clusters, new Microsoft.Extensions.Primitives.CancellationChangeToken(_cts.Token));
|
||||
}
|
||||
|
||||
private class CustomProxyConfig(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters)
|
||||
private class CustomProxyConfig(IReadOnlyList<RouteConfig> routes, IReadOnlyList<ClusterConfig> clusters, Microsoft.Extensions.Primitives.IChangeToken changeToken)
|
||||
: IProxyConfig
|
||||
{
|
||||
public IReadOnlyList<RouteConfig> Routes { get; } = routes;
|
||||
public IReadOnlyList<ClusterConfig> Clusters { get; } = clusters;
|
||||
|
||||
public Microsoft.Extensions.Primitives.IChangeToken ChangeToken { get; } =
|
||||
new Microsoft.Extensions.Primitives.CancellationChangeToken(CancellationToken.None);
|
||||
public Microsoft.Extensions.Primitives.IChangeToken ChangeToken { get; } = changeToken;
|
||||
}
|
||||
|
||||
public record DirectRouteConfig
|
||||
@@ -211,4 +225,4 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
|
||||
_watchCts.Cancel();
|
||||
_watchCts.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -71,7 +71,7 @@ public class PushService(IConfiguration config, AppDatabase db, IHttpClientFacto
|
||||
string? title = null,
|
||||
string? subtitle = null,
|
||||
string? content = null,
|
||||
Dictionary<string, object>? meta = null,
|
||||
Dictionary<string, object?> meta = null,
|
||||
string? actionUri = null,
|
||||
bool isSilent = false,
|
||||
bool save = true)
|
||||
@@ -79,7 +79,6 @@ public class PushService(IConfiguration config, AppDatabase db, IHttpClientFacto
|
||||
if (title is null && subtitle is null && content is null)
|
||||
throw new ArgumentException("Unable to send notification that completely empty.");
|
||||
|
||||
meta ??= new Dictionary<string, object>();
|
||||
if (actionUri is not null) meta["action_uri"] = actionUri;
|
||||
|
||||
var accountId = Guid.Parse(account.Id!);
|
||||
@@ -102,7 +101,7 @@ public class PushService(IConfiguration config, AppDatabase db, IHttpClientFacto
|
||||
if (!isSilent) _ = DeliveryNotification(notification);
|
||||
}
|
||||
|
||||
public async Task DeliveryNotification(Pusher.Notification.Notification notification)
|
||||
public async Task DeliveryNotification(Notification notification)
|
||||
{
|
||||
// Pushing the notification
|
||||
var subscribers = await db.PushSubscriptions
|
||||
|
@@ -2,6 +2,7 @@ using DysonNetwork.Pusher.Connection;
|
||||
using DysonNetwork.Pusher.Email;
|
||||
using DysonNetwork.Pusher.Notification;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using DysonNetwork.Shared.Registry;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Grpc.Core;
|
||||
|
||||
@@ -10,7 +11,8 @@ namespace DysonNetwork.Pusher.Services;
|
||||
public class PusherServiceGrpc(
|
||||
EmailService emailService,
|
||||
WebSocketService websocket,
|
||||
PushService pushService
|
||||
PushService pushService,
|
||||
AccountClientHelper accountsHelper
|
||||
) : PusherService.PusherServiceBase
|
||||
{
|
||||
public override async Task<Empty> SendEmail(SendEmailRequest request, ServerCallContext context)
|
||||
@@ -79,56 +81,10 @@ public class PusherServiceGrpc(
|
||||
return Task.FromResult(new Empty());
|
||||
}
|
||||
|
||||
public override async Task<Empty> SendPushNotification(SendPushNotificationRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
// This is a placeholder implementation. In a real-world scenario, you would
|
||||
// need to retrieve the account from the database based on the device token.
|
||||
var account = new Account();
|
||||
await pushService.SendNotification(
|
||||
account,
|
||||
request.Notification.Topic,
|
||||
request.Notification.Title,
|
||||
request.Notification.Subtitle,
|
||||
request.Notification.Body,
|
||||
GrpcTypeHelper.ConvertFromValueMap(request.Notification.Meta),
|
||||
request.Notification.ActionUri,
|
||||
request.Notification.IsSilent,
|
||||
request.Notification.IsSavable
|
||||
);
|
||||
return new Empty();
|
||||
}
|
||||
|
||||
public override async Task<Empty> SendPushNotificationToDevices(SendPushNotificationToDevicesRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
// This is a placeholder implementation. In a real-world scenario, you would
|
||||
// need to retrieve the accounts from the database based on the device tokens.
|
||||
var account = new Account();
|
||||
foreach (var deviceId in request.DeviceIds)
|
||||
{
|
||||
await pushService.SendNotification(
|
||||
account,
|
||||
request.Notification.Topic,
|
||||
request.Notification.Title,
|
||||
request.Notification.Subtitle,
|
||||
request.Notification.Body,
|
||||
GrpcTypeHelper.ConvertFromValueMap(request.Notification.Meta),
|
||||
request.Notification.ActionUri,
|
||||
request.Notification.IsSilent,
|
||||
request.Notification.IsSavable
|
||||
);
|
||||
}
|
||||
|
||||
return new Empty();
|
||||
}
|
||||
|
||||
public override async Task<Empty> SendPushNotificationToUser(SendPushNotificationToUserRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
// This is a placeholder implementation. In a real-world scenario, you would
|
||||
// need to retrieve the account from the database based on the user ID.
|
||||
var account = new Account();
|
||||
var account = await accountsHelper.GetAccount(Guid.Parse(request.UserId));
|
||||
await pushService.SendNotification(
|
||||
account,
|
||||
request.Notification.Topic,
|
||||
|
@@ -206,7 +206,8 @@ public class CacheServiceRedis : ICacheService
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.None,
|
||||
NullValueHandling = NullValueHandling.Include,
|
||||
DateParseHandling = DateParseHandling.None
|
||||
DateParseHandling = DateParseHandling.None,
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
};
|
||||
|
||||
// Configure NodaTime serializers
|
||||
|
@@ -27,12 +27,6 @@ service PusherService {
|
||||
// Pushes a packet to a list of devices via WebSocket.
|
||||
rpc PushWebSocketPacketToDevices(PushWebSocketPacketToDevicesRequest) returns (google.protobuf.Empty) {}
|
||||
|
||||
// Sends a push notification to a device.
|
||||
rpc SendPushNotification(SendPushNotificationRequest) returns (google.protobuf.Empty) {}
|
||||
|
||||
// Sends a push notification to a list of devices.
|
||||
rpc SendPushNotificationToDevices(SendPushNotificationToDevicesRequest) returns (google.protobuf.Empty) {}
|
||||
|
||||
// Sends a push notification to a user.
|
||||
rpc SendPushNotificationToUser(SendPushNotificationToUserRequest) returns (google.protobuf.Empty) {}
|
||||
|
||||
@@ -60,9 +54,9 @@ message SendEmailRequest {
|
||||
|
||||
// Represents a WebSocket packet.
|
||||
message WebSocketPacket {
|
||||
string type = 1;
|
||||
google.protobuf.Value data = 2;
|
||||
google.protobuf.StringValue error_message = 3;
|
||||
string type = 1;
|
||||
google.protobuf.Value data = 2;
|
||||
google.protobuf.StringValue error_message = 3;
|
||||
}
|
||||
|
||||
message PushWebSocketPacketRequest {
|
||||
@@ -87,49 +81,39 @@ message PushWebSocketPacketToDevicesRequest {
|
||||
|
||||
// Represents a push notification.
|
||||
message PushNotification {
|
||||
string topic = 1;
|
||||
string title = 2;
|
||||
string subtitle = 3;
|
||||
string body = 4;
|
||||
map<string, google.protobuf.Value> meta = 5;
|
||||
optional string action_uri = 6;
|
||||
bool is_silent = 7;
|
||||
bool is_savable = 8;
|
||||
}
|
||||
|
||||
message SendPushNotificationRequest {
|
||||
string device_id = 1;
|
||||
PushNotification notification = 2;
|
||||
}
|
||||
|
||||
message SendPushNotificationToDevicesRequest {
|
||||
repeated string device_ids = 1;
|
||||
PushNotification notification = 2;
|
||||
string topic = 1;
|
||||
string title = 2;
|
||||
string subtitle = 3;
|
||||
string body = 4;
|
||||
map<string, google.protobuf.Value> meta = 5;
|
||||
optional string action_uri = 6;
|
||||
bool is_silent = 7;
|
||||
bool is_savable = 8;
|
||||
}
|
||||
|
||||
message SendPushNotificationToUserRequest {
|
||||
string user_id = 1;
|
||||
PushNotification notification = 2;
|
||||
string user_id = 1;
|
||||
PushNotification notification = 2;
|
||||
}
|
||||
|
||||
message SendPushNotificationToUsersRequest {
|
||||
repeated string user_ids = 1;
|
||||
PushNotification notification = 2;
|
||||
repeated string user_ids = 1;
|
||||
PushNotification notification = 2;
|
||||
}
|
||||
|
||||
message UnsubscribePushNotificationsRequest {
|
||||
string device_id = 1;
|
||||
string device_id = 1;
|
||||
}
|
||||
|
||||
message GetWebsocketConnectionStatusRequest {
|
||||
oneof id {
|
||||
string device_id = 1;
|
||||
string user_id = 2;
|
||||
}
|
||||
oneof id {
|
||||
string device_id = 1;
|
||||
string user_id = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GetWebsocketConnectionStatusResponse {
|
||||
bool is_connected = 1;
|
||||
bool is_connected = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -100,6 +100,12 @@ public partial class ChatController(
|
||||
.Skip(offset)
|
||||
.Take(take)
|
||||
.ToListAsync();
|
||||
|
||||
var members = messages.Select(m => m.Sender).DistinctBy(x => x.Id).ToList();
|
||||
members = await crs.LoadMemberAccounts(members);
|
||||
|
||||
foreach (var message in messages)
|
||||
message.Sender = members.First(x => x.Id == message.SenderId);
|
||||
|
||||
Response.Headers["X-Total"] = totalCount.ToString();
|
||||
|
||||
|
@@ -48,9 +48,9 @@ public class ChatRoomService(
|
||||
.Where(m => m.AccountId == accountId && m.ChatRoomId == chatRoomId)
|
||||
.Include(m => m.ChatRoom)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
|
||||
if (member == null) return member;
|
||||
|
||||
|
||||
member = await LoadMemberAccount(member);
|
||||
var chatRoomGroup = ChatRoomGroupPrefix + chatRoomId;
|
||||
await cache.SetWithGroupsAsync(cacheKey, member,
|
||||
@@ -91,14 +91,22 @@ public class ChatRoomService(
|
||||
.ToList();
|
||||
if (directRoomsId.Count == 0) return rooms;
|
||||
|
||||
var directMembers = directRoomsId.Count != 0
|
||||
List<ChatMember> members = directRoomsId.Count != 0
|
||||
? await db.ChatMembers
|
||||
.Where(m => directRoomsId.Contains(m.ChatRoomId))
|
||||
.Where(m => m.AccountId != userId)
|
||||
.Where(m => m.LeaveAt == null)
|
||||
.GroupBy(m => m.ChatRoomId)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.ToList())
|
||||
: new Dictionary<Guid, List<ChatMember>>();
|
||||
.ToListAsync()
|
||||
: [];
|
||||
members = await LoadMemberAccounts(members);
|
||||
|
||||
Dictionary<Guid, List<ChatMember>> directMembers = new();
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (!directMembers.ContainsKey(member.ChatRoomId))
|
||||
directMembers[member.ChatRoomId] = [];
|
||||
directMembers[member.ChatRoomId].Add(member);
|
||||
}
|
||||
|
||||
return rooms.Select(r =>
|
||||
{
|
||||
|
@@ -58,7 +58,7 @@ public class RealmController(
|
||||
|
||||
var members = await db.RealmMembers
|
||||
.Where(m => m.AccountId == accountId)
|
||||
.Where(m => m.JoinedAt == null)
|
||||
.Where(m => m.JoinedAt == null && m.LeaveAt == null)
|
||||
.Include(e => e.Realm)
|
||||
.ToListAsync();
|
||||
|
||||
|
Reference in New Issue
Block a user