Pass rewind service and account rewind service

This commit is contained in:
2025-12-25 22:26:57 +08:00
parent 24836fc606
commit f0d6772dca
10 changed files with 168 additions and 28 deletions

View File

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

View File

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

View File

@@ -0,0 +1,75 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using Grpc.Net.Client;
using Microsoft.EntityFrameworkCore;
namespace DysonNetwork.Pass.Rewind;
public class AccountRewindService(
IHttpClientFactory httpClientFactory,
AppDatabase db,
PassRewindService passRewindSrv
)
{
private static string CapitalizeFirstLetter(string str)
{
if (string.IsNullOrEmpty(str))
return str;
// Capitalize the first character and append the rest of the string in lowercase
return char.ToUpper(str[0]) + str[1..].ToLower();
}
private RewindService.RewindServiceClient CreateRewindServiceClient(string serviceId)
{
var httpClient = httpClientFactory.CreateClient(
$"{nameof(AccountRewindService)}+{CapitalizeFirstLetter(serviceId)}"
);
var channel = GrpcChannel.ForAddress($"http://{serviceId}", new GrpcChannelOptions { HttpClient = httpClient });
return new RewindService.RewindServiceClient(channel);
}
private async Task<SnRewindPoint> CreateRewindPoint(Guid accountId)
{
var currentYear = DateTime.UtcNow.Year;
var rewindRequest = new RequestRewindEvent { AccountId = accountId.ToString(), Year = currentYear};
var rewindEventTasks = new List<Task<RewindEvent>>
{
passRewindSrv.CreateRewindEvent(accountId, currentYear),
CreateRewindServiceClient("sphere").GetRewindEventAsync(rewindRequest).ResponseAsync
};
var rewindEvents = await Task.WhenAll(rewindEventTasks);
var rewindData = rewindEvents.ToDictionary<RewindEvent, string, Dictionary<string, object?>>(
rewindEvent => rewindEvent.ServiceId,
rewindEvent => GrpcTypeHelper.ConvertByteStringToObject<Dictionary<string, object?>>(rewindEvent.Data) ??
new Dictionary<string, object?>()
);
var point = new SnRewindPoint
{
SchemaVersion = 1,
AccountId = accountId,
Data = rewindData.ToDictionary(kvp => kvp.Key, object? (kvp) => kvp.Value)
};
db.RewindPoints.Add(point);
await db.SaveChangesAsync();
return point;
}
public async Task<SnRewindPoint> GetOrCreateRewindPoint(Guid accountId)
{
var currentYear = DateTime.UtcNow.Year;
var existingRewind = await db.RewindPoints
.Where(p => p.AccountId == accountId && p.Year == currentYear)
.OrderBy(p => p.CreatedAt)
.FirstOrDefaultAsync();
if (existingRewind is not null) return existingRewind;
return await CreateRewindPoint(accountId);
}
}

View File

@@ -0,0 +1,49 @@
using System.Linq;
using DysonNetwork.Shared.Proto;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Pass.Rewind;
/// <summary>
/// Although the pass uses the rewind service call internally, no need for grpc.
/// But we created a service that produce the grpc type for consistency.
/// </summary>
public class PassRewindService(AppDatabase db)
{
public async Task<RewindEvent> CreateRewindEvent(Guid accountId, int year)
{
var startDate = Instant.FromDateTimeUtc(new DateTime(year - 1, 12, 26));
var endDate = Instant.FromDateTimeUtc(new DateTime(year, 12, 26));
var checkInDates = await db.AccountCheckInResults
.Where(a => a.CreatedAt >= startDate && a.CreatedAt < endDate)
.Where(a => a.AccountId == accountId)
.Select(a => a.CreatedAt.ToDateTimeUtc().Date)
.Distinct()
.OrderBy(d => d)
.ToListAsync();
var maxCheckInStrike = 0;
if (checkInDates.Count != 0)
{
maxCheckInStrike = checkInDates
.Select((d, i) => new { Date = d, Index = i })
.GroupBy(x => x.Date.Subtract(new TimeSpan(x.Index, 0, 0, 0)))
.Select(g => g.Count())
.Max();
}
var data = new Dictionary<string, object?>
{
["max_check_in_strike"] = maxCheckInStrike,
};
return new RewindEvent
{
ServiceId = "pass",
AccountId = accountId.ToString(),
Data = GrpcTypeHelper.ConvertObjectToByteString(data)
};
}
}

View File

@@ -20,6 +20,7 @@ using DysonNetwork.Pass.Leveling;
using DysonNetwork.Pass.Lotteries;
using DysonNetwork.Pass.Mailer;
using DysonNetwork.Pass.Realm;
using DysonNetwork.Pass.Rewind;
using DysonNetwork.Pass.Safety;
using DysonNetwork.Pass.Wallet.PaymentHandlers;
using DysonNetwork.Shared.Cache;
@@ -167,6 +168,9 @@ public static class ServiceCollectionExtensions
services.Configure<OidcProviderOptions>(configuration.GetSection("OidcProvider"));
services.AddScoped<OidcProviderService>();
services.AddScoped<PassRewindService>();
services.AddScoped<AccountRewindService>();
services.AddHostedService<BroadcastEventHandler>();