Rewind service basis and sphere service rewind

This commit is contained in:
2025-12-25 21:36:26 +08:00
parent 0bc77b948c
commit 24836fc606
8 changed files with 156 additions and 2 deletions

View File

@@ -0,0 +1,6 @@
namespace DysonNetwork.Pass.Account.Rewind;
public class AccountRewindController
{
}

View File

@@ -0,0 +1,6 @@
namespace DysonNetwork.Pass.Account.Rewind;
public class AccountRewindService(AppDatabase db)
{
}

View File

@@ -63,6 +63,8 @@ public class AppDatabase(
public DbSet<SnAffiliationSpell> AffiliationSpells { get; set; } = null!; public DbSet<SnAffiliationSpell> AffiliationSpells { get; set; } = null!;
public DbSet<SnAffiliationResult> AffiliationResults { get; set; } = null!; public DbSet<SnAffiliationResult> AffiliationResults { get; set; } = null!;
public DbSet<SnRewindPoint> RewindPoints { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace DysonNetwork.Shared.Models;
public class SnRewindPoint
{
public Guid Id { get; set; } = Guid.NewGuid();
public int Year { get; set; } = DateTime.UtcNow.Year;
[Column(TypeName = "jsonb")] public Dictionary<string, string> Data { get; set; } = new();
public Guid AccountId { get; set; }
public SnAccount Account { get; set; } = null!;
}

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package proto;
option csharp_namespace = "DysonNetwork.Shared.Proto";
message RewindEvent {
string account_id = 1;
optional bytes data = 2;
string service_id = 3;
}
message RequestRewindEvent {
string account_id = 1;
}
service RewindService {
rpc GetRewindEvent(RequestRewindEvent) returns (RewindEvent) {}
}

View File

@@ -20,6 +20,14 @@ public class PublisherService(
RemoteAccountService remoteAccounts RemoteAccountService remoteAccounts
) )
{ {
public async Task<SnPublisher?> GetPublisherLoaded(Guid id)
{
var publisher = await db.Publishers
.Where(p => p.Id == id)
.FirstOrDefaultAsync();
return publisher is null ? null : (await LoadIndividualPublisherAccounts([publisher])).First();
}
public async Task<SnPublisher?> GetPublisherByName(string name) public async Task<SnPublisher?> GetPublisherByName(string name)
{ {
return await db.Publishers return await db.Publishers
@@ -453,7 +461,7 @@ public class PublisherService(
public async Task<List<SnPublisher>> LoadIndividualPublisherAccounts(ICollection<SnPublisher> publishers) public async Task<List<SnPublisher>> LoadIndividualPublisherAccounts(ICollection<SnPublisher> publishers)
{ {
var accountIds = publishers var accountIds = publishers
.Where(p => p.AccountId.HasValue && p.Type == PublisherType.Individual) .Where(p => p is { AccountId: not null, Type: PublisherType.Individual })
.Select(p => p.AccountId!.Value) .Select(p => p.AccountId!.Value)
.ToList(); .ToList();
if (accountIds.Count == 0) return publishers.ToList(); if (accountIds.Count == 0) return publishers.ToList();
@@ -638,7 +646,7 @@ public class PublisherService(
if (!publisherAccounts.TryGetValue(publisherId, out var receivers) || receivers.Count == 0) if (!publisherAccounts.TryGetValue(publisherId, out var receivers) || receivers.Count == 0)
continue; continue;
var publisherName = publishers.TryGetValue(publisherId, out var pub) ? pub.Name : "unknown"; var publisherName = publishers.TryGetValue(publisherId, out var pub) ? pub.Name : "unknown";
// Set social credit for receivers, expired before next settle // Set social credit for receivers, expired before next settle

View File

@@ -0,0 +1,97 @@
using System.Globalization;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Registry;
using Grpc.Core;
using Microsoft.EntityFrameworkCore;
namespace DysonNetwork.Sphere.Rewind;
public class SphereRewindServiceGrpc(
AppDatabase db,
RemoteAccountService remoteAccounts,
Publisher.PublisherService ps
) : RewindService.RewindServiceBase
{
public override async Task<RewindEvent> GetRewindEvent(RequestRewindEvent request, ServerCallContext context)
{
var accountId = Guid.Parse(request.AccountId);
// Audience data
var mostLovedPublisherClue =
await db.PostReactions
.Where(p => p.AccountId == accountId && p.Attitude == Shared.Models.PostReactionAttitude.Positive)
.GroupBy(p => p.Post.PublisherId)
.OrderByDescending(g => g.Count())
.Select(g => new { PublisherId = g.Key, ReactionCount = g.Count() })
.FirstOrDefaultAsync();
var mostLovedPublisher = mostLovedPublisherClue is not null
? ps.GetPublisherLoaded(mostLovedPublisherClue.PublisherId)
: null;
// Creator data
var publishers = await db.PublisherMembers
.Where(pm => pm.AccountId == accountId)
.Select(pm => pm.PublisherId)
.ToListAsync();
var mostLovedAudienceClue =
await db.PostReactions
.Where(pr =>
pr.Attitude == Shared.Models.PostReactionAttitude.Positive &&
publishers.Contains(pr.Post.PublisherId))
.GroupBy(pr => pr.AccountId)
.OrderByDescending(g => g.Count())
.Select(g => new { AccountId = g.Key, ReactionCount = g.Count() })
.FirstOrDefaultAsync();
var mostLovedAudience = mostLovedAudienceClue is not null
? await remoteAccounts.GetAccount(mostLovedAudienceClue.AccountId)
: null;
var posts = await db.Posts
.Where(p => publishers.Contains(p.PublisherId))
.ToListAsync();
var postTotalCount = posts.Count;
var mostPopularPost = posts
.OrderByDescending(p => p.Upvotes - p.Downvotes)
.FirstOrDefault();
var mostProductiveDay = posts
.GroupBy(p => p.CreatedAt.ToDateTimeUtc().Date)
.OrderByDescending(g => g.Count())
.Select(g => new { Date = g.Key, PostCount = g.Count() })
.FirstOrDefault();
var data = new Dictionary<string, object?>
{
["total_count"] = postTotalCount,
["most_popular_post"] = mostPopularPost,
["most_productive_day"] = mostProductiveDay is not null
? new Dictionary<string, object?>
{
["date"] = mostProductiveDay.Date.ToString(CultureInfo.InvariantCulture),
["post_count"] = mostProductiveDay.PostCount,
}
: null,
["most_loved_publisher"] = mostLovedPublisherClue is not null
? new Dictionary<string, object?>
{
["publisher"] = mostLovedPublisher,
["upvote_counts"] = mostLovedPublisherClue.ReactionCount,
}
: null,
["most_loved_audience"] = mostLovedAudienceClue is not null
? new Dictionary<string, object?>
{
["account"] = mostLovedAudience,
["upvote_counts"] = mostLovedAudienceClue.ReactionCount,
}
: null,
};
return new RewindEvent
{
ServiceId = "sphere",
AccountId = request.AccountId,
Data = GrpcTypeHelper.ConvertObjectToByteString(data)
};
}
}

View File

@@ -2,6 +2,7 @@ using DysonNetwork.Shared.Auth;
using DysonNetwork.Shared.Http; using DysonNetwork.Shared.Http;
using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Post;
using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Publisher;
using DysonNetwork.Sphere.Rewind;
namespace DysonNetwork.Sphere.Startup; namespace DysonNetwork.Sphere.Startup;
@@ -23,6 +24,7 @@ public static class ApplicationConfiguration
// Map gRPC services // Map gRPC services
app.MapGrpcService<PostServiceGrpc>(); app.MapGrpcService<PostServiceGrpc>();
app.MapGrpcService<PublisherServiceGrpc>(); app.MapGrpcService<PublisherServiceGrpc>();
app.MapGrpcService<SphereRewindServiceGrpc>();
app.MapGrpcReflectionService(); app.MapGrpcReflectionService();
return app; return app;