private async Task UpdateAliasNew(string originalName, int?ip, Data.Models.Client.EFClient entity, DatabaseContext context) { var name = originalName.CapClientName(EFAlias.MAX_NAME_LENGTH); var existingAliases = await context.Aliases .Where(alias => alias.Name == name && alias.LinkId == entity.AliasLinkId || alias.Name == name && alias.IPAddress != null && alias.IPAddress == ip) .ToListAsync(); var defaultAlias = existingAliases.FirstOrDefault(alias => alias.IPAddress == null); var existingExactAlias = existingAliases.FirstOrDefault(alias => alias.IPAddress != null && alias.IPAddress == ip); if (defaultAlias != null && existingExactAlias == null) { defaultAlias.IPAddress = ip; entity.CurrentAlias = defaultAlias; entity.CurrentAliasId = defaultAlias.AliasId; await context.SaveChangesAsync(); return; } if (existingExactAlias != null && entity.AliasLinkId == existingExactAlias.LinkId) { entity.CurrentAlias = existingExactAlias; entity.CurrentAliasId = existingExactAlias.AliasId; await context.SaveChangesAsync(); _logger.LogDebug("[{Method}] client {Client} already has an existing exact alias, so we are not making changes", nameof(UpdateAliasNew), entity.ToString()); return; } _logger.LogDebug("[{Method}] {Entity} is using a new alias", nameof(UpdateAliasNew), entity.ToString()); var newAlias = new EFAlias() { DateAdded = DateTime.UtcNow, IPAddress = ip, LinkId = entity.AliasLinkId, Name = name, SearchableName = name.StripColors().ToLower(), Active = true, }; entity.CurrentAlias = newAlias; await context.SaveChangesAsync(); entity.CurrentAliasId = newAlias.AliasId; }
private async Task UpdateAlias(string originalName, int?ip, Data.Models.Client.EFClient entity, DatabaseContext context) { { string name = originalName.CapClientName(EFAlias.MAX_NAME_LENGTH); // entity is the tracked db context item // get all aliases by IP address and LinkId var iqAliases = context.Aliases .Include(a => a.Link) // we only want alias that have the same IP address or share a link .Where(_alias => _alias.IPAddress == ip || (_alias.LinkId == entity.AliasLinkId)); var aliases = await iqAliases.ToListAsync(); var currentIPs = aliases.Where(_a2 => _a2.IPAddress != null).Select(_a2 => _a2.IPAddress).Distinct(); var floatingIPAliases = await context.Aliases.Where(_alias => currentIPs.Contains(_alias.IPAddress)) .ToListAsync(); aliases.AddRange(floatingIPAliases); // see if they have a matching IP + Name but new NetworkId var existingExactAlias = aliases.OrderBy(_alias => _alias.LinkId) .FirstOrDefault(a => a.Name == name && a.IPAddress == ip); bool hasExactAliasMatch = existingExactAlias != null; // if existing alias matches link them var newAliasLink = existingExactAlias?.Link; // if no exact matches find the first IP or LinkId that matches newAliasLink = newAliasLink ?? aliases.OrderBy(_alias => _alias.LinkId).FirstOrDefault()?.Link; // if no matches are found, use our current one ( it will become permanent ) newAliasLink = newAliasLink ?? entity.AliasLink; bool hasExistingAlias = aliases.Count > 0; bool isAliasLinkUpdated = newAliasLink.AliasLinkId != entity.AliasLink.AliasLinkId; await context.SaveChangesAsync(); int distinctLinkCount = aliases.Select(_alias => _alias.LinkId).Distinct().Count(); // this happens when the link we found is different than the one we create before adding an IP if (isAliasLinkUpdated || distinctLinkCount > 1) { _logger.LogDebug( "[updatealias] found a link for {entity} so we are updating link from {oldAliasLinkId} to {newAliasLinkId}", entity.ToString(), entity.AliasLink.AliasLinkId, newAliasLink.AliasLinkId); var completeAliasLinkIds = aliases.Select(_item => _item.LinkId) .Append(entity.AliasLinkId) .Distinct() .ToList(); _logger.LogDebug("[updatealias] updating aliasLinks {links} for IP {ip} to {linkId}", string.Join(',', completeAliasLinkIds), ip, newAliasLink.AliasLinkId); // update all the clients that have the old alias link await context.Clients .Where(_client => completeAliasLinkIds.Contains(_client.AliasLinkId)) .ForEachAsync(_client => _client.AliasLinkId = newAliasLink.AliasLinkId); // we also need to update all the penalties or they get deleted // scenario // link1 joins with ip1 // link2 joins with ip2, // link2 receives penalty // link2 joins with ip1 // pre existing link for link2 detected // link2 is deleted // link2 penalties are orphaned await context.Penalties .Where(_penalty => completeAliasLinkIds.Contains(_penalty.LinkId)) .ForEachAsync(_penalty => _penalty.LinkId = newAliasLink.AliasLinkId); entity.AliasLink = newAliasLink; entity.AliasLinkId = newAliasLink.AliasLinkId; // update all previous aliases await context.Aliases .Where(_alias => completeAliasLinkIds.Contains(_alias.LinkId)) .ForEachAsync(_alias => _alias.LinkId = newAliasLink.AliasLinkId); await context.SaveChangesAsync(); // we want to delete the now inactive alias if (newAliasLink.AliasLinkId != entity.AliasLinkId) { context.AliasLinks.Remove(entity.AliasLink); await context.SaveChangesAsync(); } } // the existing alias matches ip and name, so we can just ignore the temporary one if (hasExactAliasMatch) { _logger.LogDebug("[updatealias] {entity} has exact alias match", entity.ToString()); var oldAlias = entity.CurrentAlias; entity.CurrentAliasId = existingExactAlias.AliasId; entity.CurrentAlias = existingExactAlias; await context.SaveChangesAsync(); // the alias is the same so we can just remove it if (oldAlias.AliasId != existingExactAlias.AliasId && oldAlias.AliasId > 0) { await context.Clients .Where(_client => _client.CurrentAliasId == oldAlias.AliasId) .ForEachAsync(_client => _client.CurrentAliasId = existingExactAlias.AliasId); await context.SaveChangesAsync(); if (context.Entry(oldAlias).State != EntityState.Deleted) { _logger.LogDebug( "[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {aliasId} with linkId {linkId}", entity.ToString(), oldAlias.AliasId, oldAlias.LinkId); context.Aliases.Remove(oldAlias); await context.SaveChangesAsync(); } } } // theres no exact match, but they've played before with the GUID or IP else { _logger.LogDebug("[updatealias] {entity} is using a new alias", entity.ToString()); var newAlias = new EFAlias() { DateAdded = DateTime.UtcNow, IPAddress = ip, LinkId = newAliasLink.AliasLinkId, Name = name, SearchableName = name.StripColors().ToLower(), Active = true, }; entity.CurrentAlias = newAlias; entity.CurrentAliasId = 0; await context.SaveChangesAsync(); } } }