186 lines
No EOL
6.5 KiB
C#
186 lines
No EOL
6.5 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using PhoenixLib.Caching;
|
|
using WingsAPI.Communication.Bazaar;
|
|
using WingsAPI.Data.Bazaar;
|
|
using WingsAPI.Game.Extensions.Bazaar;
|
|
using WingsAPI.Packets.Enums.Bazaar;
|
|
using WingsEmu.Core.Extensions;
|
|
using WingsEmu.Core.Generics;
|
|
using WingsEmu.DTOs.Bazaar;
|
|
|
|
namespace BazaarServer.Managers
|
|
{
|
|
public class BazaarManager
|
|
{
|
|
private readonly IBazaarItemDAO _bazaarItemDao;
|
|
private readonly BazaarSearchManager _bazaarSearchManager;
|
|
|
|
private readonly ILongKeyCachedRepository<BazaarItemDTO> _itemsCache;
|
|
private readonly ConcurrentDictionary<long, ThreadSafeHashSet<long>> _itemsIdsByCharacterId = new();
|
|
|
|
private readonly SemaphoreSlim _semaphoreSlim = new(1, 1);
|
|
|
|
public BazaarManager(IBazaarItemDAO bazaarItemDao, ILongKeyCachedRepository<BazaarItemDTO> itemsCache, BazaarSearchManager bazaarSearchManager)
|
|
{
|
|
_bazaarItemDao = bazaarItemDao;
|
|
_itemsCache = itemsCache;
|
|
_bazaarSearchManager = bazaarSearchManager;
|
|
}
|
|
|
|
public async Task<long> CacheAllItemsInDb()
|
|
{
|
|
IEnumerable<BazaarItemDTO> items = await _bazaarItemDao.GetAllNonDeletedBazaarItems();
|
|
int count = 0;
|
|
foreach (BazaarItemDTO item in items)
|
|
{
|
|
AddToCache(item);
|
|
count++;
|
|
}
|
|
|
|
await _bazaarSearchManager.Initialize(items);
|
|
|
|
return count;
|
|
}
|
|
|
|
private void AddToCache(BazaarItemDTO item)
|
|
{
|
|
_itemsCache.Set(item.Id, item);
|
|
_itemsIdsByCharacterId.GetOrAdd(item.CharacterId, new ThreadSafeHashSet<long>()).Add(item.Id);
|
|
}
|
|
|
|
private void RemoveFromCache(BazaarItemDTO item)
|
|
{
|
|
_itemsCache.Remove(item.Id);
|
|
_itemsIdsByCharacterId.GetOrDefault(item.CharacterId)?.Remove(item.Id);
|
|
}
|
|
|
|
public async Task<BazaarItemDTO> SaveAsync(BazaarItemDTO item)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
BazaarItemDTO dto = await _bazaarItemDao.SaveAsync(item);
|
|
AddToCache(dto);
|
|
_bazaarSearchManager.AddItem(dto);
|
|
return dto;
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
|
|
public async Task<BazaarItemDTO> GetBazaarItemById(long bazaarItemId)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
return _itemsCache.Get(bazaarItemId);
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
|
|
public ICollection<BazaarItemDTO> GetItemsByCharacterId(long characterId)
|
|
{
|
|
return _itemsIdsByCharacterId.GetOrDefault(characterId)?.Select(s => _itemsCache.Get(s)).ToList();
|
|
}
|
|
|
|
public async Task<BazaarItemDTO> DeleteItemWithDto(BazaarItemDTO item, long requesterCharacterId)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
BazaarItemDTO cachedItem = _itemsCache.Get(item.Id);
|
|
if (cachedItem == null || cachedItem.CharacterId != requesterCharacterId)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
await _bazaarItemDao.DeleteByIdAsync(item.Id);
|
|
RemoveFromCache(item);
|
|
_bazaarSearchManager.RemoveItem(item);
|
|
return cachedItem;
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
|
|
public async Task<BazaarItemDTO> ChangeItemPriceWithDto(BazaarItemDTO bazaarItemDto, long characterId, long price, long saleFee)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
BazaarItemDTO cachedItem = _itemsCache.Get(bazaarItemDto.Id);
|
|
if (cachedItem == null || cachedItem.SoldAmount > 0 || characterId != cachedItem.CharacterId || cachedItem.GetBazaarItemStatus() != BazaarListedItemType.ForSale
|
|
|| BazaarExtensions.PriceOrAmountExceeds(bazaarItemDto.UsedMedal, price, bazaarItemDto.Amount))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
cachedItem.PricePerItem = price;
|
|
cachedItem.SaleFee = saleFee;
|
|
BazaarItemDTO savedItem = await _bazaarItemDao.SaveAsync(cachedItem);
|
|
return savedItem;
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
|
|
public IReadOnlyCollection<BazaarItemDTO> SearchBazaarItems(BazaarSearchContext bazaarSearchContext) => _bazaarSearchManager.SearchBazaarItems(bazaarSearchContext);
|
|
|
|
public async Task<BazaarItemDTO> BuyItemWithExpectedValues(long bazaarItemId, long buyerCharacterId, short amount, long pricePerItem)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
BazaarItemDTO cachedItem = _itemsCache.Get(bazaarItemId);
|
|
if (cachedItem == null || buyerCharacterId == cachedItem.CharacterId || amount < 1 || cachedItem.Amount - cachedItem.SoldAmount < amount || pricePerItem != cachedItem.PricePerItem
|
|
|| cachedItem.IsPackage && amount != cachedItem.Amount || cachedItem.GetBazaarItemStatus() != BazaarListedItemType.ForSale)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
cachedItem.SoldAmount += amount;
|
|
BazaarItemDTO savedItem = await _bazaarItemDao.SaveAsync(cachedItem);
|
|
return savedItem;
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
|
|
public async Task<List<BazaarItemDTO>> UnlistItemsWithVnums(List<BazaarItemDTO> items)
|
|
{
|
|
await _semaphoreSlim.WaitAsync();
|
|
try
|
|
{
|
|
foreach (BazaarItemDTO bazaarItemDto in items)
|
|
{
|
|
bazaarItemDto.ExpiryDate = DateTime.UtcNow.AddDays(-1);
|
|
BazaarItemDTO dto = await _bazaarItemDao.SaveAsync(bazaarItemDto);
|
|
AddToCache(dto);
|
|
_bazaarSearchManager.AddItem(dto);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
finally
|
|
{
|
|
_semaphoreSlim.Release();
|
|
}
|
|
}
|
|
}
|
|
} |