Exemplo n.º 1
0
        private static bool ProcessArrivedBook(TransportBookInfo book, bool isMyInfo)
        {
            if (book == null || string.IsNullOrWhiteSpace(book.AuthorLink))
            {
                return(true);
            }
            if (Authors == null)
            {
                return(true);
            }
            var author = Authors.FindAuthor(book.AuthorLink);

            if (author == null)
            {
                return(true);
            }
            var alreadyStared = author.IsNew;

            if (author.IsIgnored || author.IsDeleted)
            {
                return(true);
            }
            var authorText = author.Texts.FirstOrDefault(t => t.Link == book.Link);
            // Link  у нас - относительный путь, поэтому не преобразовываем
            bool isNew     = false;
            bool isUpdated = false;

            var convertedTime = new DateTime(book.UpdateDate, DateTimeKind.Utc).ToLocalTime();


            if (isMyInfo)
            {
                if (authorText == null)
                {
                    return(true);
                }
                // просто маркируем свои штампы серверным, не меняя локальные даты проверок
                authorText.ServerStamp = book.UpdateDate;
                author.ServerStamp     = book.UpdateDate;
            }
            else
            {
                if (authorText == null)
                {
                    authorText = new AuthorText();
                    isNew      = true;
                }
                if (authorText.ServerStamp > book.UpdateDate)
                {
                    return(true);
                }

                if (!isNew)
                {
                    book.Size = book.Size < 0 ? 0 : book.Size; // кооректируем, иногда бывает -1
                    isUpdated = ((authorText.Name != book.Name || authorText.Size != book.Size ||
                                  (_setting.SkipBookDescription ? false : authorText.Description != book.Description)));
                }
                if (!isNew && !isUpdated)
                {
                    authorText.ServerStamp = book.UpdateDate;// скорректируем локальное значение. поставим серверное
                    return(true);
                }

                _messageBrokerTrayInfoCollectorTimer.Stop();

                authorText.Description = book.Description;
                authorText.Genres      = book.Genres;
                authorText.Link        = book.Link;
                authorText.Name        = book.Name;
                authorText.SectionName = book.SectionName;

                if (!authorText.IsNew)
                {
                    authorText.SizeOld = authorText.Size;
                }

                authorText.Size        = book.Size;
                authorText.UpdateDate  = convertedTime;
                authorText.ServerStamp = book.UpdateDate; // ставим штамп сервера

                authorText.IsNew = true;
                if (isNew)
                {
                    author.Texts.Add(authorText);
                }
                author.LastCheckDate = authorText.UpdateDate;
                try
                {
                    if (author.NextCheckDate < author.LastCheckDate)
                    {
                        var elasticScheduler = new ElasticScheduler(_logger, _setting);
                        elasticScheduler.MakePlan(author);
                        elasticScheduler.SaveStatistics();
                    }
                    author.UpdateDate  = authorText.UpdateDate;
                    author.ServerStamp = book.UpdateDate; // ставим штамп сервера

                    author.IsNew = true;

                    _logger.Add(string.Format("StatServer> Уведомление: обновился {0} ({1})", author.Name, authorText.Name),
                                true, false);
                    if (!_messageBrokerTrayInfo.Contains(author.Name) && !alreadyStared)
                    {
                        _messageBrokerTrayInfo = string.IsNullOrWhiteSpace(_messageBrokerTrayInfo)
                                                     ? author.Name
                                                     : _messageBrokerTrayInfo + "; " + author.Name;
                    }
                    _messageBrokerTrayInfoCollectorTimer.Start();
                }
                catch (Exception ex)
                {
                    _logger.Add(string.Format("Ошибка формирования плана проверок автора {0} - {1}", author.Name, ex));
                }
            }
            return(false);
        }
Exemplo n.º 2
0
        private static void RecursiveAsyncUpdateAuthorFromStatServer(int counter, List <Author> authors, Action completed)
        {
            if (counter == authors.Count)
            {
                completed();
                return;
            }
            var author = authors[counter++];

            _logger.Add(string.Format("StatServer {0}> Проверяется автор {1}...", DateTime.Now.ToShortTimeString(), author.Name));
            ApiStuff.ApiManager.GetInstance().GetAuthorUpdatesInfo(_logger, _setting, author.URL, author.ServerStamp,
                                                                   (serverStamp, transportBooks) =>
            {
                var booksArrived = 0;
                if (transportBooks != null && transportBooks.Count > 0)
                {
                    foreach (var transportBook in transportBooks)
                    {
                        ProcessArrivedBook(transportBook, false);
                        booksArrived++;
                    }
                    _messageBrokerTrayInfoCollectorTimer.Start();
                }
                // если обнов нет, а штамп сервера больше, то есть уже ктото проверил автора, маркируем локального автора, что проверен и высчитываем для него новую дату проверки
                if (serverStamp > author.ServerStamp)
                {
                    var convertedTime    = new DateTime(serverStamp, DateTimeKind.Utc).ToLocalTime();
                    author.LastCheckDate = convertedTime;
                    try
                    {
                        var elasticScheduler = new ElasticScheduler(_logger, _setting);
                        elasticScheduler.MakePlan(author);
                        elasticScheduler.SaveStatistics();
                        if (author.NextCheckDate < DateTime.Now)
                        {
                            _logger.Add(string.Format(
                                            "StatServer {3}> Автор {0} уже проверен {1}. Получено {2} обновлений книг, однако требуется обращение на оригинальный сайт автора для уточнения информации",
                                            author.Name, author.LastCheckDate, booksArrived, DateTime.Now.ToShortTimeString()), false);
                        }
                        else
                        {
                            _logger.Add(string.Format(
                                            "StatServer {4}> Автор {0} уже проверен {1}. Получено {2} обновлений книг. Следующее время нашей проверки:{3}",
                                            author.Name, author.LastCheckDate, booksArrived, author.NextCheckDate, DateTime.Now.ToShortTimeString()), false);
                        }

                        author.ServerStamp = serverStamp;             // ставим штамп сервера
                    }
                    catch (Exception ex)
                    {
                        _logger.Add(string.Format("Ошибка формирования плана проверок автора {0} - {1}",
                                                  author.Name, ex));
                    }
                }
                else
                {
                    _logger.Add(string.Format("StatServer {1}> Автора {0} никто не проверял. Будет произведено обращение на оригинальный сайт автора", author.Name, DateTime.Now.ToShortTimeString()), false);
                }
                if (_logger.Working)
                {
                    RecursiveAsyncUpdateAuthorFromStatServer(counter, authors, completed);        // запускаем проверку следующего автора. если авторы закончились - упраление вернется в completed()
                }
            },
                                                                   (error) =>
            {
                _logger.Add(error, true);
                RecursiveAsyncUpdateAuthorFromStatServer(counter, authors, completed);             // запускаем проверку следующего автора. если авторы закончились - упраление вернется в completed()
            }
                                                                   );
        }
Exemplo n.º 3
0
        private void WorkerDoWork(object sender, DoWorkEventArgs e)
        {
            var elasticScheduler = new ElasticScheduler(_logger, _setting);
            var list             = (List <Author>)e.Argument;

            int index      = 1;
            int authorsCnt = list.Count;

            foreach (Author author in list)
            {
                if (_worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                SyncRun(Action.IsUpdaterTrue, author);
                try
                {
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message =
                            string.Format("{1}/{2}: '{0}' проверяется с родного сайта", author.Name, index, list.Count),
                        ToMessage = true,
                        IsError   = false
                    });
                    string page = author.GetAuthorPage();
                    if (page != null)
                    {
                        author.DaysInaccessible = 0;// скидываем накопительный счетчик дней недоступности, так как страничка доступна стала.
                        SyncRun(Action.UpdateAuthorText, new UpdateTextParam(author, page, index, list.Count));
                    }
                    else
                    {
                        // проанализируем недоступность во времени
                        var dayDate = new DateTime(author.LastCheckDate.Year, author.LastCheckDate.Month,
                                                   author.LastCheckDate.Day);
                        if (dayDate < DateTime.Today)                              // если последний раз проверял не сегодня и сегодня недоступен, увеличиваем маркер недоступности. То есть если сегодня уже был недоступен, то этот факт игнорируем. Таким образом мы раз в сутки учитываем недоступность
                        {
                            author.DaysInaccessible = author.DaysInaccessible + 1; // увеличиваем счетчик недоступности дней, там автор сам уйдет в игнор, если счетчик превысит константу _maxDaysInaccessibility
                        }
                        SyncRun(Action.SetStatus,
                                new SetStatusParam
                        {
                            Message   = string.Format("Недоступна страница '{0}'. {1}", author.Name, author.IsIgnored ? "Автор отключен от проверок из-за превышения кол-ва дней недоступности." : ""),
                            ToMessage = true,
                            IsError   = true
                        });
                    }
                }
                catch (Exception ex)
                {
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message   = ex.StackTrace,
                        ToMessage = false,
                        IsError   = true
                    });
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message   = ex.Message,
                        ToMessage = true,
                        IsError   = true
                    });
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message =
                            string.Format("{1}/{2}: '{0}' не проверен. Ошибка.", author.Name, index,
                                          list.Count),
                        ToMessage = true,
                        IsError   = true
                    });
                }

                SyncRun(Action.IsUpdaterFalse, author);

                // пропишем дату последней проверки автора. Необходимо для рассчета следующего времени проверки
                author.LastCheckDate = DateTime.Now;
                // перерасчитаем следующее время проверки автора
                try
                {
                    elasticScheduler.MakePlan(author);
                }
                catch (Exception ex)
                {
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message =
                            string.Format("Ошибка формирования плана проверок автора {0} - {1}",
                                          author.Name, ex),
                        ToMessage = true,
                        IsError   = true
                    });
                }

                index++;
                // задержка, если проверка больше одного автора
                if (authorsCnt > 1)
                {
                    var period   = _setting.IntervalOfUpdate * 3600; // весь период обновлений
                    var rnd      = new Random();
                    var waitSpan = period / authorsCnt;
                    if (App.BalanceInterval > 0)
                    {
                        waitSpan = App.BalanceInterval;
                    }
                    else
                    {
                        waitSpan = waitSpan < 10 ? rnd.Next(10, 15) : waitSpan;
                        waitSpan = waitSpan > 15 ? 15 : waitSpan;
                    }
                    while (waitSpan > 0)
                    {
                        SyncRun(Action.SetStatus,
                                new SetStatusParam
                        {
                            Message =
                                string.Format("->Балансировка нагрузки: ожидание {0} секунд(ы)...", waitSpan),
                            ToMessage = true,
                            IsError   = false
                        });
                        if (_worker.CancellationPending)
                        {
                            e.Cancel = true;
                            return;
                        }
                        Thread.Sleep(1000);
                        waitSpan--;
                    }
                }
            }
            // вызываем метод сохранения статистики. Однако внутри него он ориентируется на настройку "Сохранять статистику"
            try
            {
                elasticScheduler.SaveStatistics();
            }
            catch (Exception ex)
            {
                SyncRun(Action.SetStatus,
                        new SetStatusParam
                {
                    Message =
                        string.Format("Ошибка сохранение статистики. {0}", ex),
                    ToMessage = true,
                    IsError   = true
                });
            }
            var cachedAuthors     = new List <Author>();
            var cachedAuthorTexts = new List <AuthorText>();

            foreach (Author author in list)
            {
                foreach (AuthorText authorText in author.Texts)
                {
                    if (string.IsNullOrWhiteSpace(authorText.Name))
                    {
                        continue;
                    }
                    authorText.UpdateIsCached(author);
                    if ((authorText.IsNew) && (!authorText.IsCached))
                    {
                        if ((authorText.Cached == true) || ((authorText.Cached == null) && (author.Cached == true)) ||
                            ((authorText.Cached == null) && ((author.Cached == null) && _setting.Cached)))
                        {
                            cachedAuthors.Add(author);
                            cachedAuthorTexts.Add(authorText);
                        }
                    }
                }
            }
            if (cachedAuthors.Count > 0)
            {
                SyncRun(Action.SetStatus,
                        new SetStatusParam
                {
                    Message   = string.Format("Кешируется {0} книг", cachedAuthors.Count),
                    ToMessage = true,
                    IsError   = false
                });
                for (int i = 0; i < cachedAuthors.Count; i++)
                {
                    SyncRun(Action.SetStatus,
                            new SetStatusParam
                    {
                        Message =
                            string.Format("{1}/{2}: Кешируется '{0}'", cachedAuthorTexts[i].Name, i + 1,
                                          cachedAuthors.Count),
                        ToMessage = true,
                        IsError   = false
                    });
                    var cachedParam = new CachedParam
                    {
                        Author = cachedAuthors[i], AuthorText = cachedAuthorTexts[i]
                    };
                    SyncRun(Action.CachedAdd, cachedParam);
                    cachedParam.DownloadTextItem.DownloadTextComplete += ItemDownloadTextComplete;

                    _manualEvent = new ManualResetEvent(false);
                    // таймаут на закачку книги исходя из скорости 28 кбит/сек с учетом размера книги
                    int  timeout = Math.Max(60 * 1000, cachedAuthorTexts[i].Size * 60 * 1000 / 210);
                    bool result  = _manualEvent.WaitOne(timeout);
                    cachedParam.DownloadTextItem.DownloadTextComplete -= ItemDownloadTextComplete;
                    if (!result)
                    {
                        SyncRun(Action.SetStatus,
                                new SetStatusParam
                        {
                            Message =
                                string.Format("{1}/{2}: Закачка книги '{0}' прервана по таймауту",
                                              cachedAuthorTexts[i].Name, i + 1,
                                              cachedAuthors.Count),
                            ToMessage = true,
                            IsError   = true
                        });
                        SyncRun(Action.CachedRemove, cachedParam);
                    }
                }
            }
        }