From 0508333aeb8232c57b2d64182664b8422e899125 Mon Sep 17 00:00:00 2001 From: kilyabin <65072190+kilyabin@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:36:14 +0400 Subject: [PATCH] =?UTF-8?q?refactor:=20=D1=83=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D0=B8=20=D0=B2=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Удалить избыточные комментарии об обработке ошибок - Убрать упоминания о старых проблемах (fallback, вместо throw) - Сократить описания debug-опций - Упростить комментарии о кэшировании --- src/app/agregator/schedule.ts | 12 ++++++------ src/app/parser/schedule.ts | 5 ++--- src/pages/[group].tsx | 30 ++++++++++++++---------------- src/pages/admin.tsx | 8 ++++---- src/pages/teacher/[teacher].tsx | 28 +++++++++++++--------------- src/shared/data/database.ts | 6 ++---- 6 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/app/agregator/schedule.ts b/src/app/agregator/schedule.ts index fc9db60..16e5471 100644 --- a/src/app/agregator/schedule.ts +++ b/src/app/agregator/schedule.ts @@ -57,7 +57,7 @@ export async function getSchedule(groupID: number, groupName: string, wk?: numbe dom = null return scheduleResult } catch(e) { - // Очищаем JSDOM даже в случае ошибки + // Очищаем JSDOM при ошибке if (dom) { dom.window.close() } @@ -118,7 +118,7 @@ export async function getSchedule(groupID: number, groupName: string, wk?: numbe networkErrorMessage: networkError.message }) } else if (networkError.code === 'DEPTH_ZERO_SELF_SIGNED_CERT' || networkError.message?.includes('self-signed certificate') || networkError.message?.includes('certificate')) { - // Ошибка SSL сертификата + // Обработка ошибки SSL сертификата console.error(`SSL certificate error while fetching ${PROXY_URL}:`, { code: networkError.code, message: networkError.message, @@ -144,7 +144,7 @@ export async function getSchedule(groupID: number, groupName: string, wk?: numbe }) } } else { - // Проверяем сообщение об ошибке на наличие упоминания сертификата + // Проверка на ошибку SSL сертификата по сообщению if (errorObj.message?.includes('self-signed certificate') || errorObj.message?.includes('certificate')) { const sslError = new Error(`В колледже что-то сломалось (проблема с сертификатом безопасности). Здесь я бессилен, проблема не на моей стороне.`) logErrorToFile(sslError, { @@ -207,7 +207,7 @@ export async function getTeacherSchedule(teacherID: number, teacherName: string, dom = null return scheduleResult } catch(e) { - // Очищаем JSDOM даже в случае ошибки + // Очищаем JSDOM при ошибке if (dom) { dom.window.close() } @@ -268,7 +268,7 @@ export async function getTeacherSchedule(teacherID: number, teacherName: string, networkErrorMessage: networkError.message }) } else if (networkError.code === 'DEPTH_ZERO_SELF_SIGNED_CERT' || networkError.message?.includes('self-signed certificate') || networkError.message?.includes('certificate')) { - // Ошибка SSL сертификата + // Обработка ошибки SSL сертификата console.error(`SSL certificate error while fetching ${PROXY_URL}:`, { code: networkError.code, message: networkError.message, @@ -294,7 +294,7 @@ export async function getTeacherSchedule(teacherID: number, teacherName: string, }) } } else { - // Проверяем сообщение об ошибке на наличие упоминания сертификата + // Проверка на ошибку SSL сертификата по сообщению if (errorObj.message?.includes('self-signed certificate') || errorObj.message?.includes('certificate')) { const sslError = new Error(`В колледже что-то сломалось (проблема с сертификатом безопасности). Здесь я бессилен, проблема не на моей стороне.`) logErrorToFile(sslError, { diff --git a/src/app/parser/schedule.ts b/src/app/parser/schedule.ts index 56d2a6c..c0ad95a 100644 --- a/src/app/parser/schedule.ts +++ b/src/app/parser/schedule.ts @@ -671,9 +671,9 @@ const parseLesson = (row: Element, isTeacherSchedule: boolean = false): Lesson | } } - // Для преподавателей может быть другая структура - проверяем наличие данных + // Для преподавателей может быть другая структура — проверяем наличие данных if (!cellText && !cellHTML) { - // Вместо ошибки, используем fallback + // Используем fallback для получения текста const allText = row.textContent?.trim() || '' if (allText && allText.length > 10) { cellText = allText @@ -1146,7 +1146,6 @@ export function parsePage( throw new Error(`Table not found for ${groupName}. Found ${tables.length} tables on the page.`) } - // К этому моменту table определен (иначе была бы ошибка выше) const selectedTable = table! logDebug('parsePage: selected table', { groupName, rows: selectedTable.querySelectorAll('tr').length }) diff --git a/src/pages/[group].tsx b/src/pages/[group].tsx index 0638b31..79b0548 100644 --- a/src/pages/[group].tsx +++ b/src/pages/[group].tsx @@ -123,16 +123,16 @@ export default function HomePage(props: NextSerialized) { } const cachedSchedules = new Map() -const maxCacheDurationInMS = 1000 * 60 * 15 // 15 минут для нормального использования кэша -const fallbackCacheDurationInMS = 1000 * 60 * 60 * 24 // 24 часа для fallback кэша при ошибках парсинга -const maxCacheSize = 50 // Максимальное количество записей в кэше (только текущие недели) +const maxCacheDurationInMS = 1000 * 60 * 15 // 15 минут +const fallbackCacheDurationInMS = 1000 * 60 * 60 * 24 // 24 часа +const maxCacheSize = 50 // Максимальное количество записей в кэше // Очистка старых записей из кэша function cleanupCache() { const now = Date.now() const entriesToDelete: string[] = [] - - // Находим устаревшие записи (используем fallback TTL для сохранения кэша при ошибках) + + // Находим устаревшие записи for (const [key, value] of cachedSchedules.entries()) { if (now - value.lastFetched.getTime() >= fallbackCacheDurationInMS) { entriesToDelete.push(key) @@ -164,9 +164,8 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr : undefined if (group && Object.hasOwn(groups, group) && group in groups) { - // Проверяем debug опции const debug = settings.debug || {} - + // Debug: принудительно показать ошибку if (debug.forceError) { const cacheAvailableFor = Array.from(cachedSchedules.entries()) @@ -190,7 +189,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr } } - // Debug: принудительно симулировать таймаут + // Debug: симулировать таймаут if (debug.forceTimeout) { const cacheAvailableFor = Array.from(cachedSchedules.entries()) .filter(([, v]) => v.lastFetched.getTime() + maxCacheDurationInMS > Date.now()) @@ -227,7 +226,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr const cacheKey = group // Ключ кэша - только группа (текущая неделя) const cachedSchedule = useCache ? cachedSchedules.get(cacheKey) : undefined - // Debug: принудительно использовать кэш + // Debug: использовать кэш if (debug.forceCache && cachedSchedule) { scheduleResult = cachedSchedule.results parsedAt = cachedSchedule.lastFetched @@ -251,8 +250,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr cleanupCache() } } catch(e) { - // При таймауте или любой другой ошибке используем кэш, если он доступен (fallback кэш) - // Используем кэш независимо от возраста при ошибке парсинга + // При ошибке используем кэш, если он доступен if (cachedSchedule) { scheduleResult = cachedSchedule.results parsedAt = cachedSchedule.lastFetched @@ -266,7 +264,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr console.warn(`Schedule fetch error for group ${group}, using fallback cache from ${cachedSchedule.lastFetched.toISOString()} (${cacheAge} minutes old)`) } } else { - // Если кэша нет, возвращаем страницу с ошибкой вместо throw + // Если кэша нет, возвращаем страницу с ошибкой const isTimeout = e instanceof ScheduleTimeoutError const errorMessageObj = e instanceof Error ? e : new Error(String(e)) const isSSLError = errorMessageObj.message?.includes('колледже что-то сломалось') || @@ -278,7 +276,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr errorMessageObj.cause.message?.includes('self-signed certificate') )) - // Если ошибка уже содержит нужное сообщение, используем его напрямую + // Формируем сообщение об ошибке let errorMessage: string if (isTimeout) { errorMessage = 'Превышено время ожидания ответа от сервера' @@ -314,7 +312,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr } } - // Debug: принудительно показать пустое расписание + // Debug: показать пустое расписание if (debug.forceEmpty) { scheduleResult = { days: [], @@ -344,9 +342,9 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ gr const cacheAvailableFor = Array.from(cachedSchedules.entries()) .filter(([, v]) => v.lastFetched.getTime() + maxCacheDurationInMS > Date.now()) - .map(([k]) => k.split('_')[0]) // Берем только группу из ключа кэша + .map(([k]) => k.split('_')[0]) - // Debug: информация о кэше + // Информация о кэше (debug) const cacheInfo = debug.showCacheInfo ? { size: cachedSchedules.size, entries: cachedSchedules.size diff --git a/src/pages/admin.tsx b/src/pages/admin.tsx index e6e964a..c17e381 100644 --- a/src/pages/admin.tsx +++ b/src/pages/admin.tsx @@ -202,7 +202,7 @@ export default function AdminPage({ groups: initialGroups, settings: initialSett const loadSettingsList = () => loadData('/api/admin/settings', setSettings) const handleUpdateSettings = async (newSettings: AppSettings) => { - // Сохраняем предыдущее состояние для отката при ошибке + // Сохраняем предыдущее состояние для отката const previousSettings = settings // Оптимистичное обновление UI setSettings(newSettings) @@ -218,18 +218,18 @@ export default function AdminPage({ groups: initialGroups, settings: initialSett const data = await res.json() if (res.ok && data.success) { - // Обновляем состояние из ответа сервера (для синхронизации) + // Обновляем состояние из ответа сервера setSettings(data.settings) showToast('Настройки успешно обновлены', 'success') } else { - // Откатываем изменения при ошибке + // Откат изменений при ошибке setSettings(previousSettings) const errorMessage = data.error || 'Ошибка при обновлении настроек' setError(errorMessage) showToast(errorMessage, 'error') } } catch (err) { - // Откатываем изменения при ошибке + // Откат изменений при ошибке setSettings(previousSettings) const errorMessage = 'Ошибка соединения с сервером' setError(errorMessage) diff --git a/src/pages/teacher/[teacher].tsx b/src/pages/teacher/[teacher].tsx index 7042326..198898e 100644 --- a/src/pages/teacher/[teacher].tsx +++ b/src/pages/teacher/[teacher].tsx @@ -112,16 +112,16 @@ export default function TeacherPage(props: NextSerialized) { } const cachedTeacherSchedules = new Map() -const maxCacheDurationInMS = 1000 * 60 * 15 // 15 минут для нормального использования кэша -const fallbackCacheDurationInMS = 1000 * 60 * 60 * 24 // 24 часа для fallback кэша при ошибках парсинга -const maxCacheSize = 50 // Максимальное количество записей в кэше (только текущие недели) +const maxCacheDurationInMS = 1000 * 60 * 15 // 15 минут +const fallbackCacheDurationInMS = 1000 * 60 * 60 * 24 // 24 часа +const maxCacheSize = 50 // Максимальное количество записей в кэше // Очистка старых записей из кэша function cleanupCache() { const now = Date.now() const entriesToDelete: string[] = [] - - // Находим устаревшие записи (используем fallback TTL для сохранения кэша при ошибках) + + // Находим устаревшие записи for (const [key, value] of cachedTeacherSchedules.entries()) { if (now - value.lastFetched.getTime() >= fallbackCacheDurationInMS) { entriesToDelete.push(key) @@ -169,9 +169,8 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te } } - // Проверяем debug опции const debug = settings.debug || {} - + // Debug: принудительно показать ошибку if (debug.forceError) { const cacheAvailableFor = Array.from(cachedTeacherSchedules.entries()) @@ -195,7 +194,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te } } - // Debug: принудительно симулировать таймаут + // Debug: симулировать таймаут if (debug.forceTimeout) { const cacheAvailableFor = Array.from(cachedTeacherSchedules.entries()) .filter(([, v]) => v.lastFetched.getTime() + maxCacheDurationInMS > Date.now()) @@ -232,7 +231,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te const cacheKey = `teacher_${teacherParseId}` // Ключ кэша для преподавателя const cachedSchedule = useCache ? cachedTeacherSchedules.get(cacheKey) : undefined - // Debug: принудительно использовать кэш + // Debug: использовать кэш if (debug.forceCache && cachedSchedule) { scheduleResult = cachedSchedule.results parsedAt = cachedSchedule.lastFetched @@ -255,8 +254,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te cleanupCache() } } catch(e) { - // При таймауте или любой другой ошибке используем кэш, если он доступен (fallback кэш) - // Используем кэш независимо от возраста при ошибке парсинга + // При ошибке используем кэш, если он доступен if (cachedSchedule) { scheduleResult = cachedSchedule.results parsedAt = cachedSchedule.lastFetched @@ -270,7 +268,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te console.warn(`Schedule fetch error for teacher ${teacherInfo.name}, using fallback cache from ${cachedSchedule.lastFetched.toISOString()} (${cacheAge} minutes old)`) } } else { - // Если кэша нет, возвращаем страницу с ошибкой вместо throw + // Если кэша нет, возвращаем страницу с ошибкой const isTimeout = e instanceof ScheduleTimeoutError const errorMessageObj = e instanceof Error ? e : new Error(String(e)) const isSSLError = errorMessageObj.message?.includes('колледже что-то сломалось') || @@ -313,7 +311,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te } } - // Debug: принудительно показать пустое расписание + // Debug: показать пустое расписание if (debug.forceEmpty) { scheduleResult = { days: [], @@ -343,9 +341,9 @@ export async function getServerSideProps(context: GetServerSidePropsContext<{ te const cacheAvailableFor = Array.from(cachedTeacherSchedules.entries()) .filter(([, v]) => v.lastFetched.getTime() + maxCacheDurationInMS > Date.now()) - .map(([k]) => k.split('_')[1]) // Берем parseId из ключа кэша + .map(([k]) => k.split('_')[1]) - // Debug: информация о кэше + // Информация о кэше (debug) const cacheInfo = debug.showCacheInfo ? { size: cachedTeacherSchedules.size, entries: cachedTeacherSchedules.size diff --git a/src/shared/data/database.ts b/src/shared/data/database.ts index eb64663..78b4ff5 100644 --- a/src/shared/data/database.ts +++ b/src/shared/data/database.ts @@ -381,8 +381,7 @@ export function getSettings(): AppSettings { try { const settings = JSON.parse(row.value) as Partial - // Всегда добавляем дефолтные debug настройки (они не хранятся в БД) - // И добавляем отсутствующие поля для обратной совместимости + // Добавляем debug настройки и значения по умолчанию для обратной совместимости return { weekNavigationEnabled: settings.weekNavigationEnabled ?? false, showAddGroupButton: settings.showAddGroupButton ?? true, @@ -435,12 +434,11 @@ export function updateSettings(settings: AppSettings): void { } } - // Исключаем debug из настроек перед сохранением в БД + // Сохраняем настройки без debug (debug не хранится в БД) const { debug, ...settingsWithoutDebug } = settings const mergedSettings: AppSettings = { ...defaultSettings, ...settingsWithoutDebug - // debug намеренно не сохраняется в БД } database