Switch to GrpcClientIdentificationService and abolish Redis for Idents (#12)

* add GrpcClientIdentificationService

* remove unnecessary gauges

* set to no retry policy

* initialize metrics

Co-authored-by: Stanley Dimant <root.darkarchon@outlook.com>
This commit is contained in:
rootdarkarchon
2022-10-05 23:10:36 +02:00
committed by GitHub
parent 08b04e14d5
commit 17f26714ce
13 changed files with 373 additions and 209 deletions

View File

@@ -12,10 +12,10 @@ using Discord;
using Discord.Rest;
using Discord.WebSocket;
using MareSynchronosServices.Authentication;
using MareSynchronosServices.Identity;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Models;
using MareSynchronosShared.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -24,11 +24,11 @@ using Microsoft.Extensions.Logging;
namespace MareSynchronosServices.Discord;
public class DiscordBot : IHostedService
internal class DiscordBot : IHostedService
{
private readonly CleanupService cleanupService;
private readonly MareMetrics metrics;
private readonly IClientIdentificationService clientService;
private readonly IdentityHandler identityHandler;
private readonly IServiceProvider services;
private readonly IConfiguration _configuration;
private readonly ILogger<DiscordBot> logger;
@@ -44,16 +44,15 @@ public class DiscordBot : IHostedService
private ConcurrentDictionary<ulong, DateTime> LastVanityChange = new();
private ConcurrentDictionary<string, DateTime> LastVanityGidChange = new();
private ulong vanityCommandId;
private ulong vanityGidCommandId;
private Task cleanUpUserTask = null;
private SemaphoreSlim semaphore;
public DiscordBot(CleanupService cleanupService, MareMetrics metrics, IClientIdentificationService clientService, IServiceProvider services, IConfiguration configuration, ILogger<DiscordBot> logger)
public DiscordBot(CleanupService cleanupService, MareMetrics metrics, IdentityHandler identityHandler, IServiceProvider services, IConfiguration configuration, ILogger<DiscordBot> logger)
{
this.cleanupService = cleanupService;
this.metrics = metrics;
this.clientService = clientService;
this.identityHandler = identityHandler;
this.services = services;
_configuration = configuration.GetRequiredSection("MareSynchronos");
this.logger = logger;
@@ -804,7 +803,7 @@ public class DiscordBot : IHostedService
updateStatusCts = new();
while (!updateStatusCts.IsCancellationRequested)
{
var onlineUsers = await clientService.GetOnlineUsers();
var onlineUsers = identityHandler.GetOnlineUsers(string.Empty);
logger.LogInformation("Users online: " + onlineUsers);
await discordClient.SetActivityAsync(new Game("Mare for " + onlineUsers + " Users")).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(false);

View File

@@ -0,0 +1,62 @@
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
namespace MareSynchronosServices.Identity;
internal class IdentityHandler
{
private readonly ConcurrentDictionary<string, ServerIdentity> cachedIdentities = new();
internal Task<string> GetUidForCharacterIdent(string ident, string serverId)
{
var exists = cachedIdentities.Any(f => f.Value.CharacterIdent == ident && f.Value.ServerId == serverId);
return Task.FromResult(exists ? cachedIdentities.FirstOrDefault(f => f.Value.CharacterIdent == ident && f.Value.ServerId == serverId).Key : string.Empty);
}
internal Task<ServerIdentity> GetIdentForuid(string uid)
{
ServerIdentity result;
if (!cachedIdentities.TryGetValue(uid, out result))
{
result = new ServerIdentity();
}
return Task.FromResult(result);
}
internal void SetIdent(string uid, string serverId, string ident)
{
cachedIdentities[uid] = new ServerIdentity() { ServerId = serverId, CharacterIdent = ident };
}
internal void RemoveIdent(string uid, string serverId)
{
if (cachedIdentities.ContainsKey(uid) && cachedIdentities[uid].ServerId == serverId)
{
cachedIdentities.TryRemove(uid, out _);
}
}
internal int GetOnlineUsers(string serverId)
{
if (string.IsNullOrEmpty(serverId))
return cachedIdentities.Count;
return cachedIdentities.Count(c => c.Value.ServerId == serverId);
}
internal void ClearIdentsForServer(string serverId)
{
var serverIdentities = cachedIdentities.Where(i => i.Value.ServerId == serverId);
foreach (var identity in serverIdentities)
{
cachedIdentities.TryRemove(identity.Key, out _);
}
}
}
internal record ServerIdentity
{
public string ServerId { get; set; } = string.Empty;
public string CharacterIdent { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,69 @@
using Grpc.Core;
using MareSynchronosShared.Protos;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace MareSynchronosServices.Identity;
internal class IdentityService : IdentificationService.IdentificationServiceBase
{
private readonly ILogger<IdentityService> _logger;
private readonly IdentityHandler _handler;
public IdentityService(ILogger<IdentityService> logger, IdentityHandler handler)
{
_logger = logger;
_handler = handler;
}
public override Task<Empty> RemoveIdentForUid(RemoveIdentMessage request, ServerCallContext context)
{
_handler.RemoveIdent(request.Uid, request.ServerId);
return Task.FromResult(new Empty());
}
public override Task<Empty> SetIdentForUid(SetIdentMessage request, ServerCallContext context)
{
_handler.SetIdent(request.Uid, request.ServerId, request.Ident);
return Task.FromResult(new Empty());
}
public override async Task<CharacterIdentMessage> GetIdentForUid(UidMessage request, ServerCallContext context)
{
var result = await _handler.GetIdentForuid(request.Uid);
return new CharacterIdentMessage()
{
Ident = result.CharacterIdent,
ServerId = result.ServerId
};
}
public override async Task<UidMessage> GetUidForCharacterIdent(CharacterIdentMessage request, ServerCallContext context)
{
var result = await _handler.GetUidForCharacterIdent(request.Ident, request.ServerId);
return new UidMessage()
{
Uid = result
};
}
public override Task<OnlineUserCountResponse> GetOnlineUserCount(ServerMessage request, ServerCallContext context)
{
return Task.FromResult(new OnlineUserCountResponse() { Count = _handler.GetOnlineUsers(request.ServerId) });
}
public override Task<Empty> ClearIdentsForServer(ServerMessage request, ServerCallContext context)
{
_handler.ClearIdentsForServer(request.ServerId);
return Task.FromResult(new Empty());
}
public override Task<Empty> RecreateServerIdents(ServerIdentMessage request, ServerCallContext context)
{
foreach (var identMsg in request.Idents)
{
_handler.SetIdent(identMsg.Uid, identMsg.ServerId, identMsg.Ident);
}
return Task.FromResult(new Empty());
}
}

View File

@@ -10,7 +10,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Prometheus;
using System.Collections.Generic;
using MareSynchronosShared.Services;
using MareSynchronosServices.Identity;
namespace MareSynchronosServices;
@@ -45,29 +45,12 @@ public class Startup
}));
services.AddSingleton<SecretKeyAuthenticationHandler>();
services.AddSingleton<IdentityHandler>();
services.AddSingleton<CleanupService>();
services.AddTransient(_ => Configuration);
services.AddHostedService(provider => provider.GetService<CleanupService>());
services.AddHostedService<DiscordBot>();
services.AddGrpc();
// add redis related options
var redis = Configuration.GetSection("MareSynchronos").GetValue("RedisConnectionString", string.Empty);
if (!string.IsNullOrEmpty(redis))
{
services.AddStackExchangeRedisCache(opt =>
{
opt.Configuration = redis;
opt.InstanceName = "MareSynchronosCache:";
});
services.AddSingleton<IClientIdentificationService, DistributedClientIdentificationService>();
services.AddHostedService(p => p.GetService<IClientIdentificationService>());
}
else
{
services.AddSingleton<IClientIdentificationService, LocalClientIdentificationService>();
services.AddHostedService(p => p.GetService<IClientIdentificationService>());
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@@ -80,6 +63,7 @@ public class Startup
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<AuthenticationService>();
endpoints.MapGrpcService<IdentityService>();
});
}
}