add redis for character identification
This commit is contained in:
@@ -16,8 +16,8 @@ namespace MareSynchronosServer.Hubs
|
||||
|
||||
private bool IsModerator => _dbContext.Users.Single(b => b.UID == AuthenticatedUserId).IsModerator || IsAdmin;
|
||||
|
||||
private List<string> OnlineAdmins => _dbContext.Users.Where(u => !string.IsNullOrEmpty(u.CharacterIdentification) && (u.IsModerator || u.IsAdmin))
|
||||
.Select(u => u.UID).ToList();
|
||||
private List<string> OnlineAdmins => _dbContext.Users.Where(u => (u.IsModerator || u.IsAdmin)).Select(u => u.UID).ToList();
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendAdminChangeModeratorStatus)]
|
||||
public async Task ChangeModeratorStatus(string uid, bool isModerator)
|
||||
@@ -101,13 +101,14 @@ namespace MareSynchronosServer.Hubs
|
||||
{
|
||||
if (!IsModerator) return null;
|
||||
|
||||
return await _dbContext.Users.AsNoTracking().Where(b => !string.IsNullOrEmpty(b.CharacterIdentification)).Select(b => new OnlineUserDto
|
||||
var users = await _dbContext.Users.AsNoTracking().ToListAsync().ConfigureAwait(false);
|
||||
return users.Where(c => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(c.UID))).Select(b => new OnlineUserDto
|
||||
{
|
||||
CharacterNameHash = b.CharacterIdentification,
|
||||
CharacterNameHash = _clientIdentService.GetCharacterIdentForUid(b.UID),
|
||||
UID = b.UID,
|
||||
IsModerator = b.IsModerator,
|
||||
IsAdmin = b.IsAdmin
|
||||
}).ToListAsync().ConfigureAwait(false);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
@@ -134,11 +135,10 @@ namespace MareSynchronosServer.Hubs
|
||||
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await Clients.Users(OnlineAdmins).SendAsync(Api.OnAdminUpdateOrAddBannedUser, dto).ConfigureAwait(false);
|
||||
var bannedUser =
|
||||
await _dbContext.Users.SingleOrDefaultAsync(u => u.CharacterIdentification == dto.CharacterHash).ConfigureAwait(false);
|
||||
if (bannedUser != null)
|
||||
var bannedUser = _clientIdentService.GetUidForCharacterIdent(dto.CharacterHash);
|
||||
if (!string.IsNullOrEmpty(bannedUser))
|
||||
{
|
||||
await Clients.User(bannedUser.UID).SendAsync(Api.OnAdminForcedReconnect).ConfigureAwait(false);
|
||||
await Clients.User(bannedUser).SendAsync(Api.OnAdminForcedReconnect).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace MareSynchronosServer.Hubs
|
||||
IsForbidden = forbiddenFile != null,
|
||||
Hash = hash.Key,
|
||||
Size = hash.Value,
|
||||
Url = new Uri(cdnFullUri, hash.Key.ToUpperInvariant()).ToString()
|
||||
Url = new Uri(_cdnFullUri, hash.Key.ToUpperInvariant()).ToString()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace MareSynchronosServer.Hubs
|
||||
{
|
||||
_logger.LogInformation("User {AuthenticatedUserId} deleted their account", AuthenticatedUserId);
|
||||
|
||||
|
||||
string userid = AuthenticatedUserId;
|
||||
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid).ConfigureAwait(false);
|
||||
var charaIdent = _clientIdentService.GetCharacterIdentForUid(userid);
|
||||
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == userid).ToListAsync().ConfigureAwait(false);
|
||||
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == userid).ConfigureAwait(false);
|
||||
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == userid).ConfigureAwait(false);
|
||||
@@ -52,7 +52,7 @@ namespace MareSynchronosServer.Hubs
|
||||
{
|
||||
OtherUID = userid,
|
||||
IsRemoved = true
|
||||
}, userEntry.CharacterIdentification).ConfigureAwait(false);
|
||||
}, charaIdent).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugePairs, ownPairData.Count + otherPairData.Count);
|
||||
@@ -77,14 +77,18 @@ namespace MareSynchronosServer.Hubs
|
||||
.Include(u => u.User)
|
||||
.Include(u => u.OtherUser)
|
||||
.Where(w => w.User.UID == ownUser.UID && !w.IsPaused)
|
||||
.Where(w => !string.IsNullOrEmpty(w.OtherUser.CharacterIdentification))
|
||||
//.Where(w => !string.IsNullOrEmpty(w.OtherUser.CharacterIdentification))
|
||||
.Select(e => e.OtherUser).ToListAsync().ConfigureAwait(false);
|
||||
var otherOnlineUsers =
|
||||
otherUsers.Where(u => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(u.UID)));
|
||||
var otherEntries = await _dbContext.ClientPairs.AsNoTracking()
|
||||
.Include(u => u.User)
|
||||
.Where(u => otherUsers.Any(e => e == u.User) && u.OtherUser == ownUser && !u.IsPaused).ToListAsync().ConfigureAwait(false);
|
||||
.Where(u => otherOnlineUsers.Any(e => e == u.User) && u.OtherUser == ownUser && !u.IsPaused)
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(ownUser.UID);
|
||||
|
||||
await Clients.Users(otherEntries.Select(e => e.User.UID)).SendAsync(Api.OnUserAddOnlinePairedPlayer, ownUser.CharacterIdentification).ConfigureAwait(false);
|
||||
return otherEntries.Select(e => e.User.CharacterIdentification).Distinct().ToList();
|
||||
await Clients.Users(otherEntries.Select(e => e.User.UID)).SendAsync(Api.OnUserAddOnlinePairedPlayer, ownIdent).ConfigureAwait(false);
|
||||
return otherEntries.Select(e => _clientIdentService.GetCharacterIdentForUid(e.User.UID)).Distinct().ToList();
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
@@ -152,12 +156,14 @@ namespace MareSynchronosServer.Hubs
|
||||
userToOther.UserUID == user.UID
|
||||
&& !userToOther.IsPaused
|
||||
&& !otherToUser.IsPaused
|
||||
&& visibleCharacterIds.Contains(userToOther.OtherUser.CharacterIdentification)
|
||||
select otherToUser.UserUID;
|
||||
|
||||
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
|
||||
otherEntries =
|
||||
otherEntries.Where(c => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(c))).ToList();
|
||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
|
||||
await Clients.Users(otherEntries).SendAsync(Api.OnUserReceiveCharacterData, characterCache, user.CharacterIdentification).ConfigureAwait(false);
|
||||
await Clients.Users(otherEntries).SendAsync(Api.OnUserReceiveCharacterData, characterCache, ownIdent).ConfigureAwait(false);
|
||||
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, otherEntries.Count);
|
||||
@@ -199,6 +205,7 @@ namespace MareSynchronosServer.Hubs
|
||||
}, string.Empty).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(user.UID);
|
||||
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs,
|
||||
new ClientPairDto()
|
||||
{
|
||||
@@ -207,14 +214,15 @@ namespace MareSynchronosServer.Hubs
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = false,
|
||||
IsSynced = true
|
||||
}, user.CharacterIdentification).ConfigureAwait(false);
|
||||
}, userIdent).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(otherUser.CharacterIdentification))
|
||||
var otherIdent = _clientIdentService.GetCharacterIdentForUid(otherUser.UID);
|
||||
if (!string.IsNullOrEmpty(otherIdent))
|
||||
{
|
||||
await Clients.User(user.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherUser.CharacterIdentification).ConfigureAwait(false);
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, user.CharacterIdentification).ConfigureAwait(false);
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, userIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +241,8 @@ namespace MareSynchronosServer.Hubs
|
||||
pair.IsPaused = isPaused;
|
||||
_dbContext.Update(pair);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var selfCharaIdent = (await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false)).CharacterIdentification;
|
||||
var otherCharaIdent = (await _dbContext.Users.SingleAsync(u => u.UID == otherUserUid).ConfigureAwait(false)).CharacterIdentification;
|
||||
var selfCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
var otherCharaIdent = _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID);
|
||||
var otherEntry = OppositeEntry(otherUserUid);
|
||||
|
||||
await Clients.User(AuthenticatedUserId)
|
||||
@@ -282,27 +290,29 @@ namespace MareSynchronosServer.Hubs
|
||||
_dbContext.ClientPairs.Remove(wl);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var otherEntry = OppositeEntry(uid);
|
||||
var otherIdent = _clientIdentService.GetCharacterIdentForUid(otherUser.UID);
|
||||
await Clients.User(sender.UID)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = otherUser.UID,
|
||||
IsRemoved = true
|
||||
}, otherUser.CharacterIdentification).ConfigureAwait(false);
|
||||
}, otherIdent).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(otherUser.CharacterIdentification))
|
||||
if (!string.IsNullOrEmpty(otherIdent))
|
||||
{
|
||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
await Clients.User(sender.UID)
|
||||
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherUser.CharacterIdentification).ConfigureAwait(false);
|
||||
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID)
|
||||
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, sender.CharacterIdentification).ConfigureAwait(false);
|
||||
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, ownIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = sender.UID,
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = false,
|
||||
IsSynced = false
|
||||
}, sender.CharacterIdentification).ConfigureAwait(false);
|
||||
}, ownIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronosServer.Services;
|
||||
using MareSynchronosShared.Authentication;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Protos;
|
||||
using MareSynchronosShared.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
@@ -15,27 +17,30 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronosServer.Hubs
|
||||
namespace MareSynchronosServer.Hubs;
|
||||
|
||||
public partial class MareHub : Hub
|
||||
{
|
||||
public partial class MareHub : Hub
|
||||
{
|
||||
private readonly MareMetrics _mareMetrics;
|
||||
private readonly AuthService.AuthServiceClient _authServiceClient;
|
||||
private readonly FileService.FileServiceClient _fileServiceClient;
|
||||
private readonly SystemInfoService _systemInfoService;
|
||||
private readonly IHttpContextAccessor contextAccessor;
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private readonly IClientIdentificationService _clientIdentService;
|
||||
private readonly ILogger<MareHub> _logger;
|
||||
private readonly MareDbContext _dbContext;
|
||||
private readonly Uri cdnFullUri;
|
||||
private readonly Uri _cdnFullUri;
|
||||
public MareHub(MareMetrics mareMetrics, AuthService.AuthServiceClient authServiceClient, FileService.FileServiceClient fileServiceClient,
|
||||
MareDbContext mareDbContext, ILogger<MareHub> logger, SystemInfoService systemInfoService, IConfiguration configuration, IHttpContextAccessor contextAccessor)
|
||||
MareDbContext mareDbContext, ILogger<MareHub> logger, SystemInfoService systemInfoService, IConfiguration configuration, IHttpContextAccessor contextAccessor,
|
||||
IClientIdentificationService clientIdentService)
|
||||
{
|
||||
_mareMetrics = mareMetrics;
|
||||
_authServiceClient = authServiceClient;
|
||||
_fileServiceClient = fileServiceClient;
|
||||
_systemInfoService = systemInfoService;
|
||||
cdnFullUri = new Uri(configuration.GetRequiredSection("MareSynchronos").GetValue<string>("CdnFullUrl"));
|
||||
this.contextAccessor = contextAccessor;
|
||||
_cdnFullUri = new Uri(configuration.GetRequiredSection("MareSynchronos").GetValue<string>("CdnFullUrl"));
|
||||
_contextAccessor = contextAccessor;
|
||||
_clientIdentService = clientIdentService;
|
||||
_logger = logger;
|
||||
_dbContext = mareDbContext;
|
||||
}
|
||||
@@ -57,20 +62,17 @@ namespace MareSynchronosServer.Hubs
|
||||
if (!string.IsNullOrEmpty(userId) && !isBanned && !string.IsNullOrEmpty(characterIdentification))
|
||||
{
|
||||
var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId).ConfigureAwait(false));
|
||||
if (!string.IsNullOrEmpty(user.CharacterIdentification) && characterIdentification != user.CharacterIdentification)
|
||||
var existingIdent = _clientIdentService.GetCharacterIdentForUid(userId);
|
||||
if (!string.IsNullOrEmpty(existingIdent) && characterIdentification != existingIdent)
|
||||
{
|
||||
return new ConnectionDto()
|
||||
{
|
||||
ServerVersion = Api.Version
|
||||
};
|
||||
}
|
||||
else if (string.IsNullOrEmpty(user.CharacterIdentification))
|
||||
{
|
||||
_mareMetrics.IncGauge(MetricsAPI.GaugeAuthorizedConnections);
|
||||
}
|
||||
|
||||
user.LastLoggedIn = DateTime.UtcNow;
|
||||
user.CharacterIdentification = characterIdentification;
|
||||
_clientIdentService.MarkUserOnline(user.UID, characterIdentification);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
return new ConnectionDto
|
||||
@@ -90,7 +92,7 @@ namespace MareSynchronosServer.Hubs
|
||||
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
_logger.LogInformation("Connection from {ip}", contextAccessor.GetIpAddress());
|
||||
_logger.LogInformation("Connection from {ip}", _contextAccessor.GetIpAddress());
|
||||
_mareMetrics.IncGauge(MetricsAPI.GaugeConnections);
|
||||
await base.OnConnectedAsync().ConfigureAwait(false);
|
||||
}
|
||||
@@ -99,9 +101,11 @@ namespace MareSynchronosServer.Hubs
|
||||
{
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
|
||||
|
||||
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
||||
if (user != null && !string.IsNullOrEmpty(user.CharacterIdentification))
|
||||
var userCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
|
||||
if (!string.IsNullOrEmpty(userCharaIdent))
|
||||
{
|
||||
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId)!.ConfigureAwait(false);
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugeAuthorizedConnections);
|
||||
|
||||
_logger.LogInformation("Disconnect from {id}", AuthenticatedUserId);
|
||||
@@ -126,11 +130,11 @@ namespace MareSynchronosServer.Hubs
|
||||
select otherToUser.UserUID;
|
||||
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
|
||||
|
||||
await Clients.Users(otherEntries).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, user.CharacterIdentification).ConfigureAwait(false);
|
||||
await Clients.Users(otherEntries).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, userCharaIdent).ConfigureAwait(false);
|
||||
|
||||
_dbContext.RemoveRange(_dbContext.Files.Where(f => !f.Uploaded && f.UploaderUID == user.UID));
|
||||
|
||||
user.CharacterIdentification = null;
|
||||
_clientIdentService.MarkUserOffline(user.UID);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -143,5 +147,4 @@ namespace MareSynchronosServer.Hubs
|
||||
{
|
||||
return await _dbContext.Users.AsNoTrackingWithIdentityResolution().SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,6 @@ namespace MareSynchronosServer
|
||||
context.SaveChanges();
|
||||
|
||||
// clean up residuals
|
||||
var users = context.Users;
|
||||
foreach (var user in users)
|
||||
{
|
||||
user.CharacterIdentification = null;
|
||||
}
|
||||
var looseFiles = context.Files.Where(f => f.Uploaded == false);
|
||||
var unfinishedRegistrations = context.LodeStoneAuth.Where(c => c.StartedAt != null);
|
||||
context.RemoveRange(unfinishedRegistrations);
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronosServer.Hubs;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Protos;
|
||||
using MareSynchronosShared.Services;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronosServer;
|
||||
namespace MareSynchronosServer.Services;
|
||||
|
||||
public class SystemInfoService : IHostedService, IDisposable
|
||||
{
|
||||
private readonly MareMetrics _mareMetrics;
|
||||
private readonly IClientIdentificationService clientIdentService;
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<SystemInfoService> _logger;
|
||||
private readonly IHubContext<MareHub> _hubContext;
|
||||
private Timer _timer;
|
||||
public SystemInfoDto SystemInfoDto { get; private set; } = new();
|
||||
|
||||
public SystemInfoService(MareMetrics mareMetrics, IServiceProvider services, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
|
||||
public SystemInfoService(MareMetrics mareMetrics, IClientIdentificationService clientIdentService, IServiceProvider services, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
|
||||
{
|
||||
_mareMetrics = mareMetrics;
|
||||
this.clientIdentService = clientIdentService;
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
_hubContext = hubContext;
|
||||
@@ -56,8 +56,6 @@ public class SystemInfoService : IHostedService, IDisposable
|
||||
using var scope = _services.CreateScope();
|
||||
using var db = scope.ServiceProvider.GetService<MareDbContext>()!;
|
||||
|
||||
var users = db.Users.Count(c => c.CharacterIdentification != null);
|
||||
|
||||
SystemInfoDto = new SystemInfoDto()
|
||||
{
|
||||
CacheUsage = 0,
|
||||
@@ -65,7 +63,7 @@ public class SystemInfoService : IHostedService, IDisposable
|
||||
RAMUsage = 0,
|
||||
NetworkIn = 0,
|
||||
NetworkOut = 0,
|
||||
OnlineUsers = users,
|
||||
OnlineUsers = clientIdentService.GetOnlineUsers(),
|
||||
UploadedFiles = 0
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ using Grpc.Net.Client.Configuration;
|
||||
using Prometheus;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using System.Collections.Generic;
|
||||
using MareSynchronosServer.Services;
|
||||
using MareSynchronosShared.Services;
|
||||
|
||||
namespace MareSynchronosServer
|
||||
{
|
||||
@@ -101,18 +103,18 @@ namespace MareSynchronosServer
|
||||
options.EnableThreadSafetyChecks(false);
|
||||
}, mareConfig.GetValue("DbContextPoolSize", 1024));
|
||||
|
||||
|
||||
services.AddHostedService(provider => provider.GetService<SystemInfoService>());
|
||||
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultScheme = SecretKeyGrpcAuthenticationHandler.AuthScheme;
|
||||
})
|
||||
.AddScheme<AuthenticationSchemeOptions, SecretKeyGrpcAuthenticationHandler>(SecretKeyGrpcAuthenticationHandler.AuthScheme, options => { });
|
||||
}).AddScheme<AuthenticationSchemeOptions, SecretKeyGrpcAuthenticationHandler>(SecretKeyGrpcAuthenticationHandler.AuthScheme, _ => { });
|
||||
services.AddAuthorization(options => options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
|
||||
|
||||
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
||||
|
||||
var signalRserviceBuilder = services.AddSignalR(hubOptions =>
|
||||
var signalRServiceBuilder = services.AddSignalR(hubOptions =>
|
||||
{
|
||||
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
|
||||
hubOptions.EnableDetailedErrors = true;
|
||||
@@ -120,13 +122,28 @@ namespace MareSynchronosServer
|
||||
hubOptions.StreamBufferCapacity = 200;
|
||||
hubOptions.AddFilter<SignalRLimitFilter>();
|
||||
});
|
||||
|
||||
// add redis related options
|
||||
var redis = mareConfig.GetValue("RedisConnectionString", string.Empty);
|
||||
if (!string.IsNullOrEmpty(redis))
|
||||
{
|
||||
signalRserviceBuilder.AddStackExchangeRedis(redis, options =>
|
||||
signalRServiceBuilder.AddStackExchangeRedis(redis, options =>
|
||||
{
|
||||
options.Configuration.ChannelPrefix = "MareSynchronos";
|
||||
});
|
||||
|
||||
services.AddStackExchangeRedisCache(opt =>
|
||||
{
|
||||
opt.Configuration = redis;
|
||||
opt.InstanceName = "MareSynchronos";
|
||||
});
|
||||
services.AddSingleton<IClientIdentificationService, DistributedClientIdentificationService>();
|
||||
services.AddHostedService(p => p.GetService<DistributedClientIdentificationService>());
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IClientIdentificationService, LocalClientIdentificationService>();
|
||||
services.AddHostedService(p => p.GetService<LocalClientIdentificationService>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using MareSynchronosServices.Authentication;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -26,6 +27,7 @@ public class DiscordBot : IHostedService
|
||||
{
|
||||
private readonly CleanupService cleanupService;
|
||||
private readonly MareMetrics metrics;
|
||||
private readonly IClientIdentificationService clientService;
|
||||
private readonly IServiceProvider services;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<DiscordBot> logger;
|
||||
@@ -44,10 +46,11 @@ public class DiscordBot : IHostedService
|
||||
|
||||
private SemaphoreSlim semaphore;
|
||||
|
||||
public DiscordBot(CleanupService cleanupService, MareMetrics metrics, IServiceProvider services, IConfiguration configuration, ILogger<DiscordBot> logger)
|
||||
public DiscordBot(CleanupService cleanupService, MareMetrics metrics, IClientIdentificationService clientService, IServiceProvider services, IConfiguration configuration, ILogger<DiscordBot> logger)
|
||||
{
|
||||
this.cleanupService = cleanupService;
|
||||
this.metrics = metrics;
|
||||
this.clientService = clientService;
|
||||
this.services = services;
|
||||
_configuration = configuration.GetRequiredSection("MareSynchronos");
|
||||
this.logger = logger;
|
||||
@@ -687,13 +690,7 @@ public class DiscordBot : IHostedService
|
||||
updateStatusCts = new();
|
||||
while (!updateStatusCts.IsCancellationRequested)
|
||||
{
|
||||
await using var scope = services.CreateAsyncScope();
|
||||
await using (var db = scope.ServiceProvider.GetRequiredService<MareDbContext>())
|
||||
{
|
||||
var users = db.Users.Count(c => c.CharacterIdentification != null);
|
||||
await discordClient.SetActivityAsync(new Game("Mare for " + users + " Users")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await discordClient.SetActivityAsync(new Game("Mare for " + clientService.GetOnlineUsers() + " Users")).ConfigureAwait(false);
|
||||
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Prometheus;
|
||||
using System.Collections.Generic;
|
||||
using MareSynchronosShared.Services;
|
||||
|
||||
namespace MareSynchronosServices;
|
||||
|
||||
@@ -49,6 +50,24 @@ public class Startup
|
||||
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 = "MareSynchronos";
|
||||
});
|
||||
services.AddSingleton<IClientIdentificationService, DistributedClientIdentificationService>();
|
||||
services.AddHostedService(p => p.GetService<DistributedClientIdentificationService>());
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IClientIdentificationService, LocalClientIdentificationService>();
|
||||
services.AddHostedService(p => p.GetService<LocalClientIdentificationService>());
|
||||
}
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
|
||||
@@ -45,7 +45,7 @@ public class MareDbContext : DbContext
|
||||
{
|
||||
modelBuilder.Entity<Auth>().ToTable("auth");
|
||||
modelBuilder.Entity<User>().ToTable("users");
|
||||
modelBuilder.Entity<User>().HasIndex(c => c.CharacterIdentification);
|
||||
//modelBuilder.Entity<User>().HasIndex(c => c.CharacterIdentification);
|
||||
modelBuilder.Entity<FileCache>().ToTable("file_caches");
|
||||
modelBuilder.Entity<FileCache>().HasIndex(c => c.UploaderUID);
|
||||
modelBuilder.Entity<ClientPair>().ToTable("client_pairs");
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.8" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.6" />
|
||||
<PackageReference Include="prometheus-net" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace MareSynchronosShared.Models
|
||||
[Key]
|
||||
[MaxLength(10)]
|
||||
public string UID { get; set; }
|
||||
[MaxLength(100)]
|
||||
public string CharacterIdentification { get; set; }
|
||||
//[MaxLength(100)]
|
||||
//public string CharacterIdentification { get; set; }
|
||||
[Timestamp]
|
||||
public byte[] Timestamp { get; set; }
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
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 int GetOnlineUsers()
|
||||
{
|
||||
return OnlineClients.Count;
|
||||
}
|
||||
|
||||
public string? GetUidForCharacterIdent(string characterIdent)
|
||||
{
|
||||
var result = OnlineClients.SingleOrDefault(u =>
|
||||
string.Compare(u.Value, characterIdent, StringComparison.InvariantCultureIgnoreCase) == 0);
|
||||
return result.Equals(new KeyValuePair<string, string>()) ? null : result.Key;
|
||||
}
|
||||
|
||||
public virtual string? GetCharacterIdentForUid(string uid)
|
||||
{
|
||||
if (!OnlineClients.TryGetValue(uid, out var result))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual void MarkUserOnline(string uid, string charaIdent)
|
||||
{
|
||||
OnlineClients[uid] = charaIdent;
|
||||
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
|
||||
}
|
||||
|
||||
public virtual void MarkUserOffline(string uid)
|
||||
{
|
||||
if (OnlineClients.TryRemove(uid, out _))
|
||||
{
|
||||
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public virtual Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, 0);
|
||||
OnlineClients = new();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Text;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace MareSynchronosShared.Services;
|
||||
|
||||
public class DistributedClientIdentificationService : BaseClientIdentificationService
|
||||
{
|
||||
private readonly IDistributedCache distributedCache;
|
||||
private readonly IConfiguration configuration;
|
||||
private const string RedisPrefix = "uidcache:";
|
||||
|
||||
public DistributedClientIdentificationService(MareMetrics metrics, IDistributedCache distributedCache, IConfiguration configuration) : base(metrics)
|
||||
{
|
||||
this.distributedCache = distributedCache;
|
||||
this.configuration = configuration.GetSection("MareSynchronos");
|
||||
}
|
||||
|
||||
public override int GetOnlineUsers()
|
||||
{
|
||||
var redis = configuration.GetValue<string>("RedisConnectionString");
|
||||
var conn = ConnectionMultiplexer.Connect(redis);
|
||||
var endpoint = conn.GetEndPoints().First();
|
||||
return conn.GetServer(endpoint).Keys(pattern: RedisPrefix + "*").Count();
|
||||
}
|
||||
|
||||
public override string? GetCharacterIdentForUid(string uid)
|
||||
{
|
||||
var localIdent = base.GetCharacterIdentForUid(uid);
|
||||
if (localIdent != null) return localIdent;
|
||||
var cachedIdent = distributedCache.Get(RedisPrefix + uid);
|
||||
return cachedIdent == null ? null : Encoding.UTF8.GetString(cachedIdent);
|
||||
}
|
||||
|
||||
public override void MarkUserOffline(string uid)
|
||||
{
|
||||
base.MarkUserOffline(uid);
|
||||
distributedCache.Remove(RedisPrefix + uid);
|
||||
}
|
||||
|
||||
public override void MarkUserOnline(string uid, string charaIdent)
|
||||
{
|
||||
base.MarkUserOnline(uid, charaIdent);
|
||||
distributedCache.Set(RedisPrefix + uid, Encoding.UTF8.GetBytes(charaIdent));
|
||||
}
|
||||
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var uid in OnlineClients)
|
||||
{
|
||||
distributedCache.Remove(RedisPrefix + uid.Key);
|
||||
}
|
||||
return base.StopAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace MareSynchronosShared.Services;
|
||||
|
||||
public interface IClientIdentificationService : IHostedService
|
||||
{
|
||||
int GetOnlineUsers();
|
||||
string? GetUidForCharacterIdent(string characterIdent);
|
||||
string? GetCharacterIdentForUid(string uid);
|
||||
void MarkUserOnline(string uid, string charaIdent);
|
||||
void MarkUserOffline(string uid);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using MareSynchronosShared.Metrics;
|
||||
|
||||
namespace MareSynchronosShared.Services;
|
||||
|
||||
public class LocalClientIdentificationService : BaseClientIdentificationService
|
||||
{
|
||||
public LocalClientIdentificationService(MareMetrics metrics) : base(metrics)
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user