public async Task Start() { //ЗАПУСК СЛУШАТЕЛЯ ДЛЯ ТЕРМИНАЛОВ--------------------------------------------------------- if (Listener != null) { var taskListener = Listener.RunServer(ProviderTerminal); BackGroundTasks.Add(taskListener); } //ЗАПУСК ОПРОСА КАССИРОВ------------------------------------------------------------------- if (MasterSerialPort != null) { var taskSerialPort = Task.Factory.StartNew(async() => { if (await MasterSerialPort.CycleReConnect()) { var taskCashierEx = MasterSerialPort.RunExchange(); BackGroundTasks.Add(taskCashierEx); } }); BackGroundTasks.Add(taskSerialPort); } //КОНТРОЛЬ ФОНОВЫХ ЗАДАЧ var taskFirst = await Task.WhenAny(BackGroundTasks); if (taskFirst.Exception != null) //критическая ошибка фоновой задачи { ErrorString = taskFirst.Exception.ToString(); } }
public void LoadSetting() { //ЗАГРУЗКА НАСТРОЕК---------------------------------------------------------------- XmlListenerSettings xmlListener; XmlSerialSettings xmlSerial; XmlLogSettings xmlLog; List <XmlCashierSettings> xmlCashier; try { var xmlFile = XmlWorker.LoadXmlFile("Settings", "Setting.xml"); //все настройки в одном файле if (xmlFile == null) { return; } xmlListener = XmlListenerSettings.LoadXmlSetting(xmlFile); xmlSerial = XmlSerialSettings.LoadXmlSetting(xmlFile); xmlLog = XmlLogSettings.LoadXmlSetting(xmlFile); xmlCashier = XmlCashierSettings.LoadXmlSetting(xmlFile); } catch (FileNotFoundException ex) { ErrorString = ex.ToString(); return; } catch (Exception ex) { ErrorString = "ОШИБКА в узлах дерева XML файла настроек: " + ex; return; } //СОЗДАНИЕ ЛОГА-------------------------------------------------------------------------- LogTicket = new Log("TicketLog.txt", xmlLog); //СОЗДАНИЕ СЛУШАТЕЛЯ ДЛЯ ТЕРМИНАЛОВ------------------------------------------------------- Listener = new ListenerTcpIp(xmlListener); ProviderTerminal = new Server2TerminalExchangeDataProvider(); ProviderTerminal.PropertyChanged += (o, e) => { var provider = o as Server2TerminalExchangeDataProvider; if (provider != null) { if (e.PropertyName == "InputData") { TicketItem ticket; provider.OutputData = provider.OutputData ?? new TerminalOutData(); switch (provider.InputData.NumberQueue) { //ПРИГОРОДНЫЕ КАСС case 1: switch (provider.InputData.Action) { //ИНФОРМАЦИЯ ОБ ОЧЕРЕДИ case TerminalAction.Info: provider.OutputData.NumberQueue = provider.InputData.NumberQueue; provider.OutputData.CountElement = (ushort)QueueVilage.Count; provider.OutputData.NumberElement = (ushort)(TicketFactoryVilage.GetCurrentTicketNumber + 1); provider.OutputData.AddedTime = DateTime.Now; break; //ДОБАВИТЬ БИЛЕТ В ОЧЕРЕДЬ case TerminalAction.Add: ticket = TicketFactoryVilage.Create((ushort)QueueVilage.Count); provider.OutputData.NumberQueue = provider.InputData.NumberQueue; provider.OutputData.CountElement = ticket.CountElement; provider.OutputData.NumberElement = (ushort)ticket.NumberElement; provider.OutputData.AddedTime = ticket.AddedTime; QueueVilage.Enqueue(ticket); break; } break; //ДАЛЬНЕГО СЛЕДОВАНИЯ КАССЫ case 2: switch (provider.InputData.Action) { //ИНФОРМАЦИЯ ОБ ОЧЕРЕДИ case TerminalAction.Info: provider.OutputData.NumberQueue = provider.InputData.NumberQueue; provider.OutputData.CountElement = (ushort)QueueLong.Count; provider.OutputData.NumberElement = (ushort)(TicketFactoryLong.GetCurrentTicketNumber + 1); provider.OutputData.AddedTime = DateTime.Now; break; //ДОБАВИТЬ БИЛЕТ В ОЧЕРЕДЬ case TerminalAction.Add: ticket = TicketFactoryLong.Create((ushort)QueueLong.Count); provider.OutputData.NumberQueue = provider.InputData.NumberQueue; provider.OutputData.CountElement = ticket.CountElement; provider.OutputData.NumberElement = (ushort)ticket.NumberElement; provider.OutputData.AddedTime = ticket.AddedTime; QueueLong.Enqueue(ticket); break; } break; } } } }; //СОЗДАНИЕ КАССИРОВ------------------------------------------------------------------------------------------------ foreach (var xmlCash in xmlCashier) { var casher = new Сashier(xmlCash.Id, (xmlCash.Prefix == "A") ? QueueVilage : QueueLong, xmlCash.MaxCountTryHanding); DeviceCashiers.Add(new DeviceCashier(casher)); } //СОЗДАНИЕ ПОСЛЕД. ПОРТА ДЛЯ ОПРОСА КАССИРОВ----------------------------------------------------------------------- MasterSerialPort = new MasterSerialPort(xmlSerial); CashierExchangeService = new CashierExchangeService(DeviceCashiers, xmlSerial.TimeRespoune); MasterSerialPort.AddFunc(CashierExchangeService.ExchangeService); MasterSerialPort.PropertyChanged += (o, e) => { var port = o as MasterSerialPort; if (port != null) { if (e.PropertyName == "StatusString") { ErrorString = port.StatusString; } } }; }
public void Dispose() { Listener?.Dispose(); MasterSerialPort?.Dispose(); }
public async Task ExchangeService(MasterSerialPort port, CancellationToken ct) { if (port == null) { return; } foreach (var devCashier in _deviceCashiers) //Запуск опроса кассиров { var readProvider = new Server2CashierReadDataProvider { InputData = devCashier.Cashier.Id }; devCashier.DataExchangeSuccess = await port.DataExchangeAsync(_timeRespone, readProvider, ct); if (!devCashier.IsConnect) { devCashier.Cashier.DisconectHandling(); continue; } if (readProvider.IsOutDataValid) { TicketItem item; var cashierInfo = readProvider.OutputData; if (!cashierInfo.IsWork) { continue; } switch (cashierInfo.Handling) { case CashierHandling.IsSuccessfulHandling: devCashier.Cashier.SuccessfulHandling(); break; case CashierHandling.IsErrorHandling: devCashier.Cashier.ErrorHandling(); break; case CashierHandling.IsStartHandling: item = devCashier.Cashier.StartHandling(); var writeProvider = new Server2CashierWriteDataProvider { InputData = item }; await port.DataExchangeAsync(_timeRespone, writeProvider, ct); if (writeProvider.IsOutDataValid) //завершение транзакции ( успешная передача билета кассиру) { devCashier.Cashier.SuccessfulStartHandling(); } break; case CashierHandling.IsSuccessfulAndStartHandling: devCashier.Cashier.SuccessfulHandling(); item = devCashier.Cashier.StartHandling(); writeProvider = new Server2CashierWriteDataProvider { InputData = item }; await port.DataExchangeAsync(_timeRespone, writeProvider, ct); if (writeProvider.IsOutDataValid) //завершение транзакции ( успешная передача билета кассиру) { devCashier.Cashier.SuccessfulStartHandling(); } break; case CashierHandling.IsErrorAndStartHandling: devCashier.Cashier.ErrorHandling(); item = devCashier.Cashier.StartHandling(); writeProvider = new Server2CashierWriteDataProvider { InputData = item }; await port.DataExchangeAsync(_timeRespone, writeProvider, ct); if (writeProvider.IsOutDataValid) //завершение транзакции ( успешная передача билета кассиру) { devCashier.Cashier.SuccessfulStartHandling(); } break; default: item = null; break; } } } //Отправка запроса синхронизации времени раз в час if (_lastSyncLabel != DateTime.Now.Hour) { _lastSyncLabel = DateTime.Now.Hour; var syncTimeProvider = new Server2CashierSyncTimeDataProvider(); await port.DataExchangeAsync(_timeRespone, syncTimeProvider, ct); } }
public async Task ExchangeService(MasterSerialPort port, CancellationToken ct) { if (port == null) { return; } try { foreach (var devCashier in _deviceCashiers) //Запуск опроса кассиров { _loggerCashierInfo.Info($"---------------------------КАССИР: Id= {devCashier.Cashier.Id} CurrentTicket= {(devCashier.Cashier.CurrentTicket != null ? devCashier.Cashier.CurrentTicket.Prefix + devCashier.Cashier.CurrentTicket.NumberElement.ToString("000") : "НЕТ")}----------------------------------"); //LOG; var readProvider = new Server2CashierReadDataProvider(devCashier.AddresDevice, _logName); devCashier.DataExchangeSuccess = await port.DataExchangeAsync(_timeRespone, readProvider, ct); if (!devCashier.IsConnect) { _loggerCashierInfo.Info($"кассир НЕ на связи: Id= {devCashier.Cashier.Id}");//LOG; devCashier.LastSyncLabel = 0; continue; } if (readProvider.IsOutDataValid) { TicketItem item; var cashierInfo = readProvider.OutputData; //Если устойство было не на связи, то Отправка запроса синхронизации времени раз в час, будет произведенна мгновенно. if (devCashier.LastSyncLabel != DateTime.Now.Hour) { devCashier.LastSyncLabel = DateTime.Now.Hour; var syncTimeProvider = new Server2CashierSyncTimeDataProvider(_logName); await port.DataExchangeAsync(_timeRespone, syncTimeProvider, ct); } //TODO: проверить if (!cashierInfo.IsWork) { //Если кассир быстро закрыла сессию (до того как опрос порта дошел до нее), то билет из обработки надо убрать. if (devCashier.Cashier.CurrentTicket != null) { _loggerCashierInfo.Info($"Команда от кассира: Id= {devCashier.Cashier.Id} Handling=\"Если кассир быстро закрыла сессию(до того как опрос порта дошел до нее). НО У НЕЕ БЫЛ ТЕКУЩИЙ ОБРАБАТЫВАЕМЫЙ БИЛЕТ\" NameTicket= {cashierInfo.NameTicket}");//LOG; //devCashier.Cashier.SuccessfulHandling(); } continue; } switch (cashierInfo.Handling) { case CashierHandling.IsSuccessfulHandling: if (!devCashier.Cashier.CanHandling) { break; } devCashier.Cashier.SuccessfulHandling(); break; case CashierHandling.IsErrorHandling: if (!devCashier.Cashier.CanHandling) { break; } devCashier.Cashier.ErrorHandling(); break; case CashierHandling.IsStartHandling: await WriteTicketTransaction(devCashier, cashierInfo.Handling, port, ct); break; case CashierHandling.IsSuccessfulAndStartHandling: devCashier.Cashier.SuccessfulHandling(); await WriteTicketTransaction(devCashier, cashierInfo.Handling, port, ct); break; case CashierHandling.IsRedirectAndStartHandling: if (_adminCashier != null) { var redirectTicket = devCashier.Cashier.CurrentTicket; if (redirectTicket != null) { _adminCashier.Cashier.AddRedirectedTicket(redirectTicket); } devCashier.Cashier.SuccessfulHandling(); await WriteTicketTransaction(devCashier, cashierInfo.Handling, port, ct); } break; case CashierHandling.IsErrorAndStartHandling: devCashier.Cashier.ErrorHandling(); await WriteTicketTransaction(devCashier, cashierInfo.Handling, port, ct); break; case CashierHandling.IsRedirectHandling: if (_adminCashier != null) { if (!devCashier.Cashier.CanHandling) { break; } var redirectTicket = devCashier.Cashier.CurrentTicket; if (redirectTicket != null) { _adminCashier.Cashier.AddRedirectedTicket(redirectTicket); } devCashier.Cashier.SuccessfulHandling(); } break; default: item = null; break; } } } } catch (Exception ex) { _loggerCashierInfo.Info($"EXCEPTION CashierExchangeService: {ex.ToString()}"); } }
/// <summary> /// Транзакция на передачу билета кассиру. /// </summary> private async Task <bool> WriteTicketTransaction(DeviceCashier devCashier, CashierHandling handling, MasterSerialPort port, CancellationToken ct) { var item = devCashier.Cashier.StartHandling(); if (item == null) //БЛОКИРОВКА ТРАНЗАКЦИИ (билет уже используетсяв транзакции) { return(false); } var writeProvider = new Server2CashierWriteDataProvider(devCashier.AddresDevice, _logName) { InputData = item }; await port.DataExchangeAsync(_timeRespone, writeProvider, ct); if (writeProvider.IsOutDataValid) //ТРАНЗАКЦИЯ ЗАВЕРШЕНА УСПЕШНО (извлечем билет из очереди и присвоим кассиру) { devCashier.Cashier.StartHandlingSuccessful(); } else //ТРАНЗАКЦИЯ ЗАВЕРШЕНА С ОШИБКОЙ (снимем блокировку) { _loggerCashierInfo.Info($"НЕ УДАЧНАЯ ТРАНЗАКЦИЯ ПЕРЕДАЧИ БИЛЕТА КАССИРУ: Id= {devCashier.Cashier.Id} НА КОМАНДУ={handling}"); devCashier.Cashier.StartHandlingFaild(); return(false); } return(true); }
public void LoadSetting() { //ЗАГРУЗКА НАСТРОЕК---------------------------------------------------------------- XmlListenerSettings xmlListener; IList <XmlSerialSettings> xmlSerials; List <XmlCashierSettings> xmlCashier; List <XmlQueuesSettings> xmlQueues; try { var xmlFile = XmlWorker.LoadXmlFile("Settings", "Setting.xml"); //все настройки в одном файле if (xmlFile == null) { return; } xmlListener = XmlListenerSettings.LoadXmlSetting(xmlFile); xmlSerials = XmlSerialSettings.LoadXmlSetting(xmlFile).ToList(); xmlCashier = XmlCashierSettings.LoadXmlSetting(xmlFile); xmlQueues = XmlQueuesSettings.LoadXmlSetting(xmlFile); } catch (FileNotFoundException ex) { ErrorString = ex.ToString(); return; } catch (Exception ex) { ErrorString = "ОШИБКА в узлах дерева XML файла настроек: " + ex; return; } //РАЗРЕШИТЬ ЛОГГИРОВАНИЕ----------------------------------------------------------- Log.EnableLogging(true); //СОЗДАНИЕ ОЧЕРЕДИ----------------------------------------------------------------------- foreach (var xmlQueue in xmlQueues) { var queue = new QueuePriority(xmlQueue.Name, xmlQueue.Prefixes); QueuePriorities.Add(queue); } //СОЗДАНИЕ СЛУШАТЕЛЯ ДЛЯ ТЕРМИНАЛОВ------------------------------------------------------- Listener = new ListenerTcpIp(xmlListener); ProviderTerminal = new Server2TerminalExchangeDataProvider(isSynchronized: true); ProviderTerminal.PropertyChanged += (o, e) => { var provider = o as Server2TerminalExchangeDataProvider; if (provider != null) { if (e.PropertyName == "InputData") { try { provider.OutputData = provider.OutputData ?? new TerminalOutData(); //Найдем очередь к которой обращен запрос var prefixQueue = provider.InputData.PrefixQueue; var nameQueue = provider.InputData.NameQueue; var queue = QueuePriorities.FirstOrDefault(q => string.Equals(q.Name, nameQueue, StringComparison.InvariantCultureIgnoreCase)); if (queue == null) { return; } switch (provider.InputData.Action) { //ИНФОРМАЦИЯ ОБ ОЧЕРЕДИ case TerminalAction.Info: provider.OutputData.PrefixQueue = provider.InputData.PrefixQueue; provider.OutputData.CountElement = (ushort)queue.GetInseartPlace(prefixQueue); provider.OutputData.NumberElement = (ushort)(queue.GetCurrentTicketNumber + 1); provider.OutputData.AddedTime = DateTime.Now; break; //ДОБАВИТЬ БИЛЕТ В ОЧЕРЕДЬ case TerminalAction.Add: var ticket = queue.CreateTicket(prefixQueue); provider.OutputData.PrefixQueue = provider.InputData.PrefixQueue; provider.OutputData.CountElement = ticket.CountElement; provider.OutputData.NumberElement = (ushort)ticket.NumberElement; provider.OutputData.AddedTime = ticket.AddedTime; queue.Enqueue(ticket); var logMessage = $"ДОБАВИТЬ БИЛЕТ В ОЧЕРЕДЬ (команда от терминала): {ticket.ToString()} "; _logQueueInput.Info(logMessage); break; } } catch (Exception ex) { _logQueueInput.Error($"Server2TerminalExchangeDataProvider: {ex.ToString()}"); } } } }; //DEBUG------ИНИЦИАЛИЗАЦИЯ ОЧЕРЕДИ--------------------- //Обязательно коментировать _model.LoadStates(); иначе состояние очереди затрется //var queueTemp = QueuePriorities.FirstOrDefault(q => string.Equals(q.Name, "Main", StringComparison.InvariantCultureIgnoreCase)); //var queueAdmin = QueuePriorities.FirstOrDefault(q => string.Equals(q.Name, "Admin", StringComparison.InvariantCultureIgnoreCase)); //for (int i = 0; i < 200; i++) //{ // var ticketAdmin = queueTemp.CreateTicket("А"); // queueAdmin.Enqueue(ticketAdmin); // var ticket = queueTemp.CreateTicket("К"); // queueTemp.Enqueue(ticket); // ticket = queueTemp.CreateTicket("К"); // queueTemp.Enqueue(ticket); // ticket = queueTemp.CreateTicket("Г"); // queueTemp.Enqueue(ticket); // ticket = queueTemp.CreateTicket("И"); // queueTemp.Enqueue(ticket); // ticket = queueTemp.CreateTicket("С"); // queueTemp.Enqueue(ticket); //} //DEBUG---------------------------------------------- //СОЗДАНИЕ КАССИРОВ------------------------------------------------------------------------------------------------ foreach (var xmlCash in xmlCashier) { var queue = QueuePriorities.FirstOrDefault(q => q.Name == xmlCash.NameQueue); if (queue != null) { var logName = "Server.CashierInfo_" + xmlCash.Port; var casher = new Сashier(xmlCash.Id, xmlCash.Prefixs, queue, xmlCash.MaxCountTryHanding, logName); DeviceCashiers.Add(new DeviceCashier(xmlCash.AddressDevice, casher, xmlCash.Port)); } } AdminCasher = DeviceCashiers.FirstOrDefault(d => d.Cashier.Prefixes.Contains("А")); //СОЗДАНИЕ ПОСЛЕД. ПОРТА ДЛЯ ОПРОСА КАССИРОВ----------------------------------------------------------------------- var cashersGroup = DeviceCashiers.GroupBy(d => d.Port).ToDictionary(group => group.Key, group => group.ToList()); //принадлежность кассира к порту foreach (var xmlSerial in xmlSerials) { var logName = "Server.CashierInfo_" + xmlSerial.Port; var sp = new MasterSerialPort(xmlSerial, logName); var cashiers = cashersGroup[xmlSerial.Port]; var cashierExch = new CashierExchangeService(cashiers, AdminCasher, xmlSerial.TimeRespoune, logName); sp.AddFunc(cashierExch.ExchangeService); //sp.PropertyChanged += (o, e) => // { // var port = o as MasterSerialPort; // if (port != null) // { // if (e.PropertyName == "StatusString") // { // ErrorString = port.StatusString; //TODO: РАЗДЕЛЯЕМЫЙ РЕСУРС возможно нужна блокировка // } // } // }; MasterSerialPorts.Add(sp); CashierExchangeServices.Add(cashierExch); } }