예제 #1
0
        /// <summary>
        /// Получение и чтение книг клиентом без обработки общих исключений
        /// </summary>
        private void TryGettingAndReadingBook()
        {
            int MilisecondOfSecond = 1000;

            ReadingActiveBook();
            while (true)
            {
                if (ClientServer.QueueBook.Count == 0)
                {
                    WaitHandler.Reset();
                    WaitHandler.WaitOne();
                }

                MutexJointOperation.WaitOne();
                string   bookJSON              = ClientServer.QueueBook.Dequeue();
                BookSDB  book                  = JsonSerializer.Deserialize <BookSDB>(bookJSON);
                double   timeSleep             = ServerDB.TimeReadingBook(ClientServer, book, DateTime.UtcNow.ToLocalTime());
                DateTime timeComleteReadActive = DateTime.UtcNow.ToLocalTime().AddSeconds(timeSleep);
                SendBookClient(bookJSON, timeComleteReadActive);
                MutexJointOperation.ReleaseMutex();

                Thread.Sleep((int)timeSleep * MilisecondOfSecond);
                MySqlConnection.ImplementationBook(ClientServer.Address, DateTime.UtcNow.ToLocalTime());
            }
        }
        /// <summary>
        /// Распределение книги из RabbitMQ без обработки общих исключений
        /// </summary>
        /// <param name="sender">Вызывающий объект</param>
        /// <param name="e">Сообщение из RabbitMQ</param>
        private void TryDistributionBookRequest(object sender, BasicDeliverEventArgs e)
        {
            MutexOnlyMethod.WaitOne();
            BookSDB  book = WorkRabbit.ConvertMessageRabbit <BookSDB>(e.Body);
            DateTime timeRead;
            string   clientAddress = WorkClientGroup.SearchFastReader(book, out timeRead);

            if (clientAddress == null)
            {
                WorkRabbit.PublishUnallocatedQueue(e);
                WorkRabbit.BasicAckRabbit(sender, e);
            }
            else
            {
                string bookJSON = WorkRabbit.ConvertMessageRabbit <string>(e.Body);
                AddBookServer(clientAddress, bookJSON, timeRead);
                try
                {
                    WorkRabbit.BasicAckRabbit(sender, e);
                }
                catch (RabbitmqException)
                {
                    WorkMongo.DeleteLastBook(clientAddress);
                    StopServer();
                }
                WorkClientGroup.InformSendingBook(clientAddress);
            }
            MutexOnlyMethod.ReleaseMutex();
        }
예제 #3
0
        /// <summary>
        /// Поиск клиента, прочитающего книгу быстрее всех
        /// </summary>
        /// <param name="book">Книга</param>
        /// <param name="timeRead">Дата-время прочтения книги</param>
        /// <returns>Электронный адресс клиента</returns>
        public string SearchFastReader(BookSDB book, out DateTime timeRead)
        {
            string   clientAddress = null;
            DateTime timeReadEnd   = new DateTime();                    //промежуточное время окончания чтения книги
            DateTime timeReadNow   = new DateTime();                    //время начала чтения книги

            timeRead = new DateTime();                                  //время окончания чтения книги
            bool first = true;

            var selectedClients = from client in ClientDictionary
                                  from lela in client.Value.GetClientServerDB().LevelLanguages
                                  where lela.Language == book.Language
                                  select client.Value.GetClientServerDB();

            foreach (var clientServer in selectedClients)
            {
                DateTime nowTime = DateTime.UtcNow.ToLocalTime();
                timeReadNow = clientServer.TimeRead > nowTime ?
                              clientServer.TimeRead : nowTime;

                timeReadEnd = timeReadNow.AddSeconds(ServerDB.TimeReadingBook(clientServer, book, timeReadNow));
                if (first || timeReadEnd < timeRead)
                {
                    if (first)
                    {
                        first = false;
                    }
                    clientAddress = clientServer.Address;
                    timeRead      = timeReadEnd;
                }
            }
            return(clientAddress);
        }
예제 #4
0
        /// <summary>
        /// Добавление книги
        /// </summary>
        /// <param name="address">Электронный адресс клиента</param>
        /// <param name="bookJSON">Книга в JSON</param>
        /// <param name="dataGetting">Дата-время получения книги</param>
        public void AddBook(string address, string bookJSON, DateTime dataGetting)
        {
            BookSDB bookObject = JsonSerializer.Deserialize <BookSDB>(bookJSON);
            string  sqlCommand = "INSERT INTO books (AddressClient, Language, Name, Pages, DataGetting) " +
                                 "VALUES(@AddressClient, @Language, @Name, @Pages, @DataGetting); ";

            try
            {
                ConnectionMySQL.Open();
                MySqlCommand command = new MySqlCommand(sqlCommand, ConnectionMySQL);
                command.Parameters.AddWithValue("@AddressClient", address);
                command.Parameters.AddWithValue("@Language", (int)bookObject.Language);
                command.Parameters.AddWithValue("@Name", bookObject.Name);
                command.Parameters.AddWithValue("@Pages", bookObject.Pages);
                command.Parameters.AddWithValue("@DataGetting", dataGetting);
                command.ExecuteNonQuery();
            }
            catch (Exception exception)
            {
                Log.Error(exception.ToString);
                StopApplication();
            }
            finally
            {
                ConnectionMySQL.Close();
            }
        }
예제 #5
0
        /// <summary>
        /// Перерасчет даты-времени освобождения клиента от чтения
        /// </summary>
        /// <param name="clientServer">Клиент сервера</param>
        /// <returns>Даты-время освобождения клиента от чтения</returns>
        public DateTime RecalculateTimeRead(string address)
        {
            ClientServerDB clientServer          = ClientDictionary[address].GetClientServerDB();
            int            queueBookCount        = clientServer.QueueBook.Count;
            DateTime       nowTime               = DateTime.UtcNow.ToLocalTime();
            DateTime       timeReadRecalculation = clientServer.TimeReadActive < nowTime ? nowTime : clientServer.TimeReadActive;

            for (int i = 0; i < queueBookCount; i++)
            {
                string bookJSON = clientServer.QueueBook.Dequeue();
                clientServer.QueueBook.Enqueue(bookJSON);
                BookSDB book      = JsonSerializer.Deserialize <BookSDB>(bookJSON);
                double  timeSleep = ServerDB.TimeReadingBook(clientServer, book, timeReadRecalculation);
                timeReadRecalculation = timeReadRecalculation.AddSeconds(timeSleep);
            }
            return(timeReadRecalculation);
        }
        /// <summary>
        /// Расчет времени чтения книги
        /// </summary>
        /// <param name="clientServer">Клиент сервера</param>
        /// <param name="book">Книги</param>
        /// <param name="dataTime">Дата-время, относительно которого производится расчет</param>
        /// <returns>Время чтения книги (в секундах)</returns>
        public double TimeReadingBook(ClientServerDB clientServer, BookSDB book, DateTime dataTime)
        {
            double timeReadingBook;                                                                         //время чтения книги
            int    level = 0;                                                                               //уровень владения языком

            foreach (LevelLanguageSDB lela in clientServer.LevelLanguages)
            {
                if (lela.Language == book.Language)
                {
                    level = lela.Level;
                    break;
                }
            }
            if (level == 0)
            {
                throw new Exception($"Клиент не владеет языком {book.Language}");
            }
            TimeSpan interval = dataTime - clientServer.DataRegistration;                                                     //интервал времени от данного до времени регистрации
            int      readingIntervalActiveSecond  = clientServer.ReadingIntervalActive * DaysSecond;                          //время активного чтения в цикле
            int      readingIntervalPassiveSecond = clientServer.ReadingIntervalPassive * DaysSecond;                         //время пассивного чтения чтения в цикле
            int      cycleReading           = readingIntervalActiveSecond + readingIntervalPassiveSecond;                     //время цикла чтения
            double   levelPagesPerCycle     = clientServer.ReadingIntervalActive * clientServer.PagesPerDay * (level / 10.0); //количество читаемых страниц в цикл
            double   balanseInterval        = interval.TotalSeconds % (double)cycleReading;                                   //текущее время нового цикла
            double   remainingActiveCycle   = readingIntervalActiveSecond - balanseInterval;                                  //оставшееся время цикла активного чтения
            double   timeReadingBookNCCycle = (double)(book.Pages % levelPagesPerCycle) / (double)levelPagesPerCycle          //время чтения неполного цикла
                                              * (double)readingIntervalActiveSecond;
            int TimeReadingBookFullCycle = (int)(book.Pages / levelPagesPerCycle) * cycleReading;                             //время чтения полных циклов

            if (balanseInterval >= readingIntervalActiveSecond)
            {
                timeReadingBook = TimeReadingBookFullCycle + timeReadingBookNCCycle + (cycleReading - balanseInterval);
            }
            else
            {
                if (remainingActiveCycle > timeReadingBookNCCycle)
                {
                    timeReadingBook = TimeReadingBookFullCycle + timeReadingBookNCCycle;
                }
                else
                {
                    timeReadingBook = TimeReadingBookFullCycle + timeReadingBookNCCycle + readingIntervalPassiveSecond;
                }
            }
            return(timeReadingBook);
        }
        /// <summary>
        /// Перезагрузка объектов клиентов
        /// </summary>
        /// <param name="conn">Соединение с RabbitMQ</param>
        /// <param name="collection">Коллекция MongoDB</param>
        /// <param name="connectionString">Строка подключения MySQL</param>
        private static void ObjectOverload(IConnection conn, IMongoCollection <ClientServerDB> collection, string connectionString)
        {
            //извлечение всех объектов из MongoDB
            var filter = new BsonDocument();
            var people = collection.Find(filter).ToList();

            foreach (ClientServerDB clientServerDB in people)
            {
                //количество книг в очереди
                int queueBookCount = clientServerDB.queueBook.Count;
                //расчет начала чтения книг из очереди
                DateTime timeReadIntermediate = clientServerDB.TimeReadActive;
                if (timeReadIntermediate < DateTime.Now)
                {
                    timeReadIntermediate = DateTime.Now;
                }
                //перерасчет даты освобождения от чтения
                for (int i = 0; i < queueBookCount; i++)
                {
                    string book = clientServerDB.queueBook.Dequeue();
                    clientServerDB.queueBook.Enqueue(book);
                    BookSDB bookSDB   = JsonSerializer.Deserialize <BookSDB>(book);
                    double  timeSleep = clientServerDB.TimeReadingBook(bookSDB.Language, bookSDB.Pages, timeReadIntermediate);
                    timeReadIntermediate = timeReadIntermediate.AddSeconds(timeSleep);
                }
                clientServerDB.InitComponentReload(conn, collection, connectionString, timeReadIntermediate);

                //запись даты освобождения от чтения в MongoDB
                var filterDB = Builders <ClientServerDB> .Filter.Eq("Address", clientServerDB.Address);

                var updateTimeRead = Builders <ClientServerDB> .Update.Set(x => x.TimeRead, clientServerDB.TimeRead.AddHours(3));

                collection.UpdateOne(filterDB, updateTimeRead);

                //добавления объекта в список и запуск потока получения и чтения книг
                listClient.Add(clientServerDB.Address, clientServerDB);
                clientServerDB.readingBook.Start();
            }
        }
 /// <summary>
 /// Отправка книги по электронной почте
 /// </summary>
 /// <param name="address">wmail адресс</param>
 /// <param name="bookSDB">книга</param>
 private void SendEmail(string address, BookSDB bookSDB)
 {
 }
        /// <summary>
        /// Метод получения и чтения книг
        /// </summary>
        public void ReadingBook()
        {
            //проверка на перезагрузку объекта и ожидание прочтения текущей книги при необходимости
            if (ReloadObject)
            {
                ReloadObject = false;
                DateTime DTNow;
                if (TimeReadActive > DateTime.Now)
                {
                    TimeSpan timeSleepActive = TimeReadActive - DateTime.Now;
                    Thread.Sleep(timeSleepActive);
                    DTNow = DateTime.Now;
                }
                else
                {
                    DTNow = TimeReadActive;
                }
                //занесение даты прочтения книги в MySQL
                string sqlExpressionReload = "UPDATE books SET DataReading = @DTNow WHERE AddressClient = @AddressClient AND DataReading IS NULL";
                using (MySqlConnection ConnMySQL = new MySqlConnection(ConnectionString))
                {
                    ConnMySQL.Open();
                    MySqlCommand   commandReload          = new MySqlCommand(sqlExpressionReload, ConnMySQL);
                    MySqlParameter AddressClientBookParam = new MySqlParameter("@AddressClient", Address);
                    commandReload.Parameters.Add(AddressClientBookParam);
                    MySqlParameter DataReadingBookParam = new MySqlParameter("@DTNow", DTNow);
                    commandReload.Parameters.Add(DataReadingBookParam);
                    commandReload.ExecuteNonQuery();
                }
            }
            while (true)
            {
                if (queueBook.Count != 0)
                {
                    mutexSend.WaitOne();
                    //получение книги из очереди и дессериализация
                    string  book    = queueBook.Dequeue();
                    BookSDB bookSDB = JsonSerializer.Deserialize <BookSDB>(book);
                    //подсчет времени ожидания и даты окончания чтения книги
                    double   timeSleep      = TimeReadingBook(bookSDB.Language, bookSDB.Pages, DateTime.Now);
                    DateTime timeReadActive = DateTime.Now.AddSeconds(timeSleep);
                    SendEmail(Address, bookSDB);

                    //Занесение книги в MySQL
                    DateTime DataGetting   = DateTime.Now;
                    string   sqlExpression = "insert_book";
                    object   idBook;
                    using (MySqlConnection ConnMySQL = new MySqlConnection(ConnectionString))
                    {
                        ConnMySQL.Open();
                        MySqlCommand command = new MySqlCommand(sqlExpression, ConnMySQL);
                        command.CommandType = CommandType.StoredProcedure;
                        MySqlParameter AddressClientParam = new MySqlParameter("@AddressClientP", Address);
                        command.Parameters.Add(AddressClientParam);
                        MySqlParameter LanguageParam = new MySqlParameter("@LanguageP", (int)bookSDB.Language);
                        command.Parameters.Add(LanguageParam);
                        MySqlParameter NameParam = new MySqlParameter("@NameP", bookSDB.Name);
                        command.Parameters.Add(NameParam);
                        MySqlParameter PagesParam = new MySqlParameter("@PagesP", bookSDB.Pages);
                        command.Parameters.Add(PagesParam);
                        MySqlParameter DataGettingParam = new MySqlParameter("@DataGettingP", DataGetting);
                        command.Parameters.Add(DataGettingParam);
                        idBook = command.ExecuteScalar();
                    }

                    //занесение книги в MongoDB
                    var filter = Builders <ClientServerDB> .Filter.Eq("Address", Address);

                    var updateTimeReadActive = Builders <ClientServerDB> .Update.Set(x => x.TimeReadActive, timeReadActive.AddHours(3));

                    CollectionMongo.UpdateOne(filter, updateTimeReadActive);
                    var updateBook = Builders <ClientServerDB> .Update.Pull(x => x.queueBook, book);

                    CollectionMongo.UpdateOne(filter, updateBook);

                    mutexSend.ReleaseMutex();
                    //чтение книги
                    Thread.Sleep((int)timeSleep * 1000);
                    //занесение даты прочтения книги в MySQL
                    DateTime DataReading = DateTime.Now;
                    using (MySqlConnection ConnMySQL = new MySqlConnection(ConnectionString))
                    {
                        ConnMySQL.Open();
                        MySqlCommand commandReading = new MySqlCommand();
                        commandReading.Connection  = ConnMySQL;
                        commandReading.CommandText = "UPDATE books SET DataReading = @DataReading WHERE Id = @Id";
                        MySqlParameter DataReadingParam = new MySqlParameter("@DataReading", DataReading);
                        commandReading.Parameters.Add(DataReadingParam);
                        MySqlParameter idParam = new MySqlParameter("@Id", idBook);
                        commandReading.Parameters.Add(idParam);
                        commandReading.ExecuteNonQuery();
                    }
                }
                else
                {
                    break;
                }
            }
        }
        /// <summary>
        /// Распределение книг
        /// </summary>
        /// <param name="e">Объект сообщения</param>
        /// <param name="channel">Канал связи с rabbitmq</param>
        /// <param name="collection">Коллекция MongoDB</param>
        private static void DistributionBook(BasicDeliverEventArgs e, IModel channel, IMongoCollection <ClientServerDB> collection)
        {
            mutexDAD.WaitOne();
            //получение и дессериализация книги
            var     body    = e.Body;
            var     message = Encoding.UTF8.GetString(body);
            BookSDB book    = JsonSerializer.Deserialize <BookSDB>(message);

            ClientServerDB clientSDB    = null;
            DateTime       timeRead     = new DateTime();           //промежуточное время окончания чтения книги
            DateTime       timeReadMain = new DateTime();           //время оканчания чтения книги
            DateTime       timeReadNow  = new DateTime();           //время начала чтения книги
            bool           first        = true;

            foreach (var client in listClient)
            {
                foreach (LevelLanguageSDB lela in client.Value.LevelLanguages)
                {
                    //проверка клиента на знание языка
                    if (book.Language == lela.Language)
                    {
                        //определение времени начала чтения книги
                        if (client.Value.TimeRead > DateTime.Now)
                        {
                            timeReadNow = client.Value.TimeRead;
                        }
                        else
                        {
                            timeReadNow = DateTime.Now;
                        }

                        //промежуточное определение времени окончания чтения книги
                        timeRead = timeReadNow.AddSeconds(client.Value.TimeReadingBook(book.Language, book.Pages, timeReadNow));
                        if (first || timeRead < timeReadMain)
                        {
                            //если клиент прочитает книгу быстрее предыдущего клиента, он становится активным клиентом
                            if (first)
                            {
                                first = false;
                            }
                            clientSDB    = client.Value;
                            timeReadMain = timeRead;
                        }
                    }
                }
            }
            //если подходящих клиентов не найденоб отправка книги в очередь не распределенных книг
            if (clientSDB == null)
            {
                channel.BasicPublish("ServerDB", "UnallocatedBook", null, e.Body);
                Console.WriteLine("UnallocatedBook" + " " + message);
            }
            else
            {
                //изменение времени оканчания чтения клиента и добавление книги ему в очередь
                clientSDB.TimeRead = timeReadMain;
                clientSDB.queueBook.Enqueue(message);

                //изменение времени оканчания чтения клиента и добавление книги в MongoDB
                var filter = Builders <ClientServerDB> .Filter.Eq("Address", clientSDB.Address);

                var updateTimeRead = Builders <ClientServerDB> .Update.Set(x => x.TimeRead, clientSDB.TimeRead.AddHours(3));

                collection.UpdateOne(filter, updateTimeRead);
                var updateBook = Builders <ClientServerDB> .Update.AddToSet(x => x.queueBook, message);

                collection.UpdateOne(filter, updateBook);

                //если клиент в данный момент не читает и у него в очереди нет книг, запуск потока получения и чтения книг
                if (clientSDB.readingBook.ThreadState == ThreadState.Unstarted || clientSDB.readingBook.ThreadState == ThreadState.Stopped)
                {
                    if (clientSDB.readingBook.ThreadState == ThreadState.Stopped)
                    {
                        clientSDB.readingBook = new Thread(new ThreadStart(clientSDB.ReadingBook));
                    }
                    clientSDB.readingBook.Start();
                }

                Console.WriteLine(clientSDB.Address + " " + message + clientSDB.TimeRead);
            }
            channel.BasicAck(e.DeliveryTag, false);
            mutexDAD.ReleaseMutex();
        }