Exemplo n.º 1
0
        private async Task <EFClient> HandleNewCreate(EFClient entity)
        {
            await using var context = _contextFactory.CreateContext(true);
            using (LogContext.PushProperty("Server", entity.CurrentServer?.ToString()))
            {
                var existingAlias = await context.Aliases
                                    .Select(alias => new { alias.AliasId, alias.LinkId, alias.IPAddress, alias.Name })
                                    .Where(alias => alias.IPAddress != null && alias.IPAddress == entity.IPAddress &&
                                           alias.Name == entity.Name)
                                    .FirstOrDefaultAsync();

                var client = new EFClient
                {
                    Level           = Permission.User,
                    FirstConnection = DateTime.UtcNow,
                    LastConnection  = DateTime.UtcNow,
                    NetworkId       = entity.NetworkId
                };

                if (existingAlias == null)
                {
                    _logger.LogDebug("[{Method}] creating new Link and Alias for {Entity}", nameof(HandleNewCreate), entity.ToString());
                    var link  = new EFAliasLink();
                    var alias = new EFAlias
                    {
                        Name           = entity.Name,
                        SearchableName = entity.Name.StripColors().ToLower(),
                        DateAdded      = DateTime.UtcNow,
                        IPAddress      = entity.IPAddress,
                        Link           = link
                    };
                    client.CurrentAlias = alias;
                    client.AliasLink    = link;
                }

                else
                {
                    _logger.LogDebug("[{Method}] associating new GUID {Guid} with new exact alias match with linkId {LinkId} for {Entity}",
                                     nameof(HandleNewCreate), entity.GuidString, existingAlias.LinkId, entity.ToString());

                    var alias = new EFAlias
                    {
                        Name           = existingAlias.Name,
                        SearchableName = entity.Name.StripColors().ToLower(),
                        DateAdded      = DateTime.UtcNow,
                        IPAddress      = entity.IPAddress,
                        LinkId         = existingAlias.LinkId
                    };
                    client.CurrentAlias = alias;
                    client.AliasLinkId  = existingAlias.LinkId;
                }

                context.Clients.Add(client);
                await context.SaveChangesAsync();

                return(client);
            }
        }
Exemplo n.º 2
0
        public static void ImportClients(IList <Player> clients)
        {
            DatabaseContext context = null;

            try
            {
                context = new DatabaseContext();
                context.Configuration.AutoDetectChangesEnabled = false;
                context.Configuration.LazyLoadingEnabled       = false;
                context.Configuration.ProxyCreationEnabled     = false;

                int count = 0;
                foreach (var entityToInsert in clients)
                {
                    ++count;

                    var link = new EFAliasLink()
                    {
                        Active = true
                    };

                    var alias = new EFAlias()
                    {
                        Active    = true,
                        DateAdded = entityToInsert.LastConnection,
                        IPAddress = entityToInsert.IPAddress,
                        Link      = link,
                        Name      = entityToInsert.Name,
                    };

                    var client = new EFClient()
                    {
                        Active              = true,
                        AliasLink           = link,
                        Connections         = entityToInsert.Connections,
                        CurrentAlias        = alias,
                        FirstConnection     = entityToInsert.LastConnection,
                        Level               = entityToInsert.Level,
                        LastConnection      = entityToInsert.LastConnection,
                        TotalConnectionTime = entityToInsert.TotalConnectionTime,
                        Masked              = entityToInsert.Masked,
                        NetworkId           = entityToInsert.NetworkId
                    };

                    context = AddClient(context, client, count, 1000, true);
                }

                context.SaveChanges();
            }
            finally
            {
                if (context != null)
                {
                    context.Dispose();
                }
            }
        }
Exemplo n.º 3
0
        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;
        }
Exemplo n.º 4
0
        public async Task Seed()
        {
            // make sure database exists
            //context.Database.EnsureCreated();
            context.Database.Migrate();

            if (context.AliasLinks.Count() == 0)
            {
                context.AliasLinks.Add(new EFAliasLink()
                {
                    AliasLinkId = 1
                });

                var currentAlias = new EFAlias()
                {
                    AliasId   = 1,
                    Active    = true,
                    DateAdded = DateTime.UtcNow,
                    IPAddress = 0,
                    Name      = "IW4MAdmin",
                    LinkId    = 1
                };

                context.Aliases.Add(currentAlias);

                context.Clients.Add(new EFClient()
                {
                    ClientId        = 1,
                    Active          = false,
                    Connections     = 0,
                    FirstConnection = DateTime.UtcNow,
                    LastConnection  = DateTime.UtcNow,
                    Level           = Objects.Player.Permission.Console,
                    Masked          = true,
                    NetworkId       = 0,
                    AliasLinkId     = 1,
                    CurrentAliasId  = 1,
                });

                await context.SaveChangesAsync();
            }
        }
Exemplo n.º 5
0
        private async Task UpdateAlias(string name, int?ip, EFClient entity, DatabaseContext context)
        {
            // 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));

#if DEBUG == true
            var aliasSql = iqAliases.ToSql();
#endif
            var aliases = await iqAliases.ToListAsync();

            // update each of the aliases where this is no IP but the name is identical
            foreach (var alias in aliases.Where(_alias => (_alias.IPAddress == null || _alias.IPAddress == 0)))
            {
                alias.IPAddress = ip;
            }

            await context.SaveChangesAsync();

            // see if they have a matching IP + Name but new NetworkId
            var  existingExactAlias = aliases.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.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;

            // this happens when the link we found is different than the one we create before adding an IP
            if (isAliasLinkUpdated)
            {
                entity.CurrentServer.Logger.WriteDebug($"[updatealias] found a link for {entity} so we are updating link from {entity.AliasLink.AliasLinkId} to {newAliasLink.AliasLinkId}");

                var oldAliasLink = entity.AliasLink;

                // update all the clients that have the old alias link
                await context.Clients
                .Where(_client => _client.AliasLinkId == oldAliasLink.AliasLinkId)
                .ForEachAsync(_client => _client.AliasLinkId = newAliasLink.AliasLinkId);

                entity.AliasLink   = newAliasLink;
                entity.AliasLinkId = newAliasLink.AliasLinkId;

                // update all previous aliases
                await context.Aliases
                .Where(_alias => _alias.LinkId == oldAliasLink.AliasLinkId)
                .ForEachAsync(_alias => _alias.LinkId = newAliasLink.AliasLinkId);

                await context.SaveChangesAsync();

                // we want to delete the now inactive alias
                context.AliasLinks.Remove(oldAliasLink);
                await context.SaveChangesAsync();
            }

            // the existing alias matches ip and name, so we can just ignore the temporary one
            if (hasExactAliasMatch)
            {
                entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match");

                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();

                    entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {oldAlias.AliasId} with linkId {oldAlias.AliasId}");
                    context.Aliases.Remove(oldAlias);
                    await context.SaveChangesAsync();
                }
            }

            // theres no exact match, but they've played before with the GUID or IP
            else
            {
                entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} is using a new alias");

                var newAlias = new EFAlias()
                {
                    DateAdded = DateTime.UtcNow,
                    IPAddress = ip,
                    LinkId    = newAliasLink.AliasLinkId,
                    Name      = name,
                    Active    = true,
                };

                entity.CurrentAlias   = newAlias;
                entity.CurrentAliasId = 0;
                await context.SaveChangesAsync();
            }
        }
Exemplo n.º 6
0
        public async Task <EFClient> Create(EFClient entity)
        {
            using (var context = new DatabaseContext())
            {
                int?linkId  = null;
                int?aliasId = null;

                if (entity.IPAddress != null)
                {
                    var existingAlias = await context.Aliases
                                        .Select(_alias => new { _alias.AliasId, _alias.LinkId, _alias.IPAddress, _alias.Name })
                                        .FirstOrDefaultAsync(_alias => _alias.IPAddress == entity.IPAddress);

                    if (existingAlias != null)
                    {
                        entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing link {existingAlias.LinkId}");

                        linkId = existingAlias.LinkId;
                        if (existingAlias.Name == entity.Name)
                        {
                            entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing alias {existingAlias.AliasId}");
                            aliasId = existingAlias.AliasId;
                        }
                    }
                }

                var client = new EFClient()
                {
                    Level           = Permission.User,
                    FirstConnection = DateTime.UtcNow,
                    LastConnection  = DateTime.UtcNow,
                    NetworkId       = entity.NetworkId
                };

                context.Clients.Add(client);

                // they're just using a new GUID
                if (aliasId.HasValue)
                {
                    entity.CurrentServer.Logger.WriteDebug($"[create] setting {entity}'s alias id and linkid to ({aliasId.Value}, {linkId.Value})");
                    client.CurrentAliasId = aliasId.Value;
                    client.AliasLinkId    = linkId.Value;
                }

                // link was found but they don't have an exact alias
                else if (!aliasId.HasValue && linkId.HasValue)
                {
                    entity.CurrentServer.Logger.WriteDebug($"[create] setting {entity}'s linkid to {linkId.Value}, but creating new alias");
                    client.AliasLinkId  = linkId.Value;
                    client.CurrentAlias = new EFAlias()
                    {
                        Name      = entity.Name,
                        DateAdded = DateTime.UtcNow,
                        IPAddress = entity.IPAddress,
                        LinkId    = linkId.Value
                    };
                }

                // brand new players (supposedly)
                else
                {
                    entity.CurrentServer.Logger.WriteDebug($"[create] creating new Link and Alias for {entity}");
                    var link  = new EFAliasLink();
                    var alias = new EFAlias()
                    {
                        Name      = entity.Name,
                        DateAdded = DateTime.UtcNow,
                        IPAddress = entity.IPAddress,
                        Link      = link
                    };

                    link.Children.Add(alias);

                    client.AliasLink    = link;
                    client.CurrentAlias = alias;
                }

                await context.SaveChangesAsync();

                return(client);
            }
        }
Exemplo n.º 7
0
        public async Task OnLoadAsync(IManager manager)
        {
            //  #if DO_IMPORT
            var svc = new GenericRepository <EFServer>();

            svc.Insert(new EFServer()
            {
                Active   = true,
                Port     = 28960,
                ServerId = Math.Abs("127.0.0.1:28960".GetHashCode()),
            });

            svc.Insert(new EFServer()
            {
                Active   = true,
                Port     = 28965,
                ServerId = Math.Abs("127.0.0.1:28965".GetHashCode()),
            });

            svc.Insert(new EFServer()
            {
                Active   = true,
                Port     = 28970,
                ServerId = Math.Abs("127.0.0.1:28970".GetHashCode()),
            });

            svc.SaveChanges();
            //       #endif
            Interval = DateTime.Now;
            var clients    = new List <Player>();
            var oldClients = new Dictionary <int, Player>();

            #region CLIENTS
            if (File.Exists("import_clients.csv"))
            {
                manager.GetLogger().WriteVerbose("Beginning import of existing clients");

                var lines = File.ReadAllLines("import_clients.csv").Skip(1);
                foreach (string line in lines)
                {
                    string[] fields = Regex.Replace(line, "\".*\"", "").Split(',');
                    fields.All(f =>
                    {
                        f = f.StripColors().Trim();
                        return(true);
                    });

                    if (fields.Length != 11)
                    {
                        manager.GetLogger().WriteError("Invalid client import file... aborting import");
                        return;
                    }

                    if (fields[1].Substring(0, 5) == "01100" || fields[0] == string.Empty || fields[1] == string.Empty || fields[6] == string.Empty)
                    {
                        continue;
                    }

                    if (!Regex.Match(fields[6], @"^\d+\.\d+\.\d+.\d+$").Success)
                    {
                        fields[6] = "0";
                    }

                    var client = new Player()
                    {
                        Name           = fields[0],
                        NetworkId      = fields[1].ConvertLong(),
                        IPAddress      = fields[6].ConvertToIP(),
                        Level          = (Player.Permission)Convert.ToInt32(fields[3]),
                        Connections    = Convert.ToInt32(fields[5]),
                        LastConnection = DateTime.Parse(fields[7]),
                    };

                    clients.Add(client);
                    oldClients.Add(Convert.ToInt32(fields[2]), client);
                }
                clients = clients.Distinct().ToList();
                //   #if DO_IMPORT

                /*clients = clients
                 *  .GroupBy(c => new { c.Name, c.IPAddress })
                 *                  .Select(c => c.FirstOrDefault())
                 *                  .ToList();*/

                //newClients = clients.ToList();
                //newClients.ForEach(c => c.ClientId = 0);

                manager.GetLogger().WriteVerbose($"Read {clients.Count} clients for import");

                try
                {
                    SharedLibrary.Database.Importer.ImportClients(clients);
                }

                catch (Exception e)
                {
                    manager.GetLogger().WriteError("Saving imported clients failed");
                }
                //  #endif
            }
            #endregion
            // load the entire database lol
            var ctx = new DatabaseContext();
            ctx.Configuration.ProxyCreationEnabled = false;
            var cls = ctx.Clients.Include("AliasLink.Children").ToList(); //manager.GetClientService().Find(c => c.Active).Result;
            ctx.Dispose();

            #region ALIASES
            if (File.Exists("import_aliases.csv"))
            {
                manager.GetLogger().WriteVerbose("Beginning import of existing aliases");

                var aliases = new List <EFAlias>();

                var lines = File.ReadAllLines("import_aliases.csv").Skip(1);
                foreach (string line in lines)
                {
                    string[] fields = Regex.Replace(line, "\".*\"", "").Split(',');
                    fields.All(f =>
                    {
                        f = f.StripColors().Trim();
                        return(true);
                    });

                    if (fields.Length != 3)
                    {
                        manager.GetLogger().WriteError("Invalid alias import file... aborting import");
                        return;
                    }
                    try
                    {
                        int number = Int32.Parse(fields[0]);
                        var names  = fields[1].Split(';').Where(n => n != String.Empty && n.Length > 2);

                        var oldClient = oldClients[number];
                        var newClient = cls.FirstOrDefault(c => c.NetworkId == oldClient.NetworkId);

                        foreach (string name in names)
                        {
                            // this is slow :D
                            if (newClient.AliasLink.Children.FirstOrDefault(n => n.Name == name) != null)
                            {
                                continue;
                            }
                            var alias = new EFAlias()
                            {
                                Active    = true,
                                DateAdded = DateTime.UtcNow,
                                Name      = name,
                                LinkId    = newClient.AliasLinkId,
                                IPAddress = newClient.IPAddress
                            };

                            aliases.Add(alias);
                        }
                    }
                    catch (KeyNotFoundException)
                    {
                        continue;
                    }

                    catch (Exception)
                    {
                        manager.GetLogger().WriteVerbose($"Could not import alias with line {line}");
                    }
                }

                SharedLibrary.Database.Importer.ImportSQLite(aliases);
            }
            #endregion
            #region PENALTIES
            if (File.Exists("import_penalties.csv"))
            {
                var penalties = new List <Penalty>();
                manager.GetLogger().WriteVerbose("Beginning import of existing penalties");
                foreach (string line in File.ReadAllLines("import_penalties.csv").Skip(1))
                {
                    string   comma  = Regex.Match(line, "\".*,.*\"").Value.Replace(",", "");
                    string[] fields = Regex.Replace(line, "\".*,.*\"", comma).Split(',');

                    fields.All(f =>
                    {
                        f = f.StripColors().Trim();
                        return(true);
                    });

                    if (fields.Length != 7)
                    {
                        manager.GetLogger().WriteError("Invalid penalty import file... aborting import");
                        return;
                    }

                    if (fields[2].Substring(0, 5) == "01100" || fields[2].Contains("0000000"))
                    {
                        continue;
                    }
                    try
                    {
                        var expires = DateTime.Parse(fields[6]);
                        var when    = DateTime.Parse(fields[5]);

                        var penaltyType = (Penalty.PenaltyType)Int32.Parse(fields[0]);
                        if (penaltyType == Penalty.PenaltyType.Ban)
                        {
                            expires = DateTime.MaxValue;
                        }

                        var penalty = new Penalty()
                        {
                            Type     = penaltyType,
                            Expires  = expires == DateTime.MinValue ? when : expires,
                            Punisher = new SharedLibrary.Database.Models.EFClient()
                            {
                                NetworkId = fields[3].ConvertLong()
                            },
                            Offender = new SharedLibrary.Database.Models.EFClient()
                            {
                                NetworkId = fields[2].ConvertLong()
                            },
                            Offense = fields[1].Replace("\"", "").Trim(),
                            Active  = true,
                            When    = when,
                        };


                        penalties.Add(penalty);
                    }

                    catch (Exception e)
                    {
                        manager.GetLogger().WriteVerbose($"Could not import penalty with line {line}");
                    }
                }
                //#if DO_IMPORT
                SharedLibrary.Database.Importer.ImportPenalties(penalties);
                manager.GetLogger().WriteVerbose($"Imported {penalties.Count} penalties");
                //#endif
            }
            #endregion
            #region CHATHISTORY

            if (File.Exists("import_chathistory.csv"))
            {
                var chatHistory = new List <EFClientMessage>();
                manager.GetLogger().WriteVerbose("Beginning import of existing messages");
                foreach (string line in File.ReadAllLines("import_chathistory.csv").Skip(1))
                {
                    string   comma  = Regex.Match(line, "\".*,.*\"").Value.Replace(",", "");
                    string[] fields = Regex.Replace(line, "\".*,.*\"", comma).Split(',');

                    fields.All(f =>
                    {
                        f = f.StripColors().Trim();
                        return(true);
                    });

                    if (fields.Length != 4)
                    {
                        manager.GetLogger().WriteError("Invalid chat history import file... aborting import");
                        return;
                    }
                    try
                    {
                        int cId          = Convert.ToInt32(fields[0]);
                        var linkedClient = oldClients[cId];

                        var newcl = cls.FirstOrDefault(c => c.NetworkId == linkedClient.NetworkId);
                        if (newcl == null)
                        {
                            newcl = cls.FirstOrDefault(c => c.Name == linkedClient.Name && c.IPAddress == linkedClient.IPAddress);
                        }
                        int newCId = newcl.ClientId;

                        var chatMessage = new EFClientMessage()
                        {
                            Active   = true,
                            ClientId = newCId,
                            Message  = fields[1],
                            TimeSent = DateTime.Parse(fields[3]),
                            ServerId = Math.Abs($"127.0.0.1:{Convert.ToInt32(fields[2]).ToString()}".GetHashCode())
                        };

                        chatHistory.Add(chatMessage);
                    }

                    catch (Exception e)
                    {
                        manager.GetLogger().WriteVerbose($"Could not import chatmessage with line {line}");
                    }
                }
                manager.GetLogger().WriteVerbose($"Read {chatHistory.Count} messages for import");
                SharedLibrary.Database.Importer.ImportSQLite(chatHistory);
            }
            #endregion
            #region STATS
            foreach (string file in Directory.GetFiles(Environment.CurrentDirectory))
            {
                if (Regex.Match(file, @"import_stats_[0-9]+.csv").Success)
                {
                    int port  = Int32.Parse(Regex.Match(file, "[0-9]{5}").Value);
                    var stats = new List <EFClientStatistics>();
                    manager.GetLogger().WriteVerbose("Beginning import of existing client stats");

                    var lines = File.ReadAllLines(file).Skip(1);
                    foreach (string line in lines)
                    {
                        string[] fields = line.Split(',');

                        if (fields.Length != 9)
                        {
                            manager.GetLogger().WriteError("Invalid client import file... aborting import");
                            return;
                        }

                        try
                        {
                            if (fields[0].Substring(0, 5) == "01100")
                            {
                                continue;
                            }

                            long id     = fields[0].ConvertLong();
                            var  client = cls.Single(c => c.NetworkId == id);

                            var    time = Convert.ToInt32(fields[8]);
                            double spm  = time < 60 ? 0 : Math.Round(Convert.ToInt32(fields[1]) * 100.0 / time, 3);
                            if (spm > 1000)
                            {
                                spm = 0;
                            }

                            var st = new EFClientStatistics()
                            {
                                Active     = true,
                                ClientId   = client.ClientId,
                                ServerId   = Math.Abs($"127.0.0.1:{port}".GetHashCode()),
                                Kills      = Convert.ToInt32(fields[1]),
                                Deaths     = Convert.ToInt32(fields[2]),
                                SPM        = spm,
                                Skill      = 0,
                                TimePlayed = time * 60
                            };
                            // client.TotalConnectionTime += time;
                            stats.Add(st);
                            stats = stats.AsEnumerable()
                                    .GroupBy(c => new { c.ClientId })
                                    .Select(c => c.FirstOrDefault()).ToList();

                            var cl = await manager.GetClientService().Get(st.ClientId);

                            cl.TotalConnectionTime += time * 60;
                            await manager.GetClientService().Update(cl);
                        }
                        catch (Exception e)
                        {
                            continue;
                        }
                    }


                    manager.GetLogger().WriteVerbose($"Read {stats.Count} clients stats for import");

                    try
                    {
                        SharedLibrary.Database.Importer.ImportSQLite(stats);
                    }

                    catch (Exception e)
                    {
                        manager.GetLogger().WriteError("Saving imported stats failed");
                    }
                }
            }
            #endregion
        }
Exemplo n.º 8
0
        public async Task <EFClient> Create(EFClient entity)
        {
            entity.Name = entity.Name.CapClientName(EFAlias.MAX_NAME_LENGTH);

            if (!_appConfig.EnableImplicitAccountLinking)
            {
                return(await HandleNewCreate(entity));
            }

            await using var context = _contextFactory.CreateContext(true);
            using (LogContext.PushProperty("Server", entity?.CurrentServer?.ToString()))
            {
                int?linkId  = null;
                int?aliasId = null;

                if (entity.IPAddress != null)
                {
                    var existingAliases = await context.Aliases
                                          .Select(_alias => new { _alias.AliasId, _alias.LinkId, _alias.IPAddress, _alias.Name })
                                          .Where(_alias => _alias.IPAddress == entity.IPAddress)
                                          .ToListAsync();

                    if (existingAliases.Count > 0)
                    {
                        linkId = existingAliases.OrderBy(_alias => _alias.LinkId).First().LinkId;

                        _logger.LogDebug("[create] client with new GUID {entity} has existing link {linkId}", entity.ToString(), linkId);

                        var existingExactAlias = existingAliases.FirstOrDefault(_alias => _alias.Name == entity.Name);

                        if (existingExactAlias != null)
                        {
                            _logger.LogDebug("[create] client with new GUID {entity} has existing alias {aliasId}", entity.ToString(), existingExactAlias.AliasId);
                            aliasId = existingExactAlias.AliasId;
                        }
                    }
                }

                var client = new EFClient()
                {
                    Level           = Permission.User,
                    FirstConnection = DateTime.UtcNow,
                    LastConnection  = DateTime.UtcNow,
                    NetworkId       = entity.NetworkId
                };

                _logger.LogDebug("[create] adding {entity} to context", entity.ToString());


                // they're just using a new GUID
                if (aliasId.HasValue)
                {
                    _logger.LogDebug("[create] setting {entity}'s alias id and linkid to ({aliasId}, {linkId})", entity.ToString(), aliasId, linkId);
                    client.CurrentAliasId = aliasId.Value;
                    client.AliasLinkId    = linkId.Value;
                }

                // link was found but they don't have an exact alias
                else if (!aliasId.HasValue && linkId.HasValue)
                {
                    _logger.LogDebug("[create] setting {entity}'s linkid to {linkId}, but creating new alias", entity.ToString(), linkId);
                    client.AliasLinkId  = linkId.Value;
                    client.CurrentAlias = new EFAlias()
                    {
                        Name           = entity.Name,
                        SearchableName = entity.Name.StripColors().ToLower(),
                        DateAdded      = DateTime.UtcNow,
                        IPAddress      = entity.IPAddress,
                        LinkId         = linkId.Value
                    };
                }

                // brand new players (supposedly)
                else
                {
                    _logger.LogDebug("[create] creating new Link and Alias for {entity}", entity.ToString());
                    var link  = new EFAliasLink();
                    var alias = new EFAlias()
                    {
                        Name           = entity.Name,
                        SearchableName = entity.Name.StripColors().ToLower(),
                        DateAdded      = DateTime.UtcNow,
                        IPAddress      = entity.IPAddress,
                        Link           = link
                    };

                    client.AliasLink    = link;
                    client.CurrentAlias = alias;
                }

                context.Clients.Add(client);
                await context.SaveChangesAsync();

                return(client);
            }
        }
Exemplo n.º 9
0
        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();
                }
            }
        }