♻️ Moving to MagicOnion
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
using System.Globalization;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Services;
|
||||
using MagicOnion.Server;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using NodaTime;
|
||||
|
||||
@ -9,11 +11,9 @@ namespace DysonNetwork.Pass.Account;
|
||||
|
||||
public class AccountEventService(
|
||||
AppDatabase db,
|
||||
// WebSocketService ws,
|
||||
// ICacheService cache,
|
||||
// PaymentService payment,
|
||||
ICacheService cache,
|
||||
IStringLocalizer<Localization.AccountEventResource> localizer
|
||||
)
|
||||
) : ServiceBase<IAccountEventService>, IAccountEventService
|
||||
{
|
||||
private static readonly Random Random = new();
|
||||
private const string StatusCacheKey = "AccountStatus_";
|
||||
@ -21,18 +21,18 @@ public class AccountEventService(
|
||||
public void PurgeStatusCache(Guid userId)
|
||||
{
|
||||
var cacheKey = $"{StatusCacheKey}{userId}";
|
||||
// cache.RemoveAsync(cacheKey);
|
||||
cache.RemoveAsync(cacheKey);
|
||||
}
|
||||
|
||||
public async Task<Status> GetStatus(Guid userId)
|
||||
{
|
||||
var cacheKey = $"{StatusCacheKey}{userId}";
|
||||
// var cachedStatus = await cache.GetAsync<Status>(cacheKey);
|
||||
// if (cachedStatus is not null)
|
||||
// {
|
||||
// cachedStatus!.IsOnline = !cachedStatus.IsInvisible && ws.GetAccountIsConnected(userId);
|
||||
// return cachedStatus;
|
||||
// }
|
||||
var cachedStatus = await cache.GetAsync<Status>(cacheKey);
|
||||
if (cachedStatus is not null)
|
||||
{
|
||||
cachedStatus!.IsOnline = !cachedStatus.IsInvisible /*&& ws.GetAccountIsConnected(userId)*/;
|
||||
return cachedStatus;
|
||||
}
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var status = await db.AccountStatuses
|
||||
@ -45,8 +45,12 @@ public class AccountEventService(
|
||||
if (status is not null)
|
||||
{
|
||||
status.IsOnline = !status.IsInvisible && isOnline;
|
||||
// await cache.SetWithGroupsAsync(cacheKey, status, [$"{AccountService.AccountCachePrefix}{status.AccountId}"],
|
||||
// TimeSpan.FromMinutes(5));
|
||||
await cache.SetWithGroupsAsync(
|
||||
cacheKey,
|
||||
status,
|
||||
[$"{AccountService.AccountCachePrefix}{status.AccountId}"],
|
||||
TimeSpan.FromMinutes(5)
|
||||
);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -62,7 +66,7 @@ public class AccountEventService(
|
||||
};
|
||||
}
|
||||
|
||||
return new Status
|
||||
return new Status
|
||||
{
|
||||
Attitude = StatusAttitude.Neutral,
|
||||
IsOnline = false,
|
||||
@ -88,7 +92,7 @@ public class AccountEventService(
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
cacheMissUserIds.Add(userId);
|
||||
cacheMissUserIds.Add(userId);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -192,27 +196,28 @@ public class AccountEventService(
|
||||
return lastDate < currentDate;
|
||||
}
|
||||
|
||||
public const string CheckInLockKey = "CheckInLock_";
|
||||
private const string CheckInLockKey = "checkin-lock:";
|
||||
|
||||
public async Task<CheckInResult> CheckInDaily(Shared.Models.Account user)
|
||||
{
|
||||
var lockKey = $"{CheckInLockKey}{user.Id}";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// var lk = await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromMilliseconds(100));
|
||||
|
||||
// if (lk != null)
|
||||
// await lk.ReleaseAsync();
|
||||
var lk = await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromMilliseconds(100));
|
||||
|
||||
if (lk != null)
|
||||
await lk.ReleaseAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors from this pre-check
|
||||
}
|
||||
|
||||
|
||||
// Now try to acquire the lock properly
|
||||
// await using var lockObj = await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(5));
|
||||
// if (lockObj is null) throw new InvalidOperationException("Check-in was in progress.");
|
||||
await using var lockObj =
|
||||
await cache.AcquireLockAsync(lockKey, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(5));
|
||||
if (lockObj is null) throw new InvalidOperationException("Check-in was in progress.");
|
||||
|
||||
var cultureInfo = new CultureInfo(user.Language, false);
|
||||
CultureInfo.CurrentCulture = cultureInfo;
|
||||
@ -274,12 +279,53 @@ public class AccountEventService(
|
||||
s.SetProperty(b => b.Experience, b => b.Experience + result.RewardExperience)
|
||||
);
|
||||
db.AccountCheckInResults.Add(result);
|
||||
await db.SaveChangesAsync(); // Don't forget to save changes to the database
|
||||
await db.SaveChangesAsync(); // Remember to save changes to the database
|
||||
|
||||
// The lock will be automatically released by the await using statement
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> GetCheckInStreak(Shared.Models.Account user)
|
||||
{
|
||||
var today = SystemClock.Instance.GetCurrentInstant().InUtc().Date;
|
||||
var yesterdayEnd = today.PlusDays(-1).AtMidnight().InUtc().ToInstant();
|
||||
var yesterdayStart = today.PlusDays(-1).AtStartOfDayInZone(DateTimeZone.Utc).ToInstant();
|
||||
var tomorrowEnd = today.PlusDays(1).AtMidnight().InUtc().ToInstant();
|
||||
var tomorrowStart = today.PlusDays(1).AtStartOfDayInZone(DateTimeZone.Utc).ToInstant();
|
||||
|
||||
var yesterdayResult = await db.AccountCheckInResults
|
||||
.Where(x => x.AccountId == user.Id)
|
||||
.Where(x => x.CreatedAt >= yesterdayStart)
|
||||
.Where(x => x.CreatedAt < yesterdayEnd)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var tomorrowResult = await db.AccountCheckInResults
|
||||
.Where(x => x.AccountId == user.Id)
|
||||
.Where(x => x.CreatedAt >= tomorrowStart)
|
||||
.Where(x => x.CreatedAt < tomorrowEnd)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (yesterdayResult is null && tomorrowResult is null)
|
||||
return 1;
|
||||
|
||||
var results = await db.AccountCheckInResults
|
||||
.Where(x => x.AccountId == user.Id)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
var streak = 0;
|
||||
var day = today;
|
||||
while (results.Any(x =>
|
||||
x.CreatedAt >= day.AtStartOfDayInZone(DateTimeZone.Utc).ToInstant() &&
|
||||
x.CreatedAt < day.AtMidnight().InUtc().ToInstant()))
|
||||
{
|
||||
streak++;
|
||||
day = day.PlusDays(-1);
|
||||
}
|
||||
|
||||
return streak;
|
||||
}
|
||||
|
||||
public async Task<List<DailyEventResponse>> GetEventCalendar(Shared.Models.Account user, int month, int year = 0,
|
||||
bool replaceInvisible = false)
|
||||
{
|
||||
|
Reference in New Issue
Block a user