Update files
This commit is contained in:
parent
a3f9374a6a
commit
ca7c508e57
|
|
@ -77,10 +77,23 @@ async function sendPhotoToUser(userId, photoUrl, caption) {
|
||||||
throw new Error('TELEGRAM_BOT_TOKEN не установлен');
|
throw new Error('TELEGRAM_BOT_TOKEN не установлен');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Валидация параметров
|
||||||
|
if (!userId || (typeof userId !== 'number' && typeof userId !== 'string')) {
|
||||||
|
throw new Error('userId должен быть числом или строкой');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!photoUrl || typeof photoUrl !== 'string') {
|
||||||
|
throw new Error('photoUrl обязателен и должен быть строкой');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Получаем оригинальный URL (если это прокси URL)
|
// Получаем оригинальный URL (если это прокси URL)
|
||||||
let finalPhotoUrl = getOriginalUrl(photoUrl);
|
let finalPhotoUrl = getOriginalUrl(photoUrl);
|
||||||
|
|
||||||
|
if (!finalPhotoUrl) {
|
||||||
|
throw new Error('Не удалось получить URL изображения');
|
||||||
|
}
|
||||||
|
|
||||||
// Если это все еще относительный URL (локальный файл), используем публичный URL
|
// Если это все еще относительный URL (локальный файл), используем публичный URL
|
||||||
if (finalPhotoUrl.startsWith('/')) {
|
if (finalPhotoUrl.startsWith('/')) {
|
||||||
const baseUrl = process.env.FRONTEND_URL || process.env.API_URL || 'https://nakama.glpshchn.ru';
|
const baseUrl = process.env.FRONTEND_URL || process.env.API_URL || 'https://nakama.glpshchn.ru';
|
||||||
|
|
@ -167,7 +180,24 @@ async function sendPhotoToUser(userId, photoUrl, caption) {
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка отправки медиа:', error.response?.data || error.message);
|
const errorDetails = {
|
||||||
|
message: error.message,
|
||||||
|
userId: userId,
|
||||||
|
photoUrl: photoUrl,
|
||||||
|
telegramError: error.response?.data
|
||||||
|
};
|
||||||
|
|
||||||
|
console.error('Ошибка отправки медиа:', errorDetails);
|
||||||
|
|
||||||
|
// Если это ошибка от Telegram API, пробрасываем её с более понятным сообщением
|
||||||
|
if (error.response?.data) {
|
||||||
|
const telegramError = error.response.data;
|
||||||
|
const errorMessage = telegramError.description || telegramError.error_code
|
||||||
|
? `Telegram API ошибка: ${telegramError.description || `Код ${telegramError.error_code}`}`
|
||||||
|
: error.message;
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,19 @@ router.post('/send-photo', authenticate, async (req, res) => {
|
||||||
return res.status(400).json({ error: 'userId и photoUrl обязательны' });
|
return res.status(400).json({ error: 'userId и photoUrl обязательны' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await sendPhotoToUser(userId, photoUrl, caption);
|
// Преобразуем userId в число, если это строка (Telegram API ожидает число)
|
||||||
|
const telegramUserId = typeof userId === 'string' ? parseInt(userId, 10) : userId;
|
||||||
|
|
||||||
|
if (isNaN(telegramUserId)) {
|
||||||
|
return res.status(400).json({ error: 'userId должен быть числом' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Валидация URL
|
||||||
|
if (typeof photoUrl !== 'string' || photoUrl.trim().length === 0) {
|
||||||
|
return res.status(400).json({ error: 'photoUrl должен быть непустой строкой' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await sendPhotoToUser(telegramUserId, photoUrl.trim(), caption);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -20,10 +32,16 @@ router.post('/send-photo', authenticate, async (req, res) => {
|
||||||
result
|
result
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка отправки:', error);
|
console.error('Ошибка отправки фото:', {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
response: error.response?.data,
|
||||||
|
userId: req.body?.userId,
|
||||||
|
photoUrl: req.body?.photoUrl
|
||||||
|
});
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: 'Ошибка отправки изображения',
|
error: 'Ошибка отправки изображения',
|
||||||
details: error.message
|
details: error.response?.data?.description || error.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ const config = require('../config');
|
||||||
|
|
||||||
// e621 требует описательный User-Agent с контактами
|
// e621 требует описательный User-Agent с контактами
|
||||||
const E621_USER_AGENT = 'NakamaApp/1.0 (by glpshchn on e621)';
|
const E621_USER_AGENT = 'NakamaApp/1.0 (by glpshchn on e621)';
|
||||||
const CACHE_TTL_MS = 60 * 1000; // 1 минута
|
const CACHE_TTL_MS = 60 * 1000; // 1 минута для поиска
|
||||||
|
const TAGS_CACHE_TTL_MS = 10 * 60 * 1000; // 10 минут для тегов (автокомплит)
|
||||||
|
|
||||||
const searchCache = new Map();
|
const searchCache = new Map();
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ function getFromCache(key) {
|
||||||
return entry.data;
|
return entry.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCache(key, data) {
|
function setCache(key, data, ttl = CACHE_TTL_MS) {
|
||||||
if (searchCache.size > 200) {
|
if (searchCache.size > 200) {
|
||||||
// Удалить устаревшие записи, если превышен лимит
|
// Удалить устаревшие записи, если превышен лимит
|
||||||
for (const [cacheKey, entry] of searchCache.entries()) {
|
for (const [cacheKey, entry] of searchCache.entries()) {
|
||||||
|
|
@ -42,7 +43,7 @@ function setCache(key, data) {
|
||||||
}
|
}
|
||||||
searchCache.set(key, {
|
searchCache.set(key, {
|
||||||
data,
|
data,
|
||||||
expires: Date.now() + CACHE_TTL_MS
|
expires: Date.now() + ttl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,7 +339,13 @@ router.get('/furry/tags', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { query } = req.query;
|
const { query } = req.query;
|
||||||
|
|
||||||
if (!query || query.length < 2) {
|
// Быстрый возврат для очень коротких запросов
|
||||||
|
if (!query || query.length < 1) {
|
||||||
|
return res.json({ tags: [] });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Для запросов длиной 1 символ возвращаем пустой результат без запроса к API
|
||||||
|
if (query.length < 2) {
|
||||||
return res.json({ tags: [] });
|
return res.json({ tags: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,7 +370,7 @@ router.get('/furry/tags', authenticate, async (req, res) => {
|
||||||
'User-Agent': E621_USER_AGENT,
|
'User-Agent': E621_USER_AGENT,
|
||||||
'Authorization': `Basic ${auth}`
|
'Authorization': `Basic ${auth}`
|
||||||
},
|
},
|
||||||
timeout: 10000,
|
timeout: 5000, // Уменьшили таймаут до 5 секунд для более быстрого ответа
|
||||||
validateStatus: (status) => status < 500 // Не бросать ошибку для 429
|
validateStatus: (status) => status < 500 // Не бросать ошибку для 429
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -388,7 +395,7 @@ router.get('/furry/tags', authenticate, async (req, res) => {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': E621_USER_AGENT
|
'User-Agent': E621_USER_AGENT
|
||||||
},
|
},
|
||||||
timeout: 10000,
|
timeout: 5000, // Уменьшили таймаут до 5 секунд
|
||||||
validateStatus: (status) => status < 500
|
validateStatus: (status) => status < 500
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -432,7 +439,8 @@ router.get('/furry/tags', authenticate, async (req, res) => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const payload = { tags };
|
const payload = { tags };
|
||||||
setCache(cacheKey, payload);
|
// Используем более длительное кэширование для тегов (10 минут)
|
||||||
|
setCache(cacheKey, payload, TAGS_CACHE_TTL_MS);
|
||||||
return res.json(payload);
|
return res.json(payload);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Обработка 429 ошибок
|
// Обработка 429 ошибок
|
||||||
|
|
@ -481,7 +489,7 @@ router.get('/anime/tags', authenticate, async (req, res) => {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||||
},
|
},
|
||||||
timeout: 30000,
|
timeout: 5000, // Уменьшили таймаут до 5 секунд для более быстрого ответа
|
||||||
validateStatus: (status) => status < 500 // Не бросать ошибку для 429
|
validateStatus: (status) => status < 500 // Не бросать ошибку для 429
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -513,7 +521,8 @@ router.get('/anime/tags', authenticate, async (req, res) => {
|
||||||
})).filter(tag => tag.name);
|
})).filter(tag => tag.name);
|
||||||
|
|
||||||
const payload = { tags };
|
const payload = { tags };
|
||||||
setCache(cacheKey, payload);
|
// Используем более длительное кэширование для тегов (10 минут)
|
||||||
|
setCache(cacheKey, payload, TAGS_CACHE_TTL_MS);
|
||||||
return res.json(payload);
|
return res.json(payload);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Обработка 429 ошибок
|
// Обработка 429 ошибок
|
||||||
|
|
|
||||||
|
|
@ -295,9 +295,22 @@ export const sendPhotoToTelegram = async (photoUrl) => {
|
||||||
throw new Error('Не удалось получить ID пользователя из Telegram')
|
throw new Error('Не удалось получить ID пользователя из Telegram')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Убеждаемся, что userId - это число (Telegram API ожидает число)
|
||||||
|
const userId = typeof telegramUser.id === 'string'
|
||||||
|
? parseInt(telegramUser.id, 10)
|
||||||
|
: telegramUser.id
|
||||||
|
|
||||||
|
if (isNaN(userId)) {
|
||||||
|
throw new Error('Неверный формат ID пользователя')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!photoUrl || typeof photoUrl !== 'string') {
|
||||||
|
throw new Error('URL изображения обязателен')
|
||||||
|
}
|
||||||
|
|
||||||
const response = await api.post('/bot/send-photo', {
|
const response = await api.post('/bot/send-photo', {
|
||||||
userId: telegramUser.id,
|
userId: userId,
|
||||||
photoUrl,
|
photoUrl: photoUrl.trim(),
|
||||||
caption: 'Из Nakama'
|
caption: 'Из Nakama'
|
||||||
})
|
})
|
||||||
return response.data
|
return response.data
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue