diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index b27a07c7b8..b76ea61ac5 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Net; using Microsoft.EntityFrameworkCore; namespace Content.Server.Database @@ -27,6 +28,7 @@ namespace Content.Server.Database public DbSet Preference { get; set; } = null!; public DbSet Profile { get; set; } = null!; public DbSet AssignedUserId { get; set; } = null!; + public DbSet Player { get; set; } = default!; public DbSet Admin { get; set; } = null!; public DbSet AdminRank { get; set; } = null!; @@ -162,6 +164,22 @@ namespace Content.Server.Database public Guid UserId { get; set; } } + [Table("player")] + public class Player + { + public int Id { get; set; } + + // Permanent data + public Guid UserId { get; set; } + public DateTime FirstSeenTime { get; set; } + + // Data that gets updated on each join. + public string LastSeenUserName { get; set; } = null!; + public DateTime LastSeenTime { get; set; } + public IPAddress LastSeenAddress { get; set; } = null!; + public byte[]? LastSeenHWId { get; set; } + } + public class Admin { [Key] public Guid UserId { get; set; } diff --git a/Content.Server.Database/ModelPostgres.cs b/Content.Server.Database/ModelPostgres.cs index 7366e418a2..891e2e91d0 100644 --- a/Content.Server.Database/ModelPostgres.cs +++ b/Content.Server.Database/ModelPostgres.cs @@ -22,7 +22,6 @@ namespace Content.Server.Database public DbSet Ban { get; set; } = default!; public DbSet Unban { get; set; } = default!; - public DbSet Player { get; set; } = default!; public DbSet ConnectionLog { get; set; } = default!; @@ -70,16 +69,16 @@ namespace Content.Server.Database .HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address") .HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR user_id IS NOT NULL OR hwid IS NOT NULL"); - modelBuilder.Entity() + modelBuilder.Entity() .HasIndex(p => p.UserId) .IsUnique(); // ReSharper disable once StringLiteralTypo - modelBuilder.Entity() + modelBuilder.Entity() .HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address"); - modelBuilder.Entity() + modelBuilder.Entity() .HasIndex(p => p.LastSeenUserName); modelBuilder.Entity() @@ -131,25 +130,6 @@ namespace Content.Server.Database public DateTime UnbanTime { get; set; } } - [Table("player")] - public class PostgresPlayer - { - public int Id { get; set; } - - // Permanent data - public Guid UserId { get; set; } - - public DateTime FirstSeenTime { get; set; } - - // Data that gets updated on each join. - public string LastSeenUserName { get; set; } = null!; - - public DateTime LastSeenTime { get; set; } - - public IPAddress LastSeenAddress { get; set; } = null!; - public byte[]? LastSeenHWId { get; set; } - } - [Table("connection_log")] public class PostgresConnectionLog { diff --git a/Content.Server.Database/ModelSqlite.cs b/Content.Server.Database/ModelSqlite.cs index 1304666c72..0cf32508ae 100644 --- a/Content.Server.Database/ModelSqlite.cs +++ b/Content.Server.Database/ModelSqlite.cs @@ -13,7 +13,6 @@ namespace Content.Server.Database { public DbSet Ban { get; set; } = default!; public DbSet Unban { get; set; } = default!; - public DbSet Player { get; set; } = default!; public DbSet ConnectionLog { get; set; } = default!; public SqliteServerDbContext() @@ -37,10 +36,18 @@ namespace Content.Server.Database { base.OnModelCreating(modelBuilder); - modelBuilder.Entity() + modelBuilder.Entity() .HasIndex(p => p.LastSeenUserName); - var converter = new ValueConverter<(IPAddress address, int mask), string>( + var ipConverter = new ValueConverter( + v => v.ToString(), + v => IPAddress.Parse(v)); + + modelBuilder.Entity() + .Property(p => p.LastSeenAddress) + .HasConversion(ipConverter); + + var ipMaskConverter = new ValueConverter<(IPAddress address, int mask), string>( v => InetToString(v.address, v.mask), v => StringToInet(v) ); @@ -49,7 +56,7 @@ namespace Content.Server.Database .Entity() .Property(e => e.Address) .HasColumnType("TEXT") - .HasConversion(converter); + .HasConversion(ipMaskConverter); } public SqliteServerDbContext(DbContextOptions options) : base(options) @@ -105,22 +112,6 @@ namespace Content.Server.Database public DateTime UnbanTime { get; set; } } - [Table("player")] - public class SqlitePlayer - { - public int Id { get; set; } - - // Permanent data - public Guid UserId { get; set; } - public DateTime FirstSeenTime { get; set; } - - // Data that gets updated on each join. - public string LastSeenUserName { get; set; } = null!; - public DateTime LastSeenTime { get; set; } - public string LastSeenAddress { get; set; } = null!; - public byte[]? LastSeenHWId { get; set; } - } - [Table("connection_log")] public class SqliteConnectionLog { diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index 355e24608b..60205fde86 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -16,7 +16,6 @@ namespace Content.Server.Database { public abstract class ServerDbBase { - #region Preferences public async Task GetPlayerPreferencesAsync(NetUserId userId) { @@ -229,6 +228,7 @@ namespace Content.Server.Database } #endregion + #region User Ids public async Task GetAssignedUserIdAsync(string name) { await using var db = await GetDb(); @@ -249,8 +249,9 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(); } + #endregion - + #region Bans /* * BAN STUFF */ @@ -292,18 +293,66 @@ namespace Content.Server.Database public abstract Task AddServerBanAsync(ServerBanDef serverBan); public abstract Task AddServerUnbanAsync(ServerUnbanDef serverUnban); + #endregion + #region Player Records /* * PLAYER RECORDS */ - public abstract Task UpdatePlayerRecord( + public async Task UpdatePlayerRecord( NetUserId userId, string userName, IPAddress address, - ImmutableArray hwId); - public abstract Task GetPlayerRecordByUserName(string userName, CancellationToken cancel); - public abstract Task GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel); + ImmutableArray hwId) + { + await using var db = await GetDb(); + var record = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == userId.UserId); + if (record == null) + { + db.DbContext.Player.Add(record = new Player + { + FirstSeenTime = DateTime.UtcNow, + UserId = userId.UserId, + }); + } + + record.LastSeenTime = DateTime.UtcNow; + record.LastSeenAddress = address; + record.LastSeenUserName = userName; + record.LastSeenHWId = hwId.ToArray(); + + await db.DbContext.SaveChangesAsync(); + } + + public async Task GetPlayerRecordByUserName(string userName, CancellationToken cancel) + { + await using var db = await GetDb(); + + // Sort by descending last seen time. + // So if, due to account renames, we have two people with the same username in the DB, + // the most recent one is picked. + var record = await db.DbContext.Player + .OrderByDescending(p => p.LastSeenTime) + .FirstOrDefaultAsync(p => p.LastSeenUserName == userName, cancel); + + return record == null ? null : MakePlayerRecord(record); + } + + public async Task GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel) + { + await using var db = await GetDb(); + + var record = await db.DbContext.Player + .SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel); + + return record == null ? null : MakePlayerRecord(record); + } + + protected abstract PlayerRecord MakePlayerRecord(Player player); + #endregion + + #region Connection Logs /* * CONNECTION LOG */ @@ -312,9 +361,11 @@ namespace Content.Server.Database string userName, IPAddress address, ImmutableArray hwId); + #endregion + #region Admin Ranks /* - * ADMIN STUFF + * ADMIN RANKS */ public async Task GetAdminDataForAsync(NetUserId userId, CancellationToken cancel) { @@ -402,6 +453,7 @@ namespace Content.Server.Database await db.DbContext.SaveChangesAsync(cancel); } + #endregion protected abstract Task GetDb(); diff --git a/Content.Server/Database/ServerDbPostgres.cs b/Content.Server/Database/ServerDbPostgres.cs index 328cdb7796..39f041cb87 100644 --- a/Content.Server/Database/ServerDbPostgres.cs +++ b/Content.Server/Database/ServerDbPostgres.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Robust.Shared.Network; - namespace Content.Server.Database { public sealed class ServerDbPostgres : ServerDbBase @@ -222,63 +221,8 @@ namespace Content.Server.Database await db.PgDbContext.SaveChangesAsync(); } - public override async Task UpdatePlayerRecord( - NetUserId userId, - string userName, - IPAddress address, - ImmutableArray hwId) + protected override PlayerRecord MakePlayerRecord(Player record) { - await using var db = await GetDbImpl(); - - var record = await db.PgDbContext.Player.SingleOrDefaultAsync(p => p.UserId == userId.UserId); - if (record == null) - { - db.PgDbContext.Player.Add(record = new PostgresPlayer - { - FirstSeenTime = DateTime.UtcNow, - UserId = userId.UserId, - }); - } - - record.LastSeenTime = DateTime.UtcNow; - record.LastSeenAddress = address; - record.LastSeenUserName = userName; - record.LastSeenHWId = hwId.ToArray(); - - await db.PgDbContext.SaveChangesAsync(); - } - - public override async Task GetPlayerRecordByUserName(string userName, CancellationToken cancel) - { - await using var db = await GetDbImpl(); - - // Sort by descending last seen time. - // So if, due to account renames, we have two people with the same username in the DB, - // the most recent one is picked. - var record = await db.PgDbContext.Player - .OrderByDescending(p => p.LastSeenTime) - .FirstOrDefaultAsync(p => p.LastSeenUserName == userName, cancel); - - return MakePlayerRecord(record); - } - - public override async Task GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel) - { - await using var db = await GetDbImpl(); - - var record = await db.PgDbContext.Player - .SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel); - - return MakePlayerRecord(record); - } - - private static PlayerRecord? MakePlayerRecord(PostgresPlayer? record) - { - if (record == null) - { - return null; - } - return new PlayerRecord( new NetUserId(record.UserId), new DateTimeOffset(record.FirstSeenTime), diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index a82a9e0b39..08cb162f58 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -1,22 +1,18 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Globalization; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; using Content.Server.IP; -using Content.Server.Preferences; using Content.Server.Preferences.Managers; -using Content.Shared; using Content.Shared.CCVar; using Microsoft.EntityFrameworkCore; using Robust.Shared.Configuration; using Robust.Shared.IoC; using Robust.Shared.Network; - namespace Content.Server.Database { /// @@ -154,69 +150,14 @@ namespace Content.Server.Database await db.SqliteDbContext.SaveChangesAsync(); } - public override async Task UpdatePlayerRecord( - NetUserId userId, - string userName, - IPAddress address, - ImmutableArray hwId) + protected override PlayerRecord MakePlayerRecord(Player record) { - await using var db = await GetDbImpl(); - - var record = await db.SqliteDbContext.Player.SingleOrDefaultAsync(p => p.UserId == userId.UserId); - if (record == null) - { - db.SqliteDbContext.Player.Add(record = new SqlitePlayer - { - FirstSeenTime = DateTime.UtcNow, - UserId = userId.UserId, - }); - } - - record.LastSeenTime = DateTime.UtcNow; - record.LastSeenAddress = address.ToString(); - record.LastSeenUserName = userName; - record.LastSeenHWId = hwId.ToArray(); - - await db.SqliteDbContext.SaveChangesAsync(); - } - - public override async Task GetPlayerRecordByUserName(string userName, CancellationToken cancel) - { - await using var db = await GetDbImpl(); - - // Sort by descending last seen time. - // So if due to account renames we have two people with the same username in the DB, - // the most recent one is picked. - var record = await db.SqliteDbContext.Player - .OrderByDescending(p => p.LastSeenTime) - .FirstOrDefaultAsync(p => p.LastSeenUserName == userName, cancel); - - return MakePlayerRecord(record); - } - - public override async Task GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel) - { - await using var db = await GetDbImpl(); - - var record = await db.SqliteDbContext.Player - .SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel); - - return MakePlayerRecord(record); - } - - private static PlayerRecord? MakePlayerRecord(SqlitePlayer? record) - { - if (record == null) - { - return null; - } - return new PlayerRecord( new NetUserId(record.UserId), new DateTimeOffset(record.FirstSeenTime, TimeSpan.Zero), record.LastSeenUserName, new DateTimeOffset(record.LastSeenTime, TimeSpan.Zero), - IPAddress.Parse(record.LastSeenAddress), + record.LastSeenAddress, record.LastSeenHWId?.ToImmutableArray()); }