.
This commit is contained in:
@@ -4,6 +4,7 @@ import kz.konturai.parser.dto.ApiResponse;
|
||||
import kz.konturai.parser.dto.HealthCheckDto;
|
||||
import kz.konturai.parser.service.MarketItemService;
|
||||
import kz.konturai.parser.service.ParserManagerService;
|
||||
import kz.konturai.parser.util.RssUrlValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -26,6 +27,9 @@ public class HealthCheckController {
|
||||
@Autowired
|
||||
private ParserManagerService parserManagerService;
|
||||
|
||||
@Autowired
|
||||
private RssUrlValidator rssUrlValidator;
|
||||
|
||||
/**
|
||||
* Проверка состояния парсера
|
||||
*/
|
||||
@@ -150,4 +154,50 @@ public class HealthCheckController {
|
||||
.body(ApiResponse.error("Ошибка при проверке парсеров: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка доступности RSS-лент
|
||||
*/
|
||||
@GetMapping("/rss")
|
||||
public ResponseEntity<ApiResponse<java.util.Map<String, Object>>> checkRssFeeds() {
|
||||
try {
|
||||
// Получаем текущие URL из конфигурации
|
||||
java.util.Map<String, String> rssUrls = new java.util.HashMap<>();
|
||||
rssUrls.put("kursiv", "https://kursiv.media/feed/");
|
||||
rssUrls.put("kapital", "https://kapital.kz/rss/");
|
||||
rssUrls.put("lsm", "https://lsm.kz/rss");
|
||||
rssUrls.put("rbc", "https://static.feed.rbc.ru/rbc/logical/footer/news.rss");
|
||||
rssUrls.put("vedomosti", "https://www.vedomosti.ru/rss/rubric/technology/internet");
|
||||
|
||||
// Проверяем доступность
|
||||
java.util.Map<String, Boolean> accessibilityResults = rssUrlValidator.checkAllRssUrls(rssUrls);
|
||||
|
||||
// Формируем детальный отчет
|
||||
java.util.Map<String, Object> report = new java.util.HashMap<>();
|
||||
report.put("overallStatus",
|
||||
accessibilityResults.values().stream().allMatch(Boolean::booleanValue) ? "UP" : "DEGRADED");
|
||||
report.put("accessibilityResults", accessibilityResults);
|
||||
report.put("totalFeeds", rssUrls.size());
|
||||
report.put("accessibleFeeds", accessibilityResults.values().stream().mapToInt(b -> b ? 1 : 0).sum());
|
||||
report.put("unaccessibleFeeds", accessibilityResults.values().stream().mapToInt(b -> b ? 0 : 1).sum());
|
||||
|
||||
// Добавляем рекомендации по альтернативным URL
|
||||
java.util.Map<String, String> recommendations = new java.util.HashMap<>();
|
||||
for (String source : rssUrls.keySet()) {
|
||||
if (!accessibilityResults.getOrDefault(source, false)) {
|
||||
String alternativeUrl = rssUrlValidator.findWorkingUrl(source);
|
||||
if (alternativeUrl != null) {
|
||||
recommendations.put(source, alternativeUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
report.put("recommendations", recommendations);
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success("Проверка RSS-лент завершена", report));
|
||||
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.internalServerError()
|
||||
.body(ApiResponse.error("Ошибка при проверке RSS-лент: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,10 +102,31 @@ public class KapitalParserService implements ParserService {
|
||||
* Получение RSS-ленты
|
||||
*/
|
||||
private SyndFeed getRssFeed() throws Exception {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
try (XmlReader reader = new XmlReader(feedUrl.openStream())) {
|
||||
return input.build(reader);
|
||||
try {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
// Добавляем таймаут и обработку ошибок
|
||||
java.net.URLConnection connection = feedUrl.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10 секунд
|
||||
connection.setReadTimeout(30000); // 30 секунд
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
try (XmlReader reader = new XmlReader(connection.getInputStream())) {
|
||||
return input.build(reader);
|
||||
}
|
||||
} catch (com.rometools.rome.io.ParsingFeedException e) {
|
||||
logger.error("Ошибка парсинга XML для Kapital.kz: {}", e.getMessage());
|
||||
throw new Exception("Невалидный XML в RSS-ленте Kapital.kz: " + e.getMessage(), e);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
logger.error("Не удается подключиться к серверу Kapital.kz: {}", e.getMessage());
|
||||
throw new Exception("Сервер Kapital.kz недоступен: " + e.getMessage(), e);
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
logger.error("Таймаут при подключении к Kapital.kz: {}", e.getMessage());
|
||||
throw new Exception("Таймаут подключения к Kapital.kz: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Общая ошибка при получении RSS-ленты Kapital.kz: {}", e.getMessage());
|
||||
throw new Exception("Ошибка получения RSS-ленты Kapital.kz: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +102,31 @@ public class KursivParserService implements ParserService {
|
||||
* Получение RSS-ленты
|
||||
*/
|
||||
private SyndFeed getRssFeed() throws Exception {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
try (XmlReader reader = new XmlReader(feedUrl.openStream())) {
|
||||
return input.build(reader);
|
||||
try {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
// Добавляем таймаут и обработку ошибок
|
||||
java.net.URLConnection connection = feedUrl.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10 секунд
|
||||
connection.setReadTimeout(30000); // 30 секунд
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
try (XmlReader reader = new XmlReader(connection.getInputStream())) {
|
||||
return input.build(reader);
|
||||
}
|
||||
} catch (com.rometools.rome.io.ParsingFeedException e) {
|
||||
logger.error("Ошибка парсинга XML для Kursiv: {}", e.getMessage());
|
||||
throw new Exception("Невалидный XML в RSS-ленте Kursiv: " + e.getMessage(), e);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
logger.error("Не удается подключиться к серверу Kursiv: {}", e.getMessage());
|
||||
throw new Exception("Сервер Kursiv недоступен: " + e.getMessage(), e);
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
logger.error("Таймаут при подключении к Kursiv: {}", e.getMessage());
|
||||
throw new Exception("Таймаут подключения к Kursiv: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Общая ошибка при получении RSS-ленты Kursiv: {}", e.getMessage());
|
||||
throw new Exception("Ошибка получения RSS-ленты Kursiv: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +102,31 @@ public class LsmParserService implements ParserService {
|
||||
* Получение RSS-ленты
|
||||
*/
|
||||
private SyndFeed getRssFeed() throws Exception {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
try (XmlReader reader = new XmlReader(feedUrl.openStream())) {
|
||||
return input.build(reader);
|
||||
try {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
// Добавляем таймаут и обработку ошибок
|
||||
java.net.URLConnection connection = feedUrl.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10 секунд
|
||||
connection.setReadTimeout(30000); // 30 секунд
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
try (XmlReader reader = new XmlReader(connection.getInputStream())) {
|
||||
return input.build(reader);
|
||||
}
|
||||
} catch (com.rometools.rome.io.ParsingFeedException e) {
|
||||
logger.error("Ошибка парсинга XML для LSM.kz: {}", e.getMessage());
|
||||
throw new Exception("Невалидный XML в RSS-ленте LSM.kz: " + e.getMessage(), e);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
logger.error("Не удается подключиться к серверу LSM.kz: {}", e.getMessage());
|
||||
throw new Exception("Сервер LSM.kz недоступен: " + e.getMessage(), e);
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
logger.error("Таймаут при подключении к LSM.kz: {}", e.getMessage());
|
||||
throw new Exception("Таймаут подключения к LSM.kz: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Общая ошибка при получении RSS-ленты LSM.kz: {}", e.getMessage());
|
||||
throw new Exception("Ошибка получения RSS-ленты LSM.kz: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +102,31 @@ public class RbcParserService implements ParserService {
|
||||
* Получение RSS-ленты
|
||||
*/
|
||||
private SyndFeed getRssFeed() throws Exception {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
try (XmlReader reader = new XmlReader(feedUrl.openStream())) {
|
||||
return input.build(reader);
|
||||
try {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
// Добавляем таймаут и обработку ошибок
|
||||
java.net.URLConnection connection = feedUrl.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10 секунд
|
||||
connection.setReadTimeout(30000); // 30 секунд
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
try (XmlReader reader = new XmlReader(connection.getInputStream())) {
|
||||
return input.build(reader);
|
||||
}
|
||||
} catch (com.rometools.rome.io.ParsingFeedException e) {
|
||||
logger.error("Ошибка парсинга XML для РБК: {}", e.getMessage());
|
||||
throw new Exception("Невалидный XML в RSS-ленте РБК: " + e.getMessage(), e);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
logger.error("Не удается подключиться к серверу РБК: {}", e.getMessage());
|
||||
throw new Exception("Сервер РБК недоступен: " + e.getMessage(), e);
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
logger.error("Таймаут при подключении к РБК: {}", e.getMessage());
|
||||
throw new Exception("Таймаут подключения к РБК: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Общая ошибка при получении RSS-ленты РБК: {}", e.getMessage());
|
||||
throw new Exception("Ошибка получения RSS-ленты РБК: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,10 +102,31 @@ public class VedomostiParserService implements ParserService {
|
||||
* Получение RSS-ленты
|
||||
*/
|
||||
private SyndFeed getRssFeed() throws Exception {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
try (XmlReader reader = new XmlReader(feedUrl.openStream())) {
|
||||
return input.build(reader);
|
||||
try {
|
||||
URL feedUrl = URI.create(rssFeedUrl).toURL();
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
|
||||
// Добавляем таймаут и обработку ошибок
|
||||
java.net.URLConnection connection = feedUrl.openConnection();
|
||||
connection.setConnectTimeout(10000); // 10 секунд
|
||||
connection.setReadTimeout(30000); // 30 секунд
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
try (XmlReader reader = new XmlReader(connection.getInputStream())) {
|
||||
return input.build(reader);
|
||||
}
|
||||
} catch (com.rometools.rome.io.ParsingFeedException e) {
|
||||
logger.error("Ошибка парсинга XML для Ведомости: {}", e.getMessage());
|
||||
throw new Exception("Невалидный XML в RSS-ленте Ведомости: " + e.getMessage(), e);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
logger.error("Не удается подключиться к серверу Ведомости: {}", e.getMessage());
|
||||
throw new Exception("Сервер Ведомости недоступен: " + e.getMessage(), e);
|
||||
} catch (java.net.SocketTimeoutException e) {
|
||||
logger.error("Таймаут при подключении к Ведомости: {}", e.getMessage());
|
||||
throw new Exception("Таймаут подключения к Ведомости: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
logger.error("Общая ошибка при получении RSS-ленты Ведомости: {}", e.getMessage());
|
||||
throw new Exception("Ошибка получения RSS-ленты Ведомости: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package kz.konturai.parser.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Утилита для проверки доступности RSS-лент
|
||||
*/
|
||||
@Component
|
||||
public class RssUrlValidator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RssUrlValidator.class);
|
||||
|
||||
/**
|
||||
* Проверяет доступность RSS-ленты
|
||||
*/
|
||||
public boolean isRssUrlAccessible(String url) {
|
||||
try {
|
||||
URL feedUrl = URI.create(url).toURL();
|
||||
HttpURLConnection connection = (HttpURLConnection) feedUrl.openConnection();
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setConnectTimeout(10000);
|
||||
connection.setReadTimeout(10000);
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
connection.disconnect();
|
||||
|
||||
return responseCode == 200;
|
||||
} catch (Exception e) {
|
||||
logger.warn("RSS URL недоступен: {} - {}", url, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает альтернативные URL для RSS-лент
|
||||
*/
|
||||
public Map<String, String[]> getAlternativeUrls() {
|
||||
Map<String, String[]> alternatives = new HashMap<>();
|
||||
|
||||
// Альтернативные URL для Kapital.kz
|
||||
alternatives.put("kapital", new String[] {
|
||||
"https://kapital.kz/rss/",
|
||||
"https://kapital.kz/feed/",
|
||||
"https://kapital.kz/rss.xml"
|
||||
});
|
||||
|
||||
// Альтернативные URL для Kursiv
|
||||
alternatives.put("kursiv", new String[] {
|
||||
"https://kursiv.media/feed/",
|
||||
"https://kursiv.media/rss/",
|
||||
"https://kursiv.media/rss.xml"
|
||||
});
|
||||
|
||||
// Альтернативные URL для LSM.kz
|
||||
alternatives.put("lsm", new String[] {
|
||||
"https://lsm.kz/rss",
|
||||
"https://lsm.kz/feed/",
|
||||
"https://lsm.kz/rss.xml"
|
||||
});
|
||||
|
||||
// Альтернативные URL для РБК
|
||||
alternatives.put("rbc", new String[] {
|
||||
"https://static.feed.rbc.ru/rbc/logical/footer/news.rss",
|
||||
"https://rbc.ru/rss/",
|
||||
"https://rbc.ru/feed/",
|
||||
"https://www.rbc.ru/rss/",
|
||||
"https://www.rbc.ru/feed/"
|
||||
});
|
||||
|
||||
// Альтернативные URL для Ведомости
|
||||
alternatives.put("vedomosti", new String[] {
|
||||
"https://www.vedomosti.ru/rss/rubric/technology/internet",
|
||||
"https://www.vedomosti.ru/rss/",
|
||||
"https://www.vedomosti.ru/feed/",
|
||||
"https://vedomosti.ru/rss/"
|
||||
});
|
||||
|
||||
return alternatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Находит первый доступный URL из списка альтернатив
|
||||
*/
|
||||
public String findWorkingUrl(String sourceName) {
|
||||
Map<String, String[]> alternatives = getAlternativeUrls();
|
||||
String[] urls = alternatives.get(sourceName);
|
||||
|
||||
if (urls == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String url : urls) {
|
||||
if (isRssUrlAccessible(url)) {
|
||||
logger.info("Найден рабочий URL для {}: {}", sourceName, url);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
logger.warn("Не найдено рабочих URL для источника: {}", sourceName);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет все RSS-ленты и возвращает отчет
|
||||
*/
|
||||
public Map<String, Boolean> checkAllRssUrls(Map<String, String> rssUrls) {
|
||||
Map<String, Boolean> results = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, String> entry : rssUrls.entrySet()) {
|
||||
String source = entry.getKey();
|
||||
String url = entry.getValue();
|
||||
|
||||
boolean isAccessible = isRssUrlAccessible(url);
|
||||
results.put(source, isAccessible);
|
||||
|
||||
if (!isAccessible) {
|
||||
logger.warn("RSS URL недоступен: {} - {}", source, url);
|
||||
String alternativeUrl = findWorkingUrl(source);
|
||||
if (alternativeUrl != null) {
|
||||
logger.info("Рекомендуется использовать альтернативный URL для {}: {}", source, alternativeUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user