using Google.Protobuf.WellKnownTypes; using Grpc.Core; using EllieBot.Db.Models; using EllieBot.Modules.Gambling.Bank; using EllieBot.Modules.EllieExpressions; using EllieBot.Modules.Utility; using EllieBot.Modules.Xp.Services; namespace EllieBot.GrpcApi; public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService { private readonly XpService _xp; private readonly DiscordSocketClient _client; private readonly IUserService _duSvc; public XpSvc(XpService xp, DiscordSocketClient client, IUserService duSvc) { _xp = xp; _client = client; _duSvc = duSvc; } public ServerServiceDefinition Bind() => GrpcXp.BindService(this); public override async Task<GetXpSettingsReply> GetXpSettings( GetXpSettingsRequest request, ServerCallContext context) { await Task.Yield(); var guild = _client.GetGuild(request.GuildId); if (guild is null) throw new RpcException(new Status(StatusCode.NotFound, "Guild not found")); var excludedChannels = _xp.GetExcludedChannels(request.GuildId); var excludedRoles = _xp.GetExcludedRoles(request.GuildId); var isServerExcluded = _xp.IsServerExcluded(request.GuildId); var reply = new GetXpSettingsReply(); reply.Exclusions.AddRange(excludedChannels .Select(x => new ExclItemReply() { Id = x, Type = "Channel", Name = guild.GetChannel(x)?.Name ?? "????" }) .Concat(excludedRoles .Select(x => new ExclItemReply() { Id = x, Type = "Role", Name = guild.GetRole(x)?.Name ?? "????" }))); var curRews = _xp.GetCurrencyRewards(request.GuildId); var roleRews = _xp.GetRoleRewards(request.GuildId); var rews = curRews.Select(x => new RewItemReply() { Level = x.Level, Type = "Currency", Value = x.Amount.ToString() }); rews = rews.Concat(roleRews.Select(x => new RewItemReply() { Level = x.Level, Type = "Role", Value = guild.GetRole(x.RoleId)?.ToString() ?? x.RoleId.ToString() })) .OrderBy(x => x.Level); reply.Rewards.AddRange(rews); reply.ServerExcluded = isServerExcluded; return reply; } public override async Task<AddExclusionReply> AddExclusion(AddExclusionRequest request, ServerCallContext context) { await Task.Yield(); var success = false; var guild = _client.GetGuild(request.GuildId); if (guild is null) throw new RpcException(new Status(StatusCode.NotFound, "Guild not found")); if (request.Type == "Role") { if (guild.GetRole(request.Id) is null) return new() { Success = false }; success = _xp.ToggleExcludeRole(request.GuildId, request.Id); } else if (request.Type == "Channel") { if (guild.GetTextChannel(request.Id) is null) return new() { Success = false }; success = _xp.ToggleExcludeChannel(request.GuildId, request.Id); } return new() { Success = success }; } public override Task<DeleteExclusionReply> DeleteExclusion( DeleteExclusionRequest request, ServerCallContext context) { var success = false; if (request.Type == "Role") success = _xp.ToggleExcludeRole(request.GuildId, request.Id); else success = _xp.ToggleExcludeChannel(request.GuildId, request.Id); return Task.FromResult(new DeleteExclusionReply { Success = success }); } public override async Task<AddRewardReply> AddReward(AddRewardRequest request, ServerCallContext context) { await Task.Yield(); var success = false; var guild = _client.GetGuild(request.GuildId); if (guild is null) throw new RpcException(new Status(StatusCode.NotFound, "Guild not found")); if (request.Type == "AddRole" || request.Type == "RemoveRole") { if (!ulong.TryParse(request.Value, out var rid)) throw new RpcException(new Status(StatusCode.InvalidArgument, "Invalid role id")); var role = guild.GetRole(rid); if (role is null) return new() { Success = false }; _xp.SetRoleReward(request.GuildId, request.Level, rid, request.Type == "RemoveRole"); success = true; } else if (request.Type == "Currency") { if (!int.TryParse(request.Value, out var amount)) throw new RpcException(new Status(StatusCode.InvalidArgument, "Invalid amount")); _xp.SetCurrencyReward(request.GuildId, request.Level, amount); success = true; } return new() { Success = success }; } public override Task<DeleteRewardReply> DeleteReward(DeleteRewardRequest request, ServerCallContext context) { var success = false; if (request.Type == "AddRole" || request.Type == "RemoveRole") { _xp.ResetRoleReward(request.GuildId, request.Level); success = true; } else if (request.Type == "Currency") { _xp.SetCurrencyReward(request.GuildId, request.Level, 0); success = true; } return Task.FromResult(new DeleteRewardReply { Success = success }); } public override async Task<ResetUserXpReply> ResetUserXp(ResetUserXpRequest request, ServerCallContext context) { await _xp.XpReset(request.GuildId, request.UserId); return new ResetUserXpReply { Success = true }; } public override async Task<GetXpLbReply> GetXpLb(GetXpLbRequest request, ServerCallContext context) { if (request.Page < 0) throw new RpcException(new Status(StatusCode.InvalidArgument, "Page must be greater than or equal to 0")); var guild = _client.GetGuild(request.GuildId); if (guild is null) throw new RpcException(new Status(StatusCode.NotFound, "Guild not found")); var data = await _xp.GetGuildUserXps(request.GuildId, request.Page); var total = await _xp.GetTotalGuildUsers(request.GuildId); var reply = new GetXpLbReply { Total = total }; reply.Users.AddRange(await data .Select(async x => { var user = guild.GetUser(x.UserId); if (user is null) { var du = await _duSvc.GetUserAsync(x.UserId); if (du is null) return new XpLbUserReply { UserId = x.UserId, Avatar = string.Empty, Username = string.Empty, Xp = x.Xp, Level = new LevelStats(x.Xp).Level }; return new XpLbUserReply() { UserId = x.UserId, Avatar = du.RealAvatarUrl()?.ToString() ?? string.Empty, Username = du.ToString() ?? string.Empty, Xp = x.Xp, Level = new LevelStats(x.Xp).Level }; } return new XpLbUserReply { UserId = x.UserId, Avatar = user?.GetAvatarUrl() ?? string.Empty, Username = user?.ToString() ?? string.Empty, Xp = x.Xp, Level = new LevelStats(x.Xp).Level }; }) .WhenAll()); return reply; } }