Implement missing asset bundle endpoints and initial new user flow

This commit is contained in:
BillyCool
2026-03-14 02:09:25 +11:00
parent 48cf89f792
commit 62d90edbea
13 changed files with 833 additions and 54 deletions

View File

@@ -1,11 +1,17 @@
using MariesWonderland.Proto.User;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using MariesWonderland.Data;
using MariesWonderland.Extensions;
using MariesWonderland.Models.Entities;
using MariesWonderland.Proto.Data;
using MariesWonderland.Proto.User;
namespace MariesWonderland.Services;
public class UserService : MariesWonderland.Proto.User.UserService.UserServiceBase
public class UserService(UserDataStore store) : MariesWonderland.Proto.User.UserService.UserServiceBase
{
private readonly UserDataStore _store = store;
public override Task<GetAndroidArgsResponse> GetAndroidArgs(GetAndroidArgsRequest request, ServerCallContext context)
{
return Task.FromResult(new GetAndroidArgsResponse
@@ -17,13 +23,39 @@ public class UserService : MariesWonderland.Proto.User.UserService.UserServiceBa
public override Task<AuthUserResponse> Auth(AuthUserRequest request, ServerCallContext context)
{
return Task.FromResult(new AuthUserResponse
var (userId, isNew) = _store.RegisterOrGetUser(request.Uuid);
var userDb = _store.GetOrCreate(userId);
var nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var deviceRecord = userDb.EntitySUserDevice.FirstOrDefault(d => d.UserId == userId);
if (deviceRecord == null)
{
ExpireDatetime = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(30)),
UserId = 1234567890123450000,
SessionKey = "1234567890",
Signature = request.Signature
});
deviceRecord = new EntitySUserDevice { UserId = userId };
userDb.EntitySUserDevice.Add(deviceRecord);
}
deviceRecord.Uuid = request.Uuid;
deviceRecord.AdvertisingId = request.AdvertisingId;
deviceRecord.IsTrackingEnabled = request.IsTrackingEnabled;
deviceRecord.IdentifierForVendor = request.DeviceInherent?.IdentifierForVendor ?? "";
deviceRecord.DeviceToken = request.DeviceInherent?.DeviceToken ?? "";
deviceRecord.MacAddress = request.DeviceInherent?.MacAddress ?? "";
deviceRecord.RegistrationId = request.DeviceInherent?.RegistrationId ?? "";
deviceRecord.LastAuthAt = nowMs;
if (isNew) deviceRecord.RegisteredAt = nowMs;
var session = _store.CreateSession(userId, TimeSpan.FromHours(24));
var diffData = UserDataDiffBuilder.FullDiff(userDb);
var response = new AuthUserResponse
{
SessionKey = session.SessionKey,
ExpireDatetime = Timestamp.FromDateTime(session.ExpiresAt),
Signature = request.Signature,
UserId = userId
};
foreach (var (k, v) in diffData) response.DiffUserData[k] = v;
return Task.FromResult(response);
}
public override Task<CheckTransferSettingResponse> CheckTransferSetting(Empty request, ServerCallContext context)
@@ -66,11 +98,20 @@ public class UserService : MariesWonderland.Proto.User.UserService.UserServiceBa
public override Task<RegisterUserResponse> RegisterUser(RegisterUserRequest request, ServerCallContext context)
{
return Task.FromResult(new RegisterUserResponse
// RegisterUser is the very first API called on a fresh install. It registers the device UUID
// and assigns a permanent userId (random 19-digit number). Subsequent launches call Auth instead.
var (userId, _) = _store.RegisterOrGetUser(request.Uuid);
DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId);
Dictionary<string, DiffData> diffData = UserDataDiffBuilder.FullDiff(userDb);
RegisterUserResponse response = new()
{
UserId = 1234567890123450000,
Signature = "V2UnbGxQbGF5QWdhaW5Tb21lZGF5TXJNb25zdGVyIQ=="
});
UserId = userId,
Signature = $"sig_{userId}_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}"
};
foreach (var (k, v) in diffData) response.DiffUserData[k] = v;
return Task.FromResult(response);
}
public override Task<SetAppleAccountResponse> SetAppleAccount(SetAppleAccountRequest request, ServerCallContext context)
@@ -100,7 +141,28 @@ public class UserService : MariesWonderland.Proto.User.UserService.UserServiceBa
public override Task<SetUserNameResponse> SetUserName(SetUserNameRequest request, ServerCallContext context)
{
return Task.FromResult(new SetUserNameResponse());
long userId = context.GetUserId();
DarkUserMemoryDatabase userDb = _store.GetOrCreate(userId);
Dictionary<string, string> before = UserDataDiffBuilder.Snapshot(userDb);
EntityIUserProfile profile = userDb.EntityIUserProfile.FirstOrDefault(p => p.UserId == userId)
?? AddEntity(userDb.EntityIUserProfile, new EntityIUserProfile { UserId = userId });
profile.Name = request.Name;
profile.NameUpdateDatetime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
SetUserNameResponse response = new();
foreach (var (k, v) in UserDataDiffBuilder.Delta(before, userDb)) response.DiffUserData[k] = v;
return Task.FromResult(response);
}
/// <summary>Adds an entity to a list and returns it (convenience for inline new-entity seeding).</summary>
private static T AddEntity<T>(List<T> list, T entity)
{
list.Add(entity);
return entity;
}
public override Task<SetUserSettingResponse> SetUserSetting(SetUserSettingRequest request, ServerCallContext context)
@@ -110,11 +172,7 @@ public class UserService : MariesWonderland.Proto.User.UserService.UserServiceBa
public override Task<TransferUserResponse> TransferUser(TransferUserRequest request, ServerCallContext context)
{
return Task.FromResult(new TransferUserResponse
{
UserId = 1234567890123450000,
Signature = "V2UnbGxQbGF5QWdhaW5Tb21lZGF5TXJNb25zdGVyIQ=="
});
return Task.FromResult(new TransferUserResponse());
}
public override Task<TransferUserByAppleResponse> TransferUserByApple(TransferUserByAppleRequest request, ServerCallContext context)