using AyCode.Core.Extensions; using AyCode.Utils.Extensions; using Nop.Plugin.Misc.AuctionPlugin.Hubs.Messages; using Nop.Plugin.Misc.AuctionPlugin.Models; using Nop.Plugin.Misc.AuctionPlugin.Services; using Nop.Services.Catalog; using Nop.Services.Logging; using Microsoft.AspNetCore.SignalR; using Nop.Core; using Nop.Plugin.Misc.AuctionPlugin.Domains.Enums; namespace Nop.Plugin.Misc.AuctionPlugin.Hubs { //- Dollár currency //- Pipa, ha tied a licit //- Pause, Lezárás, Revert, //- ha saját licit a legjobb vagy lezárt, ne lehessen bid-elni //- az előző esetben a kliensen a gombot is tiltani, már a.cshtml-ben ellenőrizni! //- csak a watch-olt item-eknél legyen announcment //- ha bid-elt 1x is, kerüljön a watch-ba //- DbTransaction-t vhogy megcsinánli! public class SignalRMessageHandler(ILogger logger, IProductService productService, AuctionService auctionService, IHubContext hubContext, IWorkContext workContext) { private readonly Mutex _handleMessageMutex = new(); public async Task HandleMessage(MessageWrapper message) { if (message?.Data == null) { logger.Error($"SignalRMessageHandler.HandleMessage(); message?.Data == null"); return; } await logger.InformationAsync($"SignalRMessageHandler.HandleMessage(); jsonData: {message.Data}"); if (message.SenderId <= 0 || message.SenderId != (await workContext.GetCurrentCustomerAsync()).Id) { logger.Error($"SignalRMessageHandler.HandleMessage(); message.SenderId <= 0 || message.SenderId != (await _workContext.GetCurrentCustomerAsync()).Id; SenderId: {message.SenderId}"); return; } using (_handleMessageMutex.UseWaitOne()) { try { switch (message.MessageType) { case "BidRequestMessage": await HandleBidRequest(message.SenderId, message.Data.JsonTo()); break; case "AuctionProductStatusRequest": await HandleProductToAuctionStatusChangedRequest(message.SenderId, message.Data.JsonTo()); break; // Add other message types here default: await logger.ErrorAsync($"SignalRMessageHandler.HandleMessage(); Unknown message type; MessageType: {message.MessageType}"); break; } } catch (Exception ex) { logger.Error($"SignalRMessageHandler.HandleMessage(); switch (message.MessageType); MessageType: {message.MessageType}; ex: {ex}"); } } } private async Task HandleProductToAuctionStatusChangedRequest(int senderId, AuctionProductStatusRequest auctionProductStatusRequest) { if (auctionProductStatusRequest == null) { logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); auctionProductStatusRequest == null"); return; } try { await logger.InformationAsync($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); ProductToAuctionMappingId: {auctionProductStatusRequest.ProductToAuctionId}; Status: {auctionProductStatusRequest.AuctionStatus}({(int)auctionProductStatusRequest.AuctionStatus})"); //TODO: if IsAdmin.. - J. //productBidBoxViewModel.IsAdmin = await _customerService.IsAdminAsync(customer); //productBidBoxViewModel.IsGuest = await _customerService.IsGuestAsync(customer); //TODO: if nincs aktív item.. - J. var auction = await auctionService.GetAuctionDtoByProductToAuctionIdAsync(auctionProductStatusRequest.ProductToAuctionId, false); if (auction == null || auction.Closed) { logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}"); return; } var productToAuction = await auctionService.GetProductToAuctionMappingByIdAsync(auctionProductStatusRequest.ProductToAuctionId); if (productToAuction == null) { logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (productToAuction == null)"); return; } //TODO: mi van ha már lezárt a productToAuction? - J. if (auctionProductStatusRequest.AuctionStatus == AuctionStatus.None) { //TODO: a ProductPrice-t ne változtassuk, mert emiatt nem jó a reset! - J. productToAuction.AuctionStatus = AuctionStatus.None; await auctionService.DeactivateProductToAuctionAsync(productToAuction); //TODO: Reset legyen és ne deactivate! - J. } else { switch (auctionProductStatusRequest.AuctionStatus) { case AuctionStatus.Pause: //TODO: Pause - J. break; case AuctionStatus.Sold: var lastAuctionBid = await auctionService.GetLastAuctionBidByProductToAuctionIdAsync(productToAuction.Id); if (lastAuctionBid == null) { productToAuction.AuctionStatus = AuctionStatus.NotSold; break; } productToAuction.AuctionStatus = AuctionStatus.Sold; productToAuction.WinnerCustomerId = lastAuctionBid.CustomerId; break; case AuctionStatus.NotSold: logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); (auctionProductStatusRequest.AuctionStatus == AuctionStatus.NotSold)"); break; case AuctionStatus.FirstWarning: case AuctionStatus.SecondWarning: case AuctionStatus.Active: default: productToAuction.AuctionStatus = auctionProductStatusRequest.AuctionStatus; break; } await auctionService.UpdateProductToAuctionMappingAsync(productToAuction); } var productToauctionChangedNotification = new MessageWrapper { MessageType = nameof(ProductToAuctionStatusNotification), SenderId = senderId, Data = new ProductToAuctionStatusNotification(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(productToAuction.Id, true)) { ToasterMessage = "EMPTY", //TODO: - J. }.ToJson() }; await hubContext.Clients.All.SendAsync("send", productToauctionChangedNotification.ToJson()); } catch (Exception ex) { logger.Error($"SignalRMessageHandler.HandleProductToAuctionStatusChangedRequest(); Error {ex.Message}"); } } private async Task HandleBidRequest(int senderId, AuctionBidRequest bidRequestMessage) { if (bidRequestMessage == null) { logger.Error($"SignalRMessageHandler.HandleBidRequest(); (bidRequestMessage == null)"); return; } try { await logger.InformationAsync($"SignalRMessageHandler.HandleBidRequest(); Bid received; Auction: {bidRequestMessage.AuctionId}; Product: {bidRequestMessage.ProductId}; Bid: {bidRequestMessage.BidPrice}; Customer: {bidRequestMessage.CustomerId}"); //CustomerService a = new CustomerService()a.IsGuestAsync() //TODO: IsGuestAsync??? - J. var customer = await workContext.GetCurrentCustomerAsync(); if (customer == null || bidRequestMessage.CustomerId != customer.Id) //|| !customer.Active) { logger.Error($"SignalRMessageHandler.HandleBidRequest(); (customer == null || bidRequestMessage.CustomerId != customer.Id)"); return; } var auction = await auctionService.GetAuctionDtoByIdAsync(bidRequestMessage.AuctionId, false, false); if (auction == null || auction.Closed) { logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (auction == null || auction.Closed); Closed: {auction?.Closed}"); return; } var activeProductAuction = (await auctionService.GetProductToAuctionByAuctionIdAndProductIdAsync(bidRequestMessage.AuctionId, bidRequestMessage.ProductId, true)).FirstOrDefault(); if (activeProductAuction is not { IsActiveItem: true } || activeProductAuction.WinnerCustomerId == customer.Id) { logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (activeProductAuction is not {{ IsActiveItem: true }} || activeProductAuction.WinnerCustomerId == customer.Id); AuctionStatus: {activeProductAuction?.AuctionStatus}; WinnerCustomerId: {activeProductAuction?.WinnerCustomerId}"); return; //TODO: - J. } var product = await productService.GetProductByIdAsync(bidRequestMessage.ProductId); if (product == null) { logger.Error($"SignalRMessageHandler.HandleBidRequest(); (product == null)"); return; //ha nincs product vagy exception van, akkor ne broadcast-eljük ki az invalid Bid-et! - J. } var auctionBid = bidRequestMessage.CreateMainEntity(); auctionBid.ProductAuctionMappingId = activeProductAuction.Id; //TODO: validate the bidprice amount if (product.Price >= auctionBid.BidPrice || activeProductAuction.CurrentPrice >= auctionBid.BidPrice) { logger.Warning($"SignalRMessageHandler.HandleBidRequest(); (product.Price >= bidRequestMessage.BidPrice || activeProductAuction.CurrentPrice >= auctionBid.BidPrice); productPrice: {product.Price}; bidRequestPrice: {auctionBid.BidPrice}; activeProductAuctionPrice: {activeProductAuction.CurrentPrice}"); return; } //save bid await auctionService.InsertBidAsync(auctionBid); //set new price product.Price = bidRequestMessage.BidPrice; await productService.UpdateProductAsync(product); activeProductAuction.StartingPrice = product.OldPrice; activeProductAuction.CurrentPrice = product.Price; activeProductAuction.AuctionStatus = AuctionStatus.Active; await auctionService.UpdateProductToAuctionMappingAsync(activeProductAuction); var stepAmount = AuctionService.GetStepAmount(auctionBid.BidPrice); var nextBidPrice = auctionBid.BidPrice + stepAmount; var bid = new MessageWrapper { MessageType = "bidNotification", SenderId = senderId, Data = new BidNotificationMessage(await auctionService.GetAuctionDtoByProductToAuctionIdAsync(activeProductAuction.Id, true)) { ProductName = product.Name, CurrentPrice = auctionBid.BidPrice, NextStepAmount = stepAmount, NextBidPrice = nextBidPrice, ToasterMessage = "EMPTY", //TODO: - J. }.ToJson() }; await hubContext.Clients.All.SendAsync("send", bid.ToJson()); } catch (Exception ex) { logger.Error($"SignalRMessageHandler.HandleBidRequest(); MessageHandling error: {ex}"); } } } }