Files
Swarm/DysonNetwork.Develop/Identity/BotAccountService.cs
2025-08-23 17:06:52 +08:00

174 lines
5.5 KiB
C#

using DysonNetwork.Develop.Project;
using DysonNetwork.Shared.Data;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Registry;
using Grpc.Core;
using Microsoft.EntityFrameworkCore;
using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Develop.Identity;
public class BotAccountService(
AppDatabase db,
BotAccountReceiverService.BotAccountReceiverServiceClient accountReceiver,
AccountClientHelper accounts
)
{
public async Task<BotAccount?> GetBotByIdAsync(Guid id)
{
return await db.BotAccounts
.Include(b => b.Project)
.FirstOrDefaultAsync(b => b.Id == id);
}
public async Task<IEnumerable<BotAccount>> GetBotsByProjectAsync(Guid projectId)
{
return await db.BotAccounts
.Where(b => b.ProjectId == projectId)
.ToListAsync();
}
public async Task<BotAccount> CreateBotAsync(
DevProject project,
string slug,
Account account,
string? pictureId,
string? backgroundId
)
{
// First, check if a bot with this slug already exists in this project
var existingBot = await db.BotAccounts
.FirstOrDefaultAsync(b => b.ProjectId == project.Id && b.Slug == slug);
if (existingBot != null)
throw new InvalidOperationException("A bot with this slug already exists in this project.");
try
{
var automatedId = Guid.NewGuid();
var createRequest = new CreateBotAccountRequest
{
AutomatedId = automatedId.ToString(),
Account = account,
PictureId = pictureId,
BackgroundId = backgroundId
};
var createResponse = await accountReceiver.CreateBotAccountAsync(createRequest);
var botAccount = createResponse.Bot;
// Then create the local bot account
var bot = new BotAccount
{
Id = automatedId,
Slug = slug,
ProjectId = project.Id,
Project = project,
IsActive = botAccount.IsActive,
CreatedAt = botAccount.CreatedAt.ToInstant(),
UpdatedAt = botAccount.UpdatedAt.ToInstant()
};
db.BotAccounts.Add(bot);
await db.SaveChangesAsync();
return bot;
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.AlreadyExists)
{
throw new InvalidOperationException(
"A bot account with this ID already exists in the authentication service.", ex);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument)
{
throw new ArgumentException($"Invalid bot account data: {ex.Status.Detail}", ex);
}
catch (RpcException ex)
{
throw new Exception($"Failed to create bot account: {ex.Status.Detail}", ex);
}
}
public async Task<BotAccount> UpdateBotAsync(
BotAccount bot,
Account account,
string? pictureId,
string? backgroundId
)
{
db.Update(bot);
await db.SaveChangesAsync();
try
{
// Update the bot account in the Pass service
var updateRequest = new UpdateBotAccountRequest
{
AutomatedId = bot.Id.ToString(),
Account = account,
PictureId = pictureId,
BackgroundId = backgroundId
};
var updateResponse = await accountReceiver.UpdateBotAccountAsync(updateRequest);
var updatedBot = updateResponse.Bot;
// Update local bot account
bot.UpdatedAt = updatedBot.UpdatedAt.ToInstant();
bot.IsActive = updatedBot.IsActive;
await db.SaveChangesAsync();
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound)
{
throw new Exception("Bot account not found in the authentication service", ex);
}
catch (RpcException ex)
{
throw new Exception($"Failed to update bot account: {ex.Status.Detail}", ex);
}
return bot;
}
public async Task DeleteBotAsync(BotAccount bot)
{
try
{
// Delete the bot account from the Pass service
var deleteRequest = new DeleteBotAccountRequest
{
AutomatedId = bot.Id.ToString(),
Force = false
};
await accountReceiver.DeleteBotAccountAsync(deleteRequest);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound)
{
// Account not found in Pass service, continue with local deletion
}
// Delete the local bot account
db.BotAccounts.Remove(bot);
await db.SaveChangesAsync();
}
public async Task<BotAccount?> LoadBotAccountAsync(BotAccount bot) =>
(await LoadBotsAccountAsync([bot])).FirstOrDefault();
public async Task<List<BotAccount>> LoadBotsAccountAsync(IEnumerable<BotAccount> bots)
{
bots = bots.ToList();
var automatedIds = bots.Select(b => b.Id).ToList();
var data = await accounts.GetBotAccountBatch(automatedIds);
foreach (var bot in bots)
{
bot.Account = data
.Select(AccountReference.FromProtoValue)
.FirstOrDefault(e => e.AutomatedId == bot.Id);
}
return bots as List<BotAccount> ?? [];
}
}