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

@@ -16,8 +16,50 @@ service FileService {
rpc DeleteFiles (DeleteFilesRequest) returns (Empty);
}
service IdentificationService {
rpc GetOnlineUserCount (ServerMessage) returns (OnlineUserCountResponse);
rpc RemoveIdentForUid (RemoveIdentMessage) returns (Empty);
rpc SetIdentForUid (SetIdentMessage) returns (Empty);
rpc GetUidForCharacterIdent (CharacterIdentMessage) returns (UidMessage);
rpc GetIdentForUid (UidMessage) returns (CharacterIdentMessage);
rpc ClearIdentsForServer (ServerMessage) returns (Empty);
rpc RecreateServerIdents (ServerIdentMessage) returns (Empty);
}
message Empty { }
message ServerIdentMessage {
repeated SetIdentMessage idents = 1;
}
message ServerMessage {
string server_id = 1;
}
message OnlineUserCountResponse {
int64 count = 1;
}
message RemoveIdentMessage {
string uid = 1;
string server_id = 2;
}
message SetIdentMessage {
string uid = 1;
string server_id = 2;
string ident = 3;
}
message CharacterIdentMessage {
string server_id = 1;
string ident = 2;
}
message UidMessage {
string uid = 1;
}
message UploadFileRequest {
string hash = 1;
string uploader = 2;

View File

@@ -1,65 +0,0 @@
using System.Collections.Concurrent;
using MareSynchronosShared.Metrics;
namespace MareSynchronosShared.Services;
public abstract class BaseClientIdentificationService : IClientIdentificationService
{
private readonly MareMetrics metrics;
protected ConcurrentDictionary<string, string> OnlineClients = new();
protected BaseClientIdentificationService(MareMetrics metrics)
{
this.metrics = metrics;
}
public virtual Task<int> GetOnlineUsers()
{
return Task.FromResult(OnlineClients.Count);
}
public Task<string?> GetUidForCharacterIdent(string characterIdent)
{
var result = OnlineClients.SingleOrDefault(u =>
string.Compare(u.Value, characterIdent, StringComparison.InvariantCultureIgnoreCase) == 0);
return Task.FromResult(result.Equals(new KeyValuePair<string, string>()) ? null : result.Key);
}
public virtual Task<string?> GetCharacterIdentForUid(string uid)
{
if (!OnlineClients.TryGetValue(uid, out var result))
{
return Task.FromResult((string?)null);
}
return Task.FromResult(result);
}
public virtual Task MarkUserOnline(string uid, string charaIdent)
{
OnlineClients[uid] = charaIdent;
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
return Task.CompletedTask;
}
public virtual Task MarkUserOffline(string uid)
{
if (OnlineClients.TryRemove(uid, out _))
{
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
}
return Task.CompletedTask;
}
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public virtual Task StopAsync(CancellationToken cancellationToken)
{
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, 0);
OnlineClients = new();
return Task.CompletedTask;
}
}

View File

@@ -1,71 +0,0 @@
using System.Text;
using MareSynchronosShared.Metrics;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace MareSynchronosShared.Services;
public class DistributedClientIdentificationService : BaseClientIdentificationService
{
private readonly IDistributedCache distributedCache;
private readonly ILogger<DistributedClientIdentificationService> logger;
private readonly IConfiguration configuration;
private const string RedisPrefix = "uidcache:";
public DistributedClientIdentificationService(MareMetrics metrics, IDistributedCache distributedCache, IConfiguration configuration, ILogger<DistributedClientIdentificationService> logger) : base(metrics)
{
this.distributedCache = distributedCache;
this.logger = logger;
this.configuration = configuration.GetSection("MareSynchronos");
}
public override async Task<int> GetOnlineUsers()
{
try
{
var redis = configuration.GetValue<string>("RedisConnectionString");
var conn = await ConnectionMultiplexer.ConnectAsync(redis).ConfigureAwait(false);
var endpoint = conn.GetEndPoints().First();
return await conn.GetServer(endpoint).KeysAsync(pattern: "*" + RedisPrefix + "*").CountAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogError(ex, "Error during GetOnlineUsers");
return 0;
}
}
public override async Task<string?> GetCharacterIdentForUid(string uid)
{
var localIdent = await base.GetCharacterIdentForUid(uid).ConfigureAwait(false);
if (localIdent != null) return localIdent;
var cachedIdent = await distributedCache.GetStringAsync(RedisPrefix + uid).ConfigureAwait(false);
return cachedIdent ?? null;
}
public override async Task MarkUserOffline(string uid)
{
await base.MarkUserOffline(uid).ConfigureAwait(false);
await distributedCache.RemoveAsync(RedisPrefix + uid).ConfigureAwait(false);
}
public override async Task MarkUserOnline(string uid, string charaIdent)
{
await base.MarkUserOnline(uid, charaIdent).ConfigureAwait(false);
await distributedCache.SetAsync(RedisPrefix + uid, Encoding.UTF8.GetBytes(charaIdent), new DistributedCacheEntryOptions()
{
AbsoluteExpiration = DateTime.Now.AddDays(7)
}).ConfigureAwait(false);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
foreach (var uid in OnlineClients)
{
distributedCache.Remove(RedisPrefix + uid.Key);
}
return base.StopAsync(cancellationToken);
}
}

View File

@@ -1,12 +0,0 @@
using Microsoft.Extensions.Hosting;
namespace MareSynchronosShared.Services;
public interface IClientIdentificationService : IHostedService
{
Task<int> GetOnlineUsers();
Task<string?> GetUidForCharacterIdent(string characterIdent);
Task<string?> GetCharacterIdentForUid(string uid);
Task MarkUserOnline(string uid, string charaIdent);
Task MarkUserOffline(string uid);
}

View File

@@ -1,10 +0,0 @@
using MareSynchronosShared.Metrics;
namespace MareSynchronosShared.Services;
public class LocalClientIdentificationService : BaseClientIdentificationService
{
public LocalClientIdentificationService(MareMetrics metrics) : base(metrics)
{
}
}