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:
		| @@ -0,0 +1,158 @@ | ||||
| using Grpc.Core; | ||||
| using MareSynchronosShared.Metrics; | ||||
| using MareSynchronosShared.Protos; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Linq; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace MareSynchronosServer.Services; | ||||
|  | ||||
| public class GrpcClientIdentificationService : IHostedService | ||||
| { | ||||
|     private readonly string _shardName; | ||||
|     private readonly ILogger<GrpcClientIdentificationService> _logger; | ||||
|     private readonly IdentificationService.IdentificationServiceClient _grpcIdentClient; | ||||
|     private readonly MareMetrics _metrics; | ||||
|     protected ConcurrentDictionary<string, string> OnlineClients = new(StringComparer.Ordinal); | ||||
|     private bool _grpcIsFaulty = false; | ||||
|  | ||||
|     public GrpcClientIdentificationService(ILogger<GrpcClientIdentificationService> logger, IdentificationService.IdentificationServiceClient gprcIdentClient, MareMetrics metrics, IConfiguration configuration) | ||||
|     { | ||||
|         var config = configuration.GetSection("MareSynchronos"); | ||||
|         _shardName = config.GetValue("ServerName", "Main"); | ||||
|         _logger = logger; | ||||
|         _grpcIdentClient = gprcIdentClient; | ||||
|         _metrics = metrics; | ||||
|     } | ||||
|  | ||||
|     public async Task<string?> GetCharacterIdentForUid(string uid) | ||||
|     { | ||||
|         if (OnlineClients.TryGetValue(uid, out string ident)) | ||||
|         { | ||||
|             return ident; | ||||
|         } | ||||
|  | ||||
|         var result = await InvokeOnGrpc(_grpcIdentClient.GetIdentForUidAsync(new UidMessage { Uid = uid })).ConfigureAwait(false); | ||||
|         if (result == default(CharacterIdentMessage)) return null; | ||||
|         return result.Ident; | ||||
|     } | ||||
|  | ||||
|     public async Task<string?> GetServerForUid(string uid) | ||||
|     { | ||||
|         if (OnlineClients.ContainsKey(uid)) | ||||
|         { | ||||
|             return _shardName; | ||||
|         } | ||||
|  | ||||
|         var result = await InvokeOnGrpc(_grpcIdentClient.GetIdentForUidAsync(new UidMessage { Uid = uid })).ConfigureAwait(false); | ||||
|         if (result == default(CharacterIdentMessage)) return null; | ||||
|         return result.ServerId; | ||||
|     } | ||||
|  | ||||
|     public async Task<long> GetOnlineUsers() | ||||
|     { | ||||
|         var result = await InvokeOnGrpc(_grpcIdentClient.GetOnlineUserCountAsync(new ServerMessage())).ConfigureAwait(false); | ||||
|         if (result == default(OnlineUserCountResponse)) return OnlineClients.Count; | ||||
|         return result.Count; | ||||
|     } | ||||
|  | ||||
|     public async Task<string?> GetUidForCharacterIdent(string characterIdent) | ||||
|     { | ||||
|         bool existsLocal = OnlineClients.Any(o => string.Equals(o.Value, characterIdent, StringComparison.Ordinal)); | ||||
|         if (existsLocal) | ||||
|         { | ||||
|             return OnlineClients.First(c => string.Equals(c.Value, characterIdent, StringComparison.Ordinal)).Key; | ||||
|         } | ||||
|  | ||||
|         var result = await InvokeOnGrpc(_grpcIdentClient.GetUidForCharacterIdentAsync(new CharacterIdentMessage { Ident = characterIdent, ServerId = string.Empty })).ConfigureAwait(false); | ||||
|         if (result == default(UidMessage)) return null; | ||||
|         return result.Uid; | ||||
|     } | ||||
|  | ||||
|     public async Task MarkUserOffline(string uid) | ||||
|     { | ||||
|         OnlineClients.TryRemove(uid, out _); | ||||
|         _metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count); | ||||
|         await ExecuteOnGrpc(_grpcIdentClient.RemoveIdentForUidAsync(new RemoveIdentMessage() { ServerId = _shardName, Uid = uid })).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     public async Task MarkUserOnline(string uid, string charaIdent) | ||||
|     { | ||||
|         OnlineClients[uid] = charaIdent; | ||||
|         _metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count); | ||||
|         await ExecuteOnGrpc(_grpcIdentClient.SetIdentForUidAsync(new SetIdentMessage() { Ident = charaIdent, ServerId = _shardName, Uid = uid })).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     public async Task StartAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         await ExecuteOnGrpc(_grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName })).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     public async Task StopAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         await ExecuteOnGrpc(_grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName })).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|     private async Task<T> InvokeOnGrpc<T>(AsyncUnaryCall<T> toExecute) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var result = await toExecute.ConfigureAwait(false); | ||||
|  | ||||
|             await CheckFaultStateAndResend().ConfigureAwait(false); | ||||
|  | ||||
|             return result; | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|             SetGrpcFaulty(); | ||||
|  | ||||
|             return default; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task ExecuteOnGrpc<T>(AsyncUnaryCall<T> toExecute) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             await toExecute.ConfigureAwait(false); | ||||
|             await CheckFaultStateAndResend().ConfigureAwait(false); | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|             SetGrpcFaulty(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task CheckFaultStateAndResend() | ||||
|     { | ||||
|         if (_grpcIsFaulty) | ||||
|         { | ||||
|             _logger.LogInformation("GRPC connection is restored, sending current server idents"); | ||||
|             await _grpcIdentClient.ClearIdentsForServerAsync(new ServerMessage() { ServerId = _shardName }).ConfigureAwait(false); | ||||
|             var msg = new ServerIdentMessage(); | ||||
|             msg.Idents.AddRange(OnlineClients.Select(c => new SetIdentMessage() | ||||
|             { | ||||
|                 Ident = c.Value, | ||||
|                 Uid = c.Key, | ||||
|                 ServerId = _shardName | ||||
|             })); | ||||
|             await _grpcIdentClient.RecreateServerIdentsAsync(msg).ConfigureAwait(false); | ||||
|             _grpcIsFaulty = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void SetGrpcFaulty() | ||||
|     { | ||||
|         if (!_grpcIsFaulty) | ||||
|         { | ||||
|             _grpcIsFaulty = true; | ||||
|             _logger.LogWarning("GRPC connection is faulty"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -6,7 +6,6 @@ using MareSynchronos.API; | ||||
| using MareSynchronosServer.Hubs; | ||||
| using MareSynchronosShared.Data; | ||||
| using MareSynchronosShared.Metrics; | ||||
| using MareSynchronosShared.Services; | ||||
| using Microsoft.AspNetCore.SignalR; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| @@ -19,14 +18,14 @@ public class SystemInfoService : IHostedService, IDisposable | ||||
| { | ||||
|     private readonly MareMetrics _mareMetrics; | ||||
|     private readonly IServiceProvider _services; | ||||
|     private readonly IClientIdentificationService _clientIdentService; | ||||
|     private readonly GrpcClientIdentificationService _clientIdentService; | ||||
|     private readonly ILogger<SystemInfoService> _logger; | ||||
|     private readonly IHubContext<MareHub> _hubContext; | ||||
|     private Timer _timer; | ||||
|     private string _shardName; | ||||
|     public SystemInfoDto SystemInfoDto { get; private set; } = new(); | ||||
|  | ||||
|     public SystemInfoService(MareMetrics mareMetrics, IConfiguration configuration, IServiceProvider services, IClientIdentificationService clientIdentService, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext) | ||||
|     public SystemInfoService(MareMetrics mareMetrics, IConfiguration configuration, IServiceProvider services, GrpcClientIdentificationService clientIdentService, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext) | ||||
|     { | ||||
|         _mareMetrics = mareMetrics; | ||||
|         _services = services; | ||||
| @@ -56,7 +55,7 @@ public class SystemInfoService : IHostedService, IDisposable | ||||
|         { | ||||
|             SystemInfoDto = new SystemInfoDto() | ||||
|             { | ||||
|                 OnlineUsers = _clientIdentService.GetOnlineUsers().Result, | ||||
|                 OnlineUsers = (int)_clientIdentService.GetOnlineUsers().Result, | ||||
|             }; | ||||
|  | ||||
|             _hubContext.Clients.All.SendAsync(Api.OnUpdateSystemInfo, SystemInfoDto); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 rootdarkarchon
					rootdarkarchon