Current work Fluent NHibernate

fluent_nhibernate
Tiger 2023-09-23 14:20:45 +02:00
parent 6c4de34920
commit 4b2a01fe58
20 changed files with 167 additions and 175 deletions

View File

@ -5,20 +5,21 @@ using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Game.Settings;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.Handshake;
public class SsoTicketEvent : IMessageEvent
{
private readonly IHabboDao _habboDao;
private readonly IRepository<Habbo> _habboRepository;
private readonly IGameSessionManager _gameSessionManager;
private readonly ISettingsManager _settingsManager;
private readonly ISettingManager _settingManager;
public SsoTicketEvent(IHabboDao habboDao, IGameSessionManager gameSessionManager, ISettingsManager settingsManager)
public SsoTicketEvent(IRepository<Habbo> habboRepository, IGameSessionManager gameSessionManager, ISettingManager settingManager)
{
_habboDao = habboDao;
_habboRepository = habboRepository;
_gameSessionManager = gameSessionManager;
_settingsManager = settingsManager;
_settingManager = settingManager;
}
public IncomingHeaders Header => IncomingHeaders.SSoTicketEvent;
@ -33,7 +34,7 @@ public class SsoTicketEvent : IMessageEvent
return;
}
var habbo = await _habboDao.GetHabboBySsoAsync(sso);
var habbo = await _habboRepository.FindOneByAsync(h => h.SsoTicket == sso);
if (habbo == null)
{
@ -45,7 +46,7 @@ public class SsoTicketEvent : IMessageEvent
await gameSession.SendComposerAsync(new AuthenticationOkMessageComposer());
await gameSession.SendComposerAsync(new HabboBroadcastMessageComposer(
_settingsManager.GetSetting<string>("welcome.message")
_settingManager.GetSetting<string>("welcome.message")
.Replace("{user}", gameSession.Habbo.Username)
));
}

View File

@ -28,7 +28,7 @@ public class UserObjectMessageComposer : IMessageComposer
message.AppendInt32(0); // respect points to give
message.AppendInt32(0); // scratch to give
message.AppendBoolean(false);
message.AppendString(_habbo.LastLogin.ToString(CultureInfo.CurrentCulture));
message.AppendString(_habbo.LastLogin?.ToString(CultureInfo.CurrentCulture) ?? string.Empty);
message.AppendBoolean(false); // can change name
message.AppendBoolean(false); // safety locked
}

View File

@ -1,39 +1,21 @@
using MySqlConnector;
namespace Tiger.Game.Habbos;
public class Habbo
{
public uint Id { get; }
public string Username { get; }
public string Email { get; }
public DateTime AccountCreated { get; }
public DateTime LastLogin { get; }
public string Motto { get; set; }
public string Figure { get; set; }
public string Gender { get; set; }
public byte Rank { get; set; }
public uint Credits { get; set; }
public bool Online { get; set; }
public uint HomeRoom { get; set; }
public uint AchievementScore { get; set; }
public uint GroupId { get; set; }
public Habbo(MySqlDataReader reader)
{
Id = reader.GetUInt32("id");
Username = reader.GetString("username");
Email = reader.GetString("email");
AccountCreated = reader.GetDateTime("account_created");
LastLogin = reader.GetDateTime("last_login");
Motto = reader.GetString("motto");
Figure = reader.GetString("figure");
Gender = reader.GetString("gender");
Rank = reader.GetByte("rank");
Credits = reader.GetUInt32("credits");
Online = reader.GetBoolean("online");
HomeRoom = reader.GetUInt32("home_room");
AchievementScore = reader.GetUInt32("achievement_score");
GroupId = reader.GetUInt32("group_id");
}
public virtual uint Id { get; set; }
public virtual string Username { get; set; } = null!;
public virtual string Password { get; set; } = null!;
public virtual string Email { get; set; } = null!;
public virtual DateTime AccountCreated { get; set; }
public virtual DateTime? LastLogin { get; set; }
public virtual string Motto { get; set; } = null!;
public virtual string Figure { get; set; } = null!;
public virtual string Gender { get; set; } = null!;
public virtual byte Rank { get; set; }
public virtual uint Credits { get; set; }
public virtual bool Online { get; set; }
public virtual uint HomeRoom { get; set; }
public virtual uint AchievementScore { get; set; }
public virtual uint? GroupId { get; set; }
public virtual string? SsoTicket { get; set; }
}

View File

@ -1,26 +0,0 @@
using Tiger.Storage;
namespace Tiger.Game.Habbos;
public class HabboDao : IHabboDao
{
private readonly IDatabaseHelper _databaseHelper;
public HabboDao(IDatabaseHelper databaseHelper)
{
_databaseHelper = databaseHelper;
}
public async Task<Habbo?> GetHabboBySsoAsync(string sso)
{
await using var dbConnection = _databaseHelper.GetConnection();
var resultSet =
await dbConnection.GetResultSet("SELECT * FROM habbos WHERE sso_ticket = @sso LIMIT 1", ("@sso", sso));
if (await resultSet.ReadAsync())
{
return new Habbo(resultSet);
}
return null;
}
}

28
Game/Habbos/HabboMap.cs Normal file
View File

@ -0,0 +1,28 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Habbos;
public class HabboMap : ClassMap<Habbo>
{
public HabboMap()
{
Table("habbos");
LazyLoad();
Id(h => h.Id).Column("id").GeneratedBy.Identity();
Map(h => h.Username).Column("username").Not.Nullable();
Map(h => h.Password).Column("password").Not.Nullable();
Map(h => h.Email).Column("email").Not.Nullable();
Map(h => h.AccountCreated).Column("account_created").Not.Nullable();
Map(h => h.LastLogin).Column("last_login").Nullable();
Map(h => h.Motto).Column("motto").Not.Nullable();
Map(h => h.Figure).Column("figure").Not.Nullable();
Map(h => h.Gender).Column("gender").Not.Nullable();
Map(h => h.Rank).Column("rank").Not.Nullable();
Map(h => h.Credits).Column("credits").Not.Nullable();
Map(h => h.Online).Column("online").Not.Nullable();
Map(h => h.HomeRoom).Column("home_room").Not.Nullable();
Map(h => h.AchievementScore).Column("achievement_score").Not.Nullable();
Map(h => h.GroupId).Column("group_id").Nullable();
Map(h => h.SsoTicket).Column("sso_ticket").Nullable();
}
}

View File

@ -1,6 +0,0 @@
namespace Tiger.Game.Habbos;
public interface IHabboDao
{
Task<Habbo?> GetHabboBySsoAsync(string sso);
}

View File

@ -1,6 +1,6 @@
namespace Tiger.Game.Settings;
public interface ISettingsManager
public interface ISettingManager
{
Task ReloadSettingsAsync();
T GetSetting<T>(string key);

View File

@ -1,6 +0,0 @@
namespace Tiger.Game.Settings;
public interface ISettingsDao
{
Task<IReadOnlyDictionary<string, object>> GetSettingsAsync();
}

7
Game/Settings/Setting.cs Normal file
View File

@ -0,0 +1,7 @@
namespace Tiger.Game.Settings;
public class Setting
{
public virtual string Key { get; set; } = string.Empty;
public virtual string Value { get; set; } = string.Empty;
}

View File

@ -1,23 +1,24 @@
using Microsoft.Extensions.Logging;
using Tiger.Storage;
namespace Tiger.Game.Settings;
public class SettingsManager : ISettingsManager
public class SettingManager : ISettingManager
{
private IReadOnlyDictionary<string, object> _settings;
private readonly ISettingsDao _settingsDao;
private readonly ILogger<ISettingsManager> _logger;
private IReadOnlyDictionary<string, string> _settings;
private readonly IRepository<Setting> _settingRepository;
private readonly ILogger<ISettingManager> _logger;
public SettingsManager(ISettingsDao settingsDao, ILogger<ISettingsManager> logger)
public SettingManager(IRepository<Setting> settingRepository, ILogger<ISettingManager> logger)
{
_settingsDao = settingsDao;
_settingRepository = settingRepository;
_logger = logger;
_settings = new Dictionary<string, object>();
_settings = new Dictionary<string, string>();
}
public async Task ReloadSettingsAsync()
{
_settings = await _settingsDao.GetSettingsAsync();
_settings = (await _settingRepository.FindByAsync()).ToDictionary(s => s.Key, s => s.Value);
_logger.LogInformation("Loaded {Count} settings", _settings.Count);
}

View File

@ -0,0 +1,13 @@
// using FluentNHibernate.Mapping;
//
// namespace Tiger.Game.Settings;
//
// public class SettingMap : ClassMap<Setting>
// {
// public SettingMap()
// {
// Table("settings");
// Id(s => s.Key).Column("skey").Not.Nullable();
// Map(s => s.Value).Column("value").Not.Nullable();
// }
// }

View File

@ -1,27 +0,0 @@
using System.Collections.ObjectModel;
using Tiger.Storage;
namespace Tiger.Game.Settings;
public class SettingsDao : ISettingsDao
{
private readonly IDatabaseHelper _databaseHelper;
public SettingsDao(IDatabaseHelper databaseHelper)
{
_databaseHelper = databaseHelper;
}
public async Task<IReadOnlyDictionary<string, object>> GetSettingsAsync()
{
var settings = new Dictionary<string, object>();
await using var dbConnection = _databaseHelper.GetConnection();
await using var resultSet = await dbConnection.GetResultSet("SELECT * FROM settings");
while (await resultSet.ReadAsync())
{
settings.Add(resultSet.GetString("skey"), resultSet.GetValue(resultSet.GetOrdinal("value")));
}
return new ReadOnlyDictionary<string, object>(settings);
}
}

View File

@ -29,15 +29,15 @@ collection.AddSingleton<IConfiguration>(configuration);
collection.AddSingleton<IWebSocketServer, WebSocketServer>();
collection.AddSingleton<IGameSessionManager, GameSessionManager>();
collection.AddSingleton<IMessageHandler, MessageHandler>();
collection.AddSingleton<IDatabaseHelper, DatabaseHelper>();
collection.AddSingleton<ISettingsDao, SettingsDao>();
collection.AddSingleton<ISettingsManager, SettingsManager>();
collection.AddSingleton<IHabboDao, HabboDao>();
collection.AddSingleton<INhSessionFactory, NhSessionFactory>();
collection.AddScoped(serviceProvider => serviceProvider.GetRequiredService<INhSessionFactory>().OpenSession());
collection.AddScoped(typeof(IRepository<>), typeof(Repository<>));
collection.AddSingleton<ISettingManager, SettingManager>();
collection.RegisterMessageEvents();
var provider = collection.BuildServiceProvider();
await provider.GetRequiredService<ISettingsManager>().ReloadSettingsAsync();
await provider.GetRequiredService<ISettingManager>().ReloadSettingsAsync();
provider.GetRequiredService<IWebSocketServer>().Start($"http://{configuration["Network:Game:Ip"]}:{configuration["Network:Game:Port"]}/");

View File

@ -1,38 +0,0 @@
using MySqlConnector;
namespace Tiger.Storage;
public class DatabaseConnection : IAsyncDisposable
{
private readonly MySqlConnection _connection;
private readonly MySqlCommand _command;
public DatabaseConnection(MySqlConnection connection)
{
_connection = connection;
_command = connection.CreateCommand();
}
public async Task<MySqlDataReader> GetResultSet(string query, params (string, object)[] mysqlParams)
{
await _connection.OpenAsync();
_command.CommandText = query;
foreach (var mysqlParam in mysqlParams)
{
_command.Parameters.AddWithValue(mysqlParam.Item1, mysqlParam.Item2);
}
var reader = await _command.ExecuteReaderAsync();
_command.Parameters.Clear();
return reader;
}
public async ValueTask DisposeAsync()
{
await _connection.DisposeAsync();
await _command.DisposeAsync();
GC.SuppressFinalize(this);
}
}

View File

@ -1,6 +0,0 @@
namespace Tiger.Storage;
public interface IDatabaseHelper
{
DatabaseConnection GetConnection();
}

View File

@ -0,0 +1,8 @@
using NHibernate;
namespace Tiger.Storage;
public interface INhSessionFactory
{
ISession OpenSession();
}

11
Storage/IRepository.cs Normal file
View File

@ -0,0 +1,11 @@
using System.Linq.Expressions;
namespace Tiger.Storage;
public interface IRepository<T>
{
Task<T?> FindAsync(object id);
Task SaveAsync(T entity);
Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression = null);
Task<T?> FindOneByAsync(Expression<Func<T, bool>> expression);
}

View File

@ -1,13 +1,17 @@
using System.Reflection;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using Microsoft.Extensions.Configuration;
using MySqlConnector;
using MySql.Data.MySqlClient;
using NHibernate;
namespace Tiger.Storage;
public class DatabaseHelper : IDatabaseHelper
public class NhSessionFactory : INhSessionFactory
{
private readonly string _connectionString;
public DatabaseHelper(IConfiguration configuration)
private readonly ISessionFactory _sessionFactory;
public NhSessionFactory(IConfiguration configuration)
{
var stringBuilder = new MySqlConnectionStringBuilder
{
@ -21,11 +25,14 @@ public class DatabaseHelper : IDatabaseHelper
MaximumPoolSize = uint.Parse(configuration["Database:MaxPool"] ?? "15")
};
_connectionString = stringBuilder.ToString();
_sessionFactory = Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(stringBuilder.ToString()).ShowSql())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.BuildSessionFactory();
}
public DatabaseConnection GetConnection()
public ISession OpenSession()
{
return new DatabaseConnection(new MySqlConnection(_connectionString));
return _sessionFactory.OpenSession();
}
}

42
Storage/Repository.cs Normal file
View File

@ -0,0 +1,42 @@
using System.Linq.Expressions;
using NHibernate;
using NHibernate.Linq;
namespace Tiger.Storage;
public class Repository<T> : IRepository<T> where T : class
{
private readonly ISession _session;
public Repository(ISession session)
{
_session = session;
}
public async Task<T?> FindAsync(object id)
{
return await _session.GetAsync<T>(id);
}
public async Task SaveAsync(T entity)
{
await _session.SaveOrUpdateAsync(entity);
}
public async Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression)
{
var query = _session.Query<T>();
if (expression != null)
{
query = query.Where(expression);
}
return await query.ToListAsync();
}
public async Task<T?> FindOneByAsync(Expression<Func<T, bool>> expression)
{
return await _session.Query<T>().FirstOrDefaultAsync(expression);
}
}

View File

@ -12,12 +12,13 @@
<ItemGroup>
<PackageReference Include="FluentNHibernate" Version="3.3.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.Yaml" Version="2.0.0-preview2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="MySqlConnector" Version="2.3.0-beta.3" />
<PackageReference Include="MySql.Data" Version="8.1.0" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.yaml">