Syncshells (#11)
* some groups stuff * further groups rework * fixes for pause changes * adjsut timeout interval * fixes and namespace change to file scoped * more fixes * further implement groups * fix change group ownership * add some more stuff for groups * more fixes and additions * some fixes based on analyzers, add shard info to ui * add discord command, cleanup * fix regex * add group migration and deletion on user deletion * add api method for client to check health of connection * adjust regex for vanity * fixes for server and bot * fixes some string comparison in linq queries * fixes group leave and sets alias to null * fix syntax in changeownership * add better logging, fixes for group leaving * fixes for group leave Co-authored-by: Stanley Dimant <root.darkarchon@outlook.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MareSynchronos.API;
|
||||
using MareSynchronosServer.Utils;
|
||||
using MareSynchronosShared.Authentication;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using MareSynchronosShared.Models;
|
||||
@@ -11,315 +12,340 @@ using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronosServer.Hubs
|
||||
namespace MareSynchronosServer.Hubs;
|
||||
|
||||
public partial class MareHub
|
||||
{
|
||||
public partial class MareHub
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserDeleteAccount)]
|
||||
public async Task DeleteAccount()
|
||||
{
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserDeleteAccount)]
|
||||
public async Task DeleteAccount()
|
||||
_logger.LogCallInfo(Api.SendUserDeleteAccount);
|
||||
|
||||
string userid = AuthenticatedUserId;
|
||||
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid).ConfigureAwait(false);
|
||||
var charaIdent = await _clientIdentService.GetCharacterIdentForUid(userid).ConfigureAwait(false);
|
||||
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);
|
||||
var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupUserUID == userid).ToListAsync().ConfigureAwait(false);
|
||||
|
||||
if (lodestone != null)
|
||||
{
|
||||
_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);
|
||||
|
||||
if (lodestone != null)
|
||||
{
|
||||
_dbContext.Remove(lodestone);
|
||||
}
|
||||
|
||||
while (_dbContext.Files.Any(f => f.Uploader == userEntry))
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await _authServiceClient.RemoveAuthAsync(new RemoveAuthRequest() { Uid = userid }).ConfigureAwait(false);
|
||||
|
||||
|
||||
_dbContext.RemoveRange(ownPairData);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
|
||||
.Where(u => u.OtherUser.UID == userid).ToListAsync().ConfigureAwait(false);
|
||||
foreach (var pair in otherPairData)
|
||||
{
|
||||
await Clients.User(pair.User.UID)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = userid,
|
||||
IsRemoved = true
|
||||
}, charaIdent).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugePairs, ownPairData.Count + otherPairData.Count);
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugePairsPaused, ownPairData.Count(c => c.IsPaused));
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUsersRegisteredDeleted, 1);
|
||||
|
||||
_dbContext.RemoveRange(otherPairData);
|
||||
_dbContext.Remove(userEntry);
|
||||
_dbContext.Remove(auth);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
_dbContext.Remove(lodestone);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserGetOnlineCharacters)]
|
||||
public async Task<List<string>> GetOnlineCharacters()
|
||||
while (_dbContext.Files.Any(f => f.Uploader == userEntry))
|
||||
{
|
||||
_logger.LogInformation("User {AuthenticatedUserId} requested online characters", AuthenticatedUserId);
|
||||
|
||||
var ownUser = await GetAuthenticatedUserUntrackedAsync().ConfigureAwait(false);
|
||||
|
||||
var otherUsers = await _dbContext.ClientPairs.AsNoTracking()
|
||||
.Include(u => u.User)
|
||||
.Include(u => u.OtherUser)
|
||||
.Where(w => w.User.UID == ownUser.UID && !w.IsPaused)
|
||||
//.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 => 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, ownIdent).ConfigureAwait(false);
|
||||
return otherEntries.Select(e => _clientIdentService.GetCharacterIdentForUid(e.User.UID)).Distinct().ToList();
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserGetPairedClients)]
|
||||
public async Task<List<ClientPairDto>> GetPairedClients()
|
||||
{
|
||||
string userid = AuthenticatedUserId;
|
||||
var query =
|
||||
from userToOther in _dbContext.ClientPairs
|
||||
join otherToUser in _dbContext.ClientPairs
|
||||
on new
|
||||
{
|
||||
user = userToOther.UserUID,
|
||||
other = userToOther.OtherUserUID
|
||||
await _authServiceClient.RemoveAuthAsync(new RemoveAuthRequest() { Uid = userid }).ConfigureAwait(false);
|
||||
|
||||
} equals new
|
||||
{
|
||||
user = otherToUser.OtherUserUID,
|
||||
other = otherToUser.UserUID
|
||||
} into leftJoin
|
||||
from otherEntry in leftJoin.DefaultIfEmpty()
|
||||
where
|
||||
userToOther.UserUID == userid
|
||||
select new
|
||||
_dbContext.RemoveRange(ownPairData);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
|
||||
.Where(u => u.OtherUser.UID == userid).ToListAsync().ConfigureAwait(false);
|
||||
foreach (var pair in otherPairData)
|
||||
{
|
||||
await Clients.User(pair.User.UID)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
userToOther.OtherUser.Alias,
|
||||
userToOther.IsPaused,
|
||||
OtherIsPaused = otherEntry != null && otherEntry.IsPaused,
|
||||
userToOther.OtherUserUID,
|
||||
IsSynced = otherEntry != null
|
||||
};
|
||||
|
||||
return (await query.ToListAsync().ConfigureAwait(false)).Select(f => new ClientPairDto()
|
||||
{
|
||||
VanityUID = f.Alias,
|
||||
IsPaused = f.IsPaused,
|
||||
OtherUID = f.OtherUserUID,
|
||||
IsSynced = f.IsSynced,
|
||||
IsPausedFromOthers = f.OtherIsPaused
|
||||
}).ToList();
|
||||
OtherUID = userid,
|
||||
IsRemoved = true
|
||||
}, charaIdent).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserPushCharacterDataToVisibleClients)]
|
||||
public async Task PushCharacterDataToVisibleClients(CharacterCacheDto characterCache, List<string> visibleCharacterIds)
|
||||
foreach (var pair in groupPairs)
|
||||
{
|
||||
_logger.LogInformation("User {AuthenticatedUserId} pushing character data to {visibleCharacterIds} visible clients", AuthenticatedUserId, visibleCharacterIds.Count);
|
||||
|
||||
var user = await GetAuthenticatedUserUntrackedAsync().ConfigureAwait(false);
|
||||
|
||||
var query =
|
||||
from userToOther in _dbContext.ClientPairs
|
||||
join otherToUser in _dbContext.ClientPairs
|
||||
on new
|
||||
{
|
||||
user = userToOther.UserUID,
|
||||
other = userToOther.OtherUserUID
|
||||
|
||||
} equals new
|
||||
{
|
||||
user = otherToUser.OtherUserUID,
|
||||
other = otherToUser.UserUID
|
||||
}
|
||||
where
|
||||
userToOther.UserUID == user.UID
|
||||
&& !userToOther.IsPaused
|
||||
&& !otherToUser.IsPaused
|
||||
select otherToUser.UserUID;
|
||||
|
||||
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
|
||||
otherEntries =
|
||||
otherEntries.Where(c => visibleCharacterIds.Select(c => c.ToLowerInvariant()).Contains(_clientIdentService.GetCharacterIdentForUid(c)?.ToLowerInvariant() ?? "")).ToList();
|
||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
|
||||
await Clients.Users(otherEntries).SendAsync(Api.OnUserReceiveCharacterData, characterCache, ownIdent).ConfigureAwait(false);
|
||||
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, otherEntries.Count);
|
||||
await GroupLeave(pair.GroupGID).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientAddition)]
|
||||
public async Task SendPairedClientAddition(string uid)
|
||||
{
|
||||
if (uid == AuthenticatedUserId || string.IsNullOrWhiteSpace(uid)) return;
|
||||
uid = uid.Trim();
|
||||
var user = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUsersRegisteredDeleted, 1);
|
||||
|
||||
var otherUser = await _dbContext.Users
|
||||
.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false);
|
||||
var existingEntry =
|
||||
await _dbContext.ClientPairs.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p =>
|
||||
p.User.UID == AuthenticatedUserId && p.OtherUser.UID == otherUser.UID).ConfigureAwait(false);
|
||||
if (otherUser == null || existingEntry != null) return;
|
||||
_logger.LogInformation("User {AuthenticatedUserId} adding {uid} to whitelist", AuthenticatedUserId, uid);
|
||||
ClientPair wl = new ClientPair()
|
||||
_dbContext.RemoveRange(otherPairData);
|
||||
_dbContext.Remove(userEntry);
|
||||
_dbContext.Remove(auth);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserGetOnlineCharacters)]
|
||||
public async Task<List<string>> GetOnlineCharacters()
|
||||
{
|
||||
_logger.LogCallInfo(Api.InvokeUserGetOnlineCharacters);
|
||||
|
||||
var ownIdent = await _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId).ConfigureAwait(false);
|
||||
|
||||
var usersToSendOnlineTo = await SendDataToAllPairedUsers(Api.OnUserAddOnlinePairedPlayer, ownIdent).ConfigureAwait(false);
|
||||
return usersToSendOnlineTo.Select(async e => await _clientIdentService.GetCharacterIdentForUid(e).ConfigureAwait(false)).Select(t => t.Result).Where(t => !string.IsNullOrEmpty(t)).Distinct(System.StringComparer.Ordinal).ToList();
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserGetPairedClients)]
|
||||
public async Task<List<ClientPairDto>> GetPairedClients()
|
||||
{
|
||||
_logger.LogCallInfo(Api.InvokeUserGetPairedClients);
|
||||
|
||||
string userid = AuthenticatedUserId;
|
||||
var query =
|
||||
from userToOther in _dbContext.ClientPairs
|
||||
join otherToUser in _dbContext.ClientPairs
|
||||
on new
|
||||
{
|
||||
user = userToOther.UserUID,
|
||||
other = userToOther.OtherUserUID
|
||||
|
||||
} equals new
|
||||
{
|
||||
user = otherToUser.OtherUserUID,
|
||||
other = otherToUser.UserUID
|
||||
} into leftJoin
|
||||
from otherEntry in leftJoin.DefaultIfEmpty()
|
||||
where
|
||||
userToOther.UserUID == userid
|
||||
select new
|
||||
{
|
||||
IsPaused = false,
|
||||
OtherUser = otherUser,
|
||||
User = user
|
||||
userToOther.OtherUser.Alias,
|
||||
userToOther.IsPaused,
|
||||
OtherIsPaused = otherEntry != null && otherEntry.IsPaused,
|
||||
userToOther.OtherUserUID,
|
||||
IsSynced = otherEntry != null
|
||||
};
|
||||
await _dbContext.ClientPairs.AddAsync(wl).ConfigureAwait(false);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var otherEntry = OppositeEntry(otherUser.UID);
|
||||
await Clients.User(user.UID)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
VanityUID = otherUser.Alias,
|
||||
OtherUID = otherUser.UID,
|
||||
IsPaused = false,
|
||||
IsPausedFromOthers = otherEntry?.IsPaused ?? false,
|
||||
IsSynced = otherEntry != null
|
||||
}, string.Empty).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(user.UID);
|
||||
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs,
|
||||
new ClientPairDto()
|
||||
{
|
||||
VanityUID = user.Alias,
|
||||
OtherUID = user.UID,
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = false,
|
||||
IsSynced = true
|
||||
}, userIdent).ConfigureAwait(false);
|
||||
|
||||
var otherIdent = _clientIdentService.GetCharacterIdentForUid(otherUser.UID);
|
||||
if (!string.IsNullOrEmpty(otherIdent))
|
||||
{
|
||||
await Clients.User(user.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, userIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
_mareMetrics.IncGauge(MetricsAPI.GaugePairs);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientPauseChange)]
|
||||
public async Task SendPairedClientPauseChange(string otherUserUid, bool isPaused)
|
||||
return (await query.ToListAsync().ConfigureAwait(false)).Select(f => new ClientPairDto()
|
||||
{
|
||||
if (otherUserUid == AuthenticatedUserId) return;
|
||||
ClientPair pair = await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == AuthenticatedUserId && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
||||
if (pair == null) return;
|
||||
VanityUID = f.Alias,
|
||||
IsPaused = f.IsPaused,
|
||||
OtherUID = f.OtherUserUID,
|
||||
IsSynced = f.IsSynced,
|
||||
IsPausedFromOthers = f.OtherIsPaused
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
_logger.LogInformation("User {AuthenticatedUserId} changed pause status with {otherUserUid} to {isPaused}", AuthenticatedUserId, otherUserUid, isPaused);
|
||||
pair.IsPaused = isPaused;
|
||||
_dbContext.Update(pair);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var selfCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
var otherCharaIdent = _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID);
|
||||
var otherEntry = OppositeEntry(otherUserUid);
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.InvokeUserPushCharacterDataToVisibleClients)]
|
||||
public async Task PushCharacterDataToVisibleClients(CharacterCacheDto characterCache, List<string> visibleCharacterIds)
|
||||
{
|
||||
_logger.LogCallInfo(Api.InvokeUserPushCharacterDataToVisibleClients, visibleCharacterIds.Count);
|
||||
|
||||
await Clients.User(AuthenticatedUserId)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = otherUserUid,
|
||||
IsPaused = isPaused,
|
||||
IsPausedFromOthers = otherEntry?.IsPaused ?? false,
|
||||
IsSynced = otherEntry != null
|
||||
}, otherCharaIdent).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
||||
|
||||
var allPairedUsersDict = allPairedUsers.ToDictionary(f => f, async f => await _clientIdentService.GetCharacterIdentForUid(f).ConfigureAwait(false), System.StringComparer.Ordinal)
|
||||
.Where(f => visibleCharacterIds.Contains(f.Value.Result, System.StringComparer.Ordinal));
|
||||
|
||||
var ownIdent = await _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId).ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(Api.InvokeUserPushCharacterDataToVisibleClients, visibleCharacterIds.Count, allPairedUsersDict.Count());
|
||||
|
||||
await Clients.Users(allPairedUsersDict.Select(f => f.Key)).SendAsync(Api.OnUserReceiveCharacterData, characterCache, ownIdent).ConfigureAwait(false);
|
||||
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, allPairedUsersDict.Count());
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientAddition)]
|
||||
public async Task SendPairedClientAddition(string uid)
|
||||
{
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientAddition, uid);
|
||||
|
||||
// don't allow adding yourself or nothing
|
||||
uid = uid.Trim();
|
||||
if (string.Equals(uid, AuthenticatedUserId, System.StringComparison.Ordinal) || string.IsNullOrWhiteSpace(uid)) return;
|
||||
|
||||
// grab other user, check if it exists and if a pair already exists
|
||||
var otherUser = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false);
|
||||
var existingEntry =
|
||||
await _dbContext.ClientPairs.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p =>
|
||||
p.User.UID == AuthenticatedUserId && p.OtherUserUID == uid).ConfigureAwait(false);
|
||||
if (otherUser == null || existingEntry != null) return;
|
||||
|
||||
// grab self create new client pair and save
|
||||
var user = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientAddition, uid, "Success");
|
||||
|
||||
ClientPair wl = new ClientPair()
|
||||
{
|
||||
IsPaused = false,
|
||||
OtherUser = otherUser,
|
||||
User = user
|
||||
};
|
||||
await _dbContext.ClientPairs.AddAsync(wl).ConfigureAwait(false);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
// get the opposite entry of the client pair
|
||||
var otherEntry = OppositeEntry(otherUser.UID);
|
||||
await Clients.User(user.UID)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = AuthenticatedUserId,
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = isPaused,
|
||||
IsSynced = true
|
||||
}, selfCharaIdent).ConfigureAwait(false);
|
||||
}
|
||||
VanityUID = otherUser.Alias,
|
||||
OtherUID = otherUser.UID,
|
||||
IsPaused = false,
|
||||
IsPausedFromOthers = otherEntry?.IsPaused ?? false,
|
||||
IsSynced = otherEntry != null
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
// if there's no opposite entry do nothing
|
||||
if (otherEntry == null) return;
|
||||
|
||||
// check if other user is online
|
||||
var otherIdent = await _clientIdentService.GetCharacterIdentForUid(otherUser.UID).ConfigureAwait(false);
|
||||
if (otherIdent == null) return;
|
||||
|
||||
// send push with update to other user if other user is online
|
||||
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs,
|
||||
new ClientPairDto()
|
||||
{
|
||||
VanityUID = user.Alias,
|
||||
OtherUID = user.UID,
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = false,
|
||||
IsSynced = true
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
// get own ident and all pairs
|
||||
var userIdent = await _clientIdentService.GetCharacterIdentForUid(user.UID).ConfigureAwait(false);
|
||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
||||
|
||||
// if the other user has paused the main user and there was no previous group connection don't send anything
|
||||
if (!otherEntry.IsPaused && allUserPairs.Any(p => string.Equals(p.UID, uid, System.StringComparison.Ordinal) && p.IsPausedPerGroup is PauseInfo.Paused or PauseInfo.NoConnection))
|
||||
{
|
||||
await Clients.User(user.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID)
|
||||
.SendAsync(Api.OnUserAddOnlinePairedPlayer, userIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientPauseChange)]
|
||||
public async Task SendPairedClientPauseChange(string otherUserUid, bool isPaused)
|
||||
{
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientPauseChange, otherUserUid, isPaused);
|
||||
|
||||
if (string.Equals(otherUserUid, AuthenticatedUserId, System.StringComparison.Ordinal)) return;
|
||||
ClientPair pair = await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == AuthenticatedUserId && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
||||
if (pair == null) return;
|
||||
|
||||
pair.IsPaused = isPaused;
|
||||
_dbContext.Update(pair);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientPauseChange, otherUserUid, isPaused, "Success");
|
||||
|
||||
var otherEntry = OppositeEntry(otherUserUid);
|
||||
|
||||
await Clients.User(AuthenticatedUserId)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = otherUserUid,
|
||||
IsPaused = isPaused,
|
||||
IsPausedFromOthers = otherEntry?.IsPaused ?? false,
|
||||
IsSynced = otherEntry != null
|
||||
}).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = AuthenticatedUserId,
|
||||
IsPaused = otherEntry.IsPaused,
|
||||
IsPausedFromOthers = isPaused,
|
||||
IsSynced = true
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
var selfCharaIdent = await _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId).ConfigureAwait(false);
|
||||
var otherCharaIdent = await _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID).ConfigureAwait(false);
|
||||
|
||||
if (selfCharaIdent == null || otherCharaIdent == null || otherEntry.IsPaused) return;
|
||||
|
||||
if (isPaused)
|
||||
{
|
||||
_mareMetrics.IncGauge(MetricsAPI.GaugePairsPaused);
|
||||
await Clients.User(AuthenticatedUserId).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherCharaIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, selfCharaIdent).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugePairsPaused);
|
||||
await Clients.User(AuthenticatedUserId).SendAsync(Api.OnUserAddOnlinePairedPlayer, otherCharaIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserAddOnlinePairedPlayer, selfCharaIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientRemoval)]
|
||||
public async Task SendPairedClientRemoval(string uid)
|
||||
{
|
||||
if (uid == AuthenticatedUserId) return;
|
||||
|
||||
var sender = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
||||
var otherUser = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == uid).ConfigureAwait(false);
|
||||
if (otherUser == null) return;
|
||||
_logger.LogInformation("User {AuthenticatedUserId} removed {uid} from whitelist", AuthenticatedUserId, uid);
|
||||
ClientPair wl =
|
||||
await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.User == sender && w.OtherUser == otherUser).ConfigureAwait(false);
|
||||
if (wl == null) return;
|
||||
_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
|
||||
}, otherIdent).ConfigureAwait(false);
|
||||
if (otherEntry != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(otherIdent))
|
||||
{
|
||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
||||
await Clients.User(sender.UID)
|
||||
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUser.UID)
|
||||
.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
|
||||
}, ownIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
_mareMetrics.DecGauge(MetricsAPI.GaugePairs);
|
||||
}
|
||||
|
||||
private ClientPair OppositeEntry(string otherUID) =>
|
||||
_dbContext.ClientPairs.AsNoTracking().SingleOrDefault(w => w.User.UID == otherUID && w.OtherUser.UID == AuthenticatedUserId);
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
|
||||
[HubMethodName(Api.SendUserPairedClientRemoval)]
|
||||
public async Task SendPairedClientRemoval(string otherUserUid)
|
||||
{
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientRemoval, otherUserUid);
|
||||
|
||||
if (string.Equals(otherUserUid, AuthenticatedUserId, System.StringComparison.Ordinal)) return;
|
||||
|
||||
// check if client pair even exists
|
||||
ClientPair callerPair =
|
||||
await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == AuthenticatedUserId && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
||||
bool callerHadPaused = callerPair.IsPaused;
|
||||
if (callerPair == null) return;
|
||||
|
||||
// delete from database, send update info to users pair list
|
||||
_dbContext.ClientPairs.Remove(callerPair);
|
||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(Api.SendUserPairedClientRemoval, otherUserUid, "Success");
|
||||
|
||||
await Clients.User(AuthenticatedUserId)
|
||||
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
|
||||
{
|
||||
OtherUID = otherUserUid,
|
||||
IsRemoved = true
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
// check if opposite entry exists
|
||||
var oppositeClientPair = OppositeEntry(otherUserUid);
|
||||
if (oppositeClientPair == null) return;
|
||||
|
||||
// check if other user is online, if no then there is no need to do anything further
|
||||
var otherIdent = await _clientIdentService.GetCharacterIdentForUid(otherUserUid).ConfigureAwait(false);
|
||||
if (otherIdent == null) return;
|
||||
|
||||
// get own ident and
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserUpdateClientPairs,
|
||||
new ClientPairDto()
|
||||
{
|
||||
OtherUID = AuthenticatedUserId,
|
||||
IsPausedFromOthers = false,
|
||||
IsSynced = false
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
// if the other user had paused the user the state will be offline for either, do nothing
|
||||
bool otherHadPaused = oppositeClientPair.IsPaused;
|
||||
if (!callerHadPaused && otherHadPaused) return;
|
||||
|
||||
var allUsers = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
||||
var pauseEntry = allUsers.SingleOrDefault(f => string.Equals(f.UID, otherUserUid, System.StringComparison.Ordinal));
|
||||
var isPausedInGroup = pauseEntry == null || pauseEntry.IsPausedPerGroup is PauseInfo.Paused or PauseInfo.NoConnection;
|
||||
|
||||
// if neither user had paused each other and both are in unpaused groups, state will be online for both, do nothing
|
||||
if (!callerHadPaused && !otherHadPaused && !isPausedInGroup) return;
|
||||
|
||||
// if neither user had paused each other and either is not in an unpaused group with each other, change state to offline
|
||||
if (!callerHadPaused && !otherHadPaused && isPausedInGroup)
|
||||
{
|
||||
var userIdent = await _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId).ConfigureAwait(false);
|
||||
await Clients.User(AuthenticatedUserId).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, userIdent).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// if the caller had paused other but not the other has paused the caller and they are in an unpaused group together, change state to online
|
||||
if (callerHadPaused && !otherHadPaused && !isPausedInGroup)
|
||||
{
|
||||
var userIdent = await _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId).ConfigureAwait(false);
|
||||
await Clients.User(AuthenticatedUserId).SendAsync(Api.OnUserAddOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
|
||||
await Clients.User(otherUserUid).SendAsync(Api.OnUserAddOnlinePairedPlayer, userIdent).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private ClientPair OppositeEntry(string otherUID) =>
|
||||
_dbContext.ClientPairs.AsNoTracking().SingleOrDefault(w => w.User.UID == otherUID && w.OtherUser.UID == AuthenticatedUserId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user