Started on catalogue, added the index and pages packets
							parent
							
								
									66744ead65
								
							
						
					
					
						commit
						59d90aeeb2
					
				| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Interfaces;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Outgoing.Catalog;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Types;
 | 
				
			||||||
 | 
					using Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					using Tiger.Networking.Game.Sessions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Communication.Messages.Incoming.Catalog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class GetCatalogIndexEvent : IMessageEvent
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ICatalogueManager _catalogueManager;
 | 
				
			||||||
 | 
					    private readonly IGameSessionManager _gameSessionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GetCatalogIndexEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _catalogueManager = catalogueManager;
 | 
				
			||||||
 | 
					        _gameSessionManager = gameSessionManager;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IncomingHeaders Header => IncomingHeaders.GetCatalogIndexEvent;
 | 
				
			||||||
 | 
					    public async Task HandleAsync(GameSession gameSession, ClientMessage request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (gameSession.Habbo == null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await _gameSessionManager.CloseAsync("Not logged in", gameSession);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        var categories = _catalogueManager.Pages.Values.Where(p => p.Parent is null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await gameSession.SendComposerAsync(new CatalogIndexMessageComposer(categories,
 | 
				
			||||||
 | 
					            request.ReadString() ?? "normal"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Interfaces;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Outgoing.Catalog;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Types;
 | 
				
			||||||
 | 
					using Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					using Tiger.Networking.Game.Sessions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Communication.Messages.Incoming.Catalog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class GetCatalogPageEvent : IMessageEvent
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ICatalogueManager _catalogueManager;
 | 
				
			||||||
 | 
					    private readonly IGameSessionManager _gameSessionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GetCatalogPageEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _catalogueManager = catalogueManager;
 | 
				
			||||||
 | 
					        _gameSessionManager = gameSessionManager;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public IncomingHeaders Header => IncomingHeaders.GetCatalogPageEvent;
 | 
				
			||||||
 | 
					    public async Task HandleAsync(GameSession gameSession, ClientMessage request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (gameSession.Habbo == null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await _gameSessionManager.CloseAsync("Not logged in", gameSession);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var pageId = request.ReadInt32() ?? -1;
 | 
				
			||||||
 | 
					        var offerId = request.ReadInt32() ?? 0;
 | 
				
			||||||
 | 
					        var mode = request.ReadString() ?? "normal";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!_catalogueManager.Pages.TryGetValue(pageId, out var page))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await gameSession.SendComposerAsync(new CatalogPageMessageComposer(page, offerId, mode));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,8 @@ public class SetActivatedBadgesEvent : IMessageEvent
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        var wearingBadges = new Collection<Badge>();
 | 
					        var wearingBadges = new Collection<Badge>();
 | 
				
			||||||
        foreach (var currentBadge in gameSession.Habbo.Badges)
 | 
					        var current = gameSession.Habbo.Badges.Where(b => b.Slot != 0);
 | 
				
			||||||
 | 
					        foreach (var currentBadge in current)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            currentBadge.Slot = 0;
 | 
					            currentBadge.Slot = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Interfaces;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Types;
 | 
				
			||||||
 | 
					using Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Communication.Messages.Outgoing.Catalog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CatalogIndexMessageComposer : IMessageComposer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly IEnumerable<CataloguePage> _pages;
 | 
				
			||||||
 | 
					    private readonly string _mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public CatalogIndexMessageComposer(IEnumerable<CataloguePage> pages, string mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _pages = pages;
 | 
				
			||||||
 | 
					        _mode = mode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OutgoingHeaders Header => OutgoingHeaders.CatalogIndexMessageComposer;
 | 
				
			||||||
 | 
					    public void Compose(ServerMessage message)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        message.AppendBoolean(true);
 | 
				
			||||||
 | 
					        message.AppendInt32(0);
 | 
				
			||||||
 | 
					        message.AppendInt32(-1);
 | 
				
			||||||
 | 
					        message.AppendString(string.Empty);
 | 
				
			||||||
 | 
					        message.AppendString(string.Empty);
 | 
				
			||||||
 | 
					        message.AppendInt32(0);
 | 
				
			||||||
 | 
					        message.AppendInt32(_pages.Count());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var page in _pages)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SerializeNode(page, message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        message.AppendBoolean(false);
 | 
				
			||||||
 | 
					        message.AppendString(_mode);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void SerializeNode(CataloguePage page, ServerMessage message)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        message.AppendBoolean(page.Visible);
 | 
				
			||||||
 | 
					        message.AppendInt32(page.Icon);
 | 
				
			||||||
 | 
					        message.AppendInt32(page.Id);
 | 
				
			||||||
 | 
					        message.AppendString(page.InternalName);
 | 
				
			||||||
 | 
					        message.AppendString(page.Name);
 | 
				
			||||||
 | 
					        message.AppendInt32(0);
 | 
				
			||||||
 | 
					        message.AppendInt32(page.Children.Count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var child in page.Children)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SerializeNode(child, message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Interfaces;
 | 
				
			||||||
 | 
					using Tiger.Communication.Messages.Types;
 | 
				
			||||||
 | 
					using Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Communication.Messages.Outgoing.Catalog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CatalogPageMessageComposer : IMessageComposer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly CataloguePage _page;
 | 
				
			||||||
 | 
					    private readonly int _offerId;
 | 
				
			||||||
 | 
					    private readonly string _mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public CatalogPageMessageComposer(CataloguePage page, int offerId, string mode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _page = page;
 | 
				
			||||||
 | 
					        _offerId = offerId;
 | 
				
			||||||
 | 
					        _mode = mode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public OutgoingHeaders Header => OutgoingHeaders.CatalogPageMessageComposer;
 | 
				
			||||||
 | 
					    public void Compose(ServerMessage message)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        message.AppendInt32(_page.Id);
 | 
				
			||||||
 | 
					        message.AppendString(_mode);
 | 
				
			||||||
 | 
					        message.AppendString(_page.Layout);
 | 
				
			||||||
 | 
					        message.AppendInt32(_page.Images.Count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var image in _page.Images)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            message.AppendString(image);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        message.AppendInt32(_page.Texts.Count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (var text in _page.Texts)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            message.AppendString(text);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        message.AppendInt32(0);
 | 
				
			||||||
 | 
					        message.AppendInt32(_offerId);
 | 
				
			||||||
 | 
					        message.AppendBoolean(_page.SeasonalCurrency);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -55,7 +55,7 @@ public enum OutgoingHeaders
 | 
				
			||||||
    CarryObjectMessageComposer = 1474,
 | 
					    CarryObjectMessageComposer = 1474,
 | 
				
			||||||
    CatalogPageExpirationComposer = 2668,
 | 
					    CatalogPageExpirationComposer = 2668,
 | 
				
			||||||
    CatalogPageMessageComposer = 804,
 | 
					    CatalogPageMessageComposer = 804,
 | 
				
			||||||
    CatalogPagesListComposer = 1032,
 | 
					    CatalogIndexMessageComposer = 1032,
 | 
				
			||||||
    CatalogPageWithEarliestExpiryMessageComposer = 2515,
 | 
					    CatalogPageWithEarliestExpiryMessageComposer = 2515,
 | 
				
			||||||
    CatalogPublishedMessageComposer = 1866,
 | 
					    CatalogPublishedMessageComposer = 1866,
 | 
				
			||||||
    CategoriesWithVisitorCountComposer = 1455,
 | 
					    CategoriesWithVisitorCountComposer = 1455,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Tiger.Storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CatalogueManager : ICatalogueManager
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly IRepository<CataloguePage> _pagesRepository;
 | 
				
			||||||
 | 
					    private readonly ILogger<ICatalogueManager> _logger;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public IDictionary<int, CataloguePage> Pages { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public CatalogueManager(IRepository<CataloguePage> pagesRepository, ILogger<ICatalogueManager> logger)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _pagesRepository = pagesRepository;
 | 
				
			||||||
 | 
					        _logger = logger;
 | 
				
			||||||
 | 
					        Pages = new Dictionary<int, CataloguePage>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public async Task LoadPagesAsync()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Pages = (await _pagesRepository.FindByAsync()).ToDictionary(p => p.Id, p => p);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        _logger.LogInformation("Loaded {Count} catalogue pages", Pages.Count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					namespace Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CataloguePage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public virtual int Id { get; set; }
 | 
				
			||||||
 | 
					    public virtual string Name { get; set; } = null!;
 | 
				
			||||||
 | 
					    public virtual string InternalName { get; set; } = null!;
 | 
				
			||||||
 | 
					    public virtual string Layout { get; set; } = null!;
 | 
				
			||||||
 | 
					    public virtual bool Visible { get; set; }
 | 
				
			||||||
 | 
					    public virtual bool Enabled { get; set; }
 | 
				
			||||||
 | 
					    public virtual int Icon { get; set; }
 | 
				
			||||||
 | 
					    public virtual int MinRank { get; set; }
 | 
				
			||||||
 | 
					    public virtual CataloguePage? Parent { get; set; }
 | 
				
			||||||
 | 
					    public virtual IList<CataloguePage> Children { get; set; } = new List<CataloguePage>();
 | 
				
			||||||
 | 
					    public virtual IList<string> Images { get; set; } = new List<string>();
 | 
				
			||||||
 | 
					    public virtual IList<string> Texts { get; set; } = new List<string>();
 | 
				
			||||||
 | 
					    public virtual bool SeasonalCurrency { get; set; }
 | 
				
			||||||
 | 
					    public virtual IList<string> Modes { get; set; } = new List<string>();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					using FluentNHibernate.Mapping;
 | 
				
			||||||
 | 
					using Tiger.Storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CataloguePageMap : ClassMap<CataloguePage>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public CataloguePageMap()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Table("catalogue_pages");
 | 
				
			||||||
 | 
					        LazyLoad();
 | 
				
			||||||
 | 
					        Id(c => c.Id).Column("id").GeneratedBy.Identity();
 | 
				
			||||||
 | 
					        Map(c => c.Name).Column("name").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.InternalName).Column("internal_name").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.Layout).Column("layout").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.Visible).Column("visible").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.Enabled).Column("enabled").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.Icon).Column("icon").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.MinRank).Column("min_rank").Not.Nullable();
 | 
				
			||||||
 | 
					        References(x => x.Parent).Column("parent_id").Nullable();
 | 
				
			||||||
 | 
					        HasMany(x => x.Children).KeyColumn("parent_id").Inverse().Cascade.AllDeleteOrphan();
 | 
				
			||||||
 | 
					        Map(c => c.Images).CustomType<StringListTypeConverter>();
 | 
				
			||||||
 | 
					        Map(c => c.Texts).CustomType<StringListTypeConverter>();
 | 
				
			||||||
 | 
					        Map(c => c.SeasonalCurrency).Column("seasonal_currency").Not.Nullable();
 | 
				
			||||||
 | 
					        Map(c => c.Modes).CustomType<StringListTypeConverter>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					namespace Tiger.Game.Catalogue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface ICatalogueManager
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public IDictionary<int, CataloguePage> Pages { get; }
 | 
				
			||||||
 | 
					    Task LoadPagesAsync();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ using Microsoft.Extensions.Configuration.Yaml;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Tiger.Communication.Messages;
 | 
					using Tiger.Communication.Messages;
 | 
				
			||||||
 | 
					using Tiger.Game.Catalogue;
 | 
				
			||||||
using Tiger.Game.Habbos;
 | 
					using Tiger.Game.Habbos;
 | 
				
			||||||
using Tiger.Game.Settings;
 | 
					using Tiger.Game.Settings;
 | 
				
			||||||
using Tiger.Networking.Game;
 | 
					using Tiger.Networking.Game;
 | 
				
			||||||
| 
						 | 
					@ -33,11 +34,13 @@ collection.AddSingleton<INhSessionFactory, NhSessionFactory>();
 | 
				
			||||||
collection.AddScoped(serviceProvider => serviceProvider.GetRequiredService<INhSessionFactory>().OpenSession());
 | 
					collection.AddScoped(serviceProvider => serviceProvider.GetRequiredService<INhSessionFactory>().OpenSession());
 | 
				
			||||||
collection.AddScoped(typeof(IRepository<>), typeof(Repository<>));
 | 
					collection.AddScoped(typeof(IRepository<>), typeof(Repository<>));
 | 
				
			||||||
collection.AddSingleton<ISettingManager, SettingManager>();
 | 
					collection.AddSingleton<ISettingManager, SettingManager>();
 | 
				
			||||||
 | 
					collection.AddSingleton<ICatalogueManager, CatalogueManager>();
 | 
				
			||||||
collection.RegisterMessageEvents();
 | 
					collection.RegisterMessageEvents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var provider = collection.BuildServiceProvider();
 | 
					var provider = collection.BuildServiceProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
await provider.GetRequiredService<ISettingManager>().ReloadSettingsAsync();
 | 
					await provider.GetRequiredService<ISettingManager>().ReloadSettingsAsync();
 | 
				
			||||||
 | 
					await provider.GetRequiredService<ICatalogueManager>().LoadPagesAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
provider.GetRequiredService<IWebSocketServer>().Start($"http://{configuration["Network:Game:Ip"]}:{configuration["Network:Game:Port"]}/");
 | 
					provider.GetRequiredService<IWebSocketServer>().Start($"http://{configuration["Network:Game:Ip"]}:{configuration["Network:Game:Port"]}/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,9 @@ public interface IRepository<T>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Task<T?> FindAsync(object id);
 | 
					    Task<T?> FindAsync(object id);
 | 
				
			||||||
    Task SaveAsync(T entity);
 | 
					    Task SaveAsync(T entity);
 | 
				
			||||||
 | 
					    Task SaveManyAsync(params T[] entities);
 | 
				
			||||||
 | 
					    Task SaveManyAsync(IEnumerable<T> entities);
 | 
				
			||||||
 | 
					    // Task FlushAsync();
 | 
				
			||||||
    Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression = null);
 | 
					    Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression = null);
 | 
				
			||||||
    Task<T?> FindOneByAsync(Expression<Func<T, bool>> expression);
 | 
					    Task<T?> FindOneByAsync(Expression<Func<T, bool>> expression);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,26 @@ public class Repository<T> : IRepository<T> where T : class
 | 
				
			||||||
        await _session.FlushAsync();
 | 
					        await _session.FlushAsync();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public async Task SaveManyAsync(params T[] entities)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach (var entity in entities)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await _session.SaveOrUpdateAsync(entity);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await _session.FlushAsync();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public async Task SaveManyAsync(IEnumerable<T> entities)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach (var entity in entities)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await _session.SaveOrUpdateAsync(entity);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await _session.FlushAsync();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public async Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression)
 | 
					    public async Task<IEnumerable<T>> FindByAsync(Expression<Func<T, bool>>? expression)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var query = _session.Query<T>();
 | 
					        var query = _session.Query<T>();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
 | 
					using System.Text.Json;
 | 
				
			||||||
 | 
					using NHibernate.Engine;
 | 
				
			||||||
 | 
					using NHibernate.SqlTypes;
 | 
				
			||||||
 | 
					using NHibernate.UserTypes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tiger.Storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class StringListTypeConverter : IUserType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public new bool Equals(object x, object y)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return object.Equals(x, y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int GetHashCode(object x)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return x.GetHashCode();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var r = rs[names[0]];
 | 
				
			||||||
 | 
					        if (r == DBNull.Value) return null!;
 | 
				
			||||||
 | 
					        var strList = JsonSerializer.Deserialize<List<string>>(r.ToString() ?? "") ?? new List<string>();
 | 
				
			||||||
 | 
					        return strList;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (value == null!)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var strList = (List<string>)value;
 | 
				
			||||||
 | 
					            var strValue = JsonSerializer.Serialize(strList);
 | 
				
			||||||
 | 
					            ((IDataParameter)cmd.Parameters[index]).Value = strValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object DeepCopy(object value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object Replace(object original, object target, object owner)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return original;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object Assemble(object cached, object owner)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return cached;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public object Disassemble(object value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SqlType[] SqlTypes => new SqlType[] { SqlTypeFactory.GetString(8000) };
 | 
				
			||||||
 | 
					    public Type ReturnedType => typeof(List<string>);
 | 
				
			||||||
 | 
					    public bool IsMutable => true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@
 | 
				
			||||||
    </ItemGroup>
 | 
					    </ItemGroup>
 | 
				
			||||||
    <ItemGroup>
 | 
					    <ItemGroup>
 | 
				
			||||||
      <None Update="appsettings.yaml">
 | 
					      <None Update="appsettings.yaml">
 | 
				
			||||||
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
					        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
				
			||||||
      </None>
 | 
					      </None>
 | 
				
			||||||
    </ItemGroup>
 | 
					    </ItemGroup>
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
Database:
 | 
					Database:
 | 
				
			||||||
  Host: 127.0.0.1
 | 
					  Host: localhost
 | 
				
			||||||
  Port: 3306
 | 
					  Port: 3306
 | 
				
			||||||
  Username: root
 | 
					  Username: tiger
 | 
				
			||||||
  Password: 123
 | 
					  Password: 123
 | 
				
			||||||
  Database: tiger_db
 | 
					  Database: tiger_db
 | 
				
			||||||
  MinPool: 5
 | 
					  MinPool: 5
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue