From ff03584518bd5168fd8b0094adf34e33c45e238b Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 22 Oct 2025 21:56:50 +0800 Subject: [PATCH] :bug: Fix some issues in moving realm service --- DysonNetwork.Pass/Realm/RealmServiceGrpc.cs | 18 ++++++++ DysonNetwork.Shared/Proto/realm.proto | 16 ++++++++ .../Registry/RemoteRealmService.cs | 15 +++++++ .../Activity/ActivityService.cs | 41 ++++++++++++++++--- .../Chat/ChatRoomController.cs | 5 ++- DysonNetwork.Sphere/Post/PostController.cs | 37 ++++++++++++++--- 6 files changed, 120 insertions(+), 12 deletions(-) diff --git a/DysonNetwork.Pass/Realm/RealmServiceGrpc.cs b/DysonNetwork.Pass/Realm/RealmServiceGrpc.cs index 2880a14..3e13bc3 100644 --- a/DysonNetwork.Pass/Realm/RealmServiceGrpc.cs +++ b/DysonNetwork.Pass/Realm/RealmServiceGrpc.cs @@ -35,6 +35,15 @@ public class RealmServiceGrpc( : realm.ToProtoValue(); } + public override async Task GetRealmBatch(GetRealmBatchRequest request, ServerCallContext context) + { + var ids = request.Ids.Select(Guid.Parse).ToList(); + var realms = await db.Realms.Where(r => ids.Contains(r.Id)).ToListAsync(); + var response = new GetRealmBatchResponse(); + response.Realms.AddRange(realms.Select(r => r.ToProtoValue())); + return response; + } + public override async Task GetUserRealms(GetUserRealmsRequest request, ServerCallContext context) { @@ -48,6 +57,7 @@ public class RealmServiceGrpc( .Include(m => m.Realm) .Where(m => m.AccountId == accountId) .Where(m => m.JoinedAt != null && m.LeaveAt == null) + .Where(m => m.Realm != null) .Select(m => m.Realm!.Id) .ToListAsync(); @@ -57,6 +67,14 @@ public class RealmServiceGrpc( return new GetUserRealmsResponse { RealmIds = { realms.Select(g => g.ToString()) } }; } + public override async Task GetPublicRealms(Empty request, ServerCallContext context) + { + var realms = await db.Realms.Where(r => r.IsPublic).ToListAsync(); + var response = new GetPublicRealmsResponse(); + response.Realms.AddRange(realms.Select(r => r.ToProtoValue())); + return response; + } + public override async Task SendInviteNotify(SendInviteNotifyRequest request, ServerCallContext context) { var member = request.Member; diff --git a/DysonNetwork.Shared/Proto/realm.proto b/DysonNetwork.Shared/Proto/realm.proto index 2418873..99bb8c5 100644 --- a/DysonNetwork.Shared/Proto/realm.proto +++ b/DysonNetwork.Shared/Proto/realm.proto @@ -32,8 +32,12 @@ message RealmMember { service RealmService { // Get realm by id or slug rpc GetRealm(GetRealmRequest) returns (Realm) {} + // Get realm batch by ids + rpc GetRealmBatch(GetRealmBatchRequest) returns (GetRealmBatchResponse) {} // Get realms for a user rpc GetUserRealms(GetUserRealmsRequest) returns (GetUserRealmsResponse) {} + // Get public realms + rpc GetPublicRealms(google.protobuf.Empty) returns (GetPublicRealmsResponse) {} // Send invitation notification rpc SendInviteNotify(SendInviteNotifyRequest) returns (google.protobuf.Empty) {} // Check if member has required role @@ -57,10 +61,22 @@ message GetUserRealmsRequest { string account_id = 1; } +message GetRealmBatchRequest { + repeated string ids = 1; +} + +message GetRealmBatchResponse { + repeated Realm realms = 1; +} + message GetUserRealmsResponse { repeated string realm_ids = 1; } +message GetPublicRealmsResponse { + repeated Realm realms = 1; +} + message SendInviteNotifyRequest { RealmMember member = 1; } diff --git a/DysonNetwork.Shared/Registry/RemoteRealmService.cs b/DysonNetwork.Shared/Registry/RemoteRealmService.cs index 15ca7b1..93d3856 100644 --- a/DysonNetwork.Shared/Registry/RemoteRealmService.cs +++ b/DysonNetwork.Shared/Registry/RemoteRealmService.cs @@ -1,5 +1,6 @@ using DysonNetwork.Shared.Models; using DysonNetwork.Shared.Proto; +using Google.Protobuf.WellKnownTypes; namespace DysonNetwork.Shared.Registry; @@ -26,6 +27,20 @@ public class RemoteRealmService(RealmService.RealmServiceClient realms) return response.RealmIds.Select(Guid.Parse).ToList(); } + public async Task> GetPublicRealms() + { + var response = await realms.GetPublicRealmsAsync(new Empty()); + return response.Realms.Select(SnRealm.FromProtoValue).ToList(); + } + + public async Task> GetRealmBatch(List ids) + { + var request = new GetRealmBatchRequest(); + request.Ids.AddRange(ids); + var response = await realms.GetRealmBatchAsync(request); + return response.Realms.Select(SnRealm.FromProtoValue).ToList(); + } + public async Task SendInviteNotify(SnRealmMember member) { var protoMember = member.ToProtoValue(); diff --git a/DysonNetwork.Sphere/Activity/ActivityService.cs b/DysonNetwork.Sphere/Activity/ActivityService.cs index 4f4fa80..a67527a 100644 --- a/DysonNetwork.Sphere/Activity/ActivityService.cs +++ b/DysonNetwork.Sphere/Activity/ActivityService.cs @@ -40,19 +40,23 @@ public class ActivityService( debugInclude ??= new HashSet(); // Get and process posts + var publicRealms = await rs.GetPublicRealms(); + var publicRealmIds = publicRealms.Select(r => r.Id).ToList(); + var postsQuery = db.Posts .Include(e => e.RepliedPost) .Include(e => e.ForwardedPost) .Include(e => e.Categories) .Include(e => e.Tags) - .Include(e => e.Realm) .Where(e => e.RepliedPostId == null) .Where(p => cursor == null || p.PublishedAt < cursor) + .Where(p => p.RealmId == null || publicRealmIds.Contains(p.RealmId.Value)) .OrderByDescending(p => p.PublishedAt) .FilterWithVisibility(null, [], [], isListing: true) .Take(take * 5); var posts = await GetAndProcessPosts(postsQuery); + await LoadPostsRealmsAsync(posts, rs); posts = RankPosts(posts, take); var interleaved = new List(); @@ -122,6 +126,9 @@ public class ActivityService( userPublishers, trackViews: true); + if (currentUser != null) + await LoadPostsRealmsAsync(posts, rs); + posts = RankPosts(posts, take); var interleaved = new List(); @@ -219,15 +226,19 @@ public class ActivityService( private async Task GetShuffledPostsActivity(int count = 5) { + var publicRealms = await rs.GetPublicRealms(); + var publicRealmIds = publicRealms.Select(r => r.Id).ToList(); + var postsQuery = db.Posts .Include(p => p.Categories) .Include(p => p.Tags) - .Include(p => p.Realm) .Where(p => p.RepliedPostId == null) + .Where(p => p.RealmId == null || publicRealmIds.Contains(p.RealmId.Value)) .OrderBy(_ => EF.Functions.Random()) .Take(count); var posts = await GetAndProcessPosts(postsQuery, trackViews: false); + await LoadPostsRealmsAsync(posts, rs); return posts.Count == 0 ? null @@ -306,7 +317,6 @@ public class ActivityService( .Include(e => e.ForwardedPost) .Include(e => e.Categories) .Include(e => e.Tags) - .Include(e => e.Realm) .Where(e => e.RepliedPostId == null) .Where(p => cursor == null || p.PublishedAt < cursor) .OrderByDescending(p => p.PublishedAt) @@ -315,10 +325,14 @@ public class ActivityService( if (filteredPublishersId != null && filteredPublishersId.Count != 0) query = query.Where(p => filteredPublishersId.Contains(p.PublisherId)); if (userRealms == null) - query = query.Where(p => p.Realm == null || p.Realm.IsPublic); + { + // For anonymous users, only show public realm posts or posts without realm + // Get public realm ids in the caller and pass them + query = query.Where(p => p.RealmId == null); // Modify in caller + } else query = query.Where(p => - p.Realm == null || p.Realm.IsPublic || p.RealmId == null || userRealms.Contains(p.RealmId.Value)); + p.RealmId == null || userRealms.Contains(p.RealmId.Value)); return query; } @@ -339,6 +353,23 @@ public class ActivityService( }; } + private static async Task LoadPostsRealmsAsync(List posts, RemoteRealmService rs) + { + var postRealmIds = posts.Where(p => p.RealmId != null).Select(p => p.RealmId.Value).Distinct().ToList(); + if (!postRealmIds.Any()) return; + + var realms = await rs.GetRealmBatch(postRealmIds.Select(id => id.ToString()).ToList()); + var realmDict = realms.ToDictionary(r => r.Id, r => r); + + foreach (var post in posts.Where(p => p.RealmId != null)) + { + if (post.RealmId != null && realmDict.TryGetValue(post.RealmId.Value, out var realm)) + { + post.Realm = realm; + } + } + } + private static double CalculatePopularity(List posts) { var score = posts.Sum(p => p.Upvotes - p.Downvotes); diff --git a/DysonNetwork.Sphere/Chat/ChatRoomController.cs b/DysonNetwork.Sphere/Chat/ChatRoomController.cs index 0e689e8..05c9676 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomController.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomController.cs @@ -35,9 +35,12 @@ public class ChatRoomController( { var chatRoom = await db.ChatRooms .Where(c => c.Id == id) - .Include(e => e.Realm) .FirstOrDefaultAsync(); if (chatRoom is null) return NotFound(); + + if (chatRoom.RealmId != null) + chatRoom.Realm = await rs.GetRealm(chatRoom.RealmId.Value.ToString()); + if (chatRoom.Type != ChatRoomType.DirectMessage) return Ok(chatRoom); if (HttpContext.Items["CurrentUser"] is Account currentUser) diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index 8787ac8..8d5c6ad 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -105,7 +105,10 @@ public class PostController( var accountId = currentUser is null ? Guid.Empty : Guid.Parse(currentUser.Id); var userPublishers = currentUser is null ? [] : await pub.GetUserPublishers(accountId); - var userRealms = currentUser is null ? [] : await rs.GetUserRealms(accountId); + var userRealms = currentUser is null ? new List() : await rs.GetUserRealms(accountId); + var publicRealms = await rs.GetPublicRealms(); + var publicRealmIds = publicRealms.Select(r => r.Id).ToList(); + var visibleRealmIds = userRealms.Concat(publicRealmIds).Distinct().ToList(); var publisher = pubName == null ? null : await db.Publishers.FirstOrDefaultAsync(p => p.Name == pubName); var realm = realmName == null ? null : (realmName != null ? await rs.GetRealmBySlug(realmName) : null); @@ -115,7 +118,6 @@ public class PostController( .Include(e => e.Tags) .Include(e => e.RepliedPost) .Include(e => e.ForwardedPost) - .Include(e => e.Realm) .AsQueryable(); if (publisher != null) query = query.Where(p => p.PublisherId == publisher.Id); @@ -131,8 +133,7 @@ public class PostController( query = query.Where(e => e.Attachments.Count > 0); if (realm == null) - query = query.Where(p => - p.RealmId == null || p.Realm == null || userRealms.Contains(p.RealmId.Value) || p.Realm.IsPublic); + query = query.Where(p => p.RealmId == null || visibleRealmIds.Contains(p.RealmId.Value)); switch (pinned) { @@ -185,11 +186,31 @@ public class PostController( .ToListAsync(); posts = await ps.LoadPostInfo(posts, currentUser, true); + // Load realm data for posts that have realm + await LoadPostsRealmsAsync(posts, rs); + Response.Headers["X-Total"] = totalCount.ToString(); return Ok(posts); } + private static async Task LoadPostsRealmsAsync(List posts, RemoteRealmService rs) + { + var postRealmIds = posts.Where(p => p.RealmId != null).Select(p => p.RealmId.Value).Distinct().ToList(); + if (!postRealmIds.Any()) return; + + var realms = await rs.GetRealmBatch(postRealmIds.Select(id => id.ToString()).ToList()); + var realmDict = realms.GroupBy(r => r.Id).ToDictionary(g => g.Key, g => g.FirstOrDefault()); + + foreach (var post in posts.Where(p => p.RealmId != null)) + { + if (post.RealmId != null && realmDict.TryGetValue(post.RealmId.Value, out var realm)) + { + post.Realm = realm; + } + } + } + [HttpGet("{publisherName}/{slug}")] public async Task> GetPost(string publisherName, string slug) { @@ -208,7 +229,6 @@ public class PostController( var post = await db.Posts .Include(e => e.Publisher) .Where(e => e.Slug == slug && e.Publisher.Name == publisherName) - .Include(e => e.Realm) .Include(e => e.Tags) .Include(e => e.Categories) .Include(e => e.RepliedPost) @@ -217,6 +237,8 @@ public class PostController( .FirstOrDefaultAsync(); if (post is null) return NotFound(); post = await ps.LoadPostInfo(post, currentUser); + if (post.RealmId != null) + post.Realm = await rs.GetRealm(post.RealmId.Value.ToString()); return Ok(post); } @@ -239,7 +261,6 @@ public class PostController( var post = await db.Posts .Where(e => e.Id == id) .Include(e => e.Publisher) - .Include(e => e.Realm) .Include(e => e.Tags) .Include(e => e.Categories) .Include(e => e.RepliedPost) @@ -248,6 +269,10 @@ public class PostController( .FirstOrDefaultAsync(); if (post is null) return NotFound(); post = await ps.LoadPostInfo(post, currentUser); + if (post.RealmId != null) + { + post.Realm = await rs.GetRealm(post.RealmId.Value.ToString()); + } return Ok(post); }