refactor: упростить комментарии в коде
- Удалить избыточные комментарии об обработке ошибок - Убрать упоминания о старых проблемах (fallback, вместо throw) - Сократить описания debug-опций - Упростить комментарии о кэшировании
This commit is contained in:
@@ -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, {
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -123,16 +123,16 @@ export default function HomePage(props: NextSerialized<PageProps>) {
|
||||
}
|
||||
|
||||
const cachedSchedules = new Map<string, { lastFetched: Date, results: ScheduleResult }>()
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -112,16 +112,16 @@ export default function TeacherPage(props: NextSerialized<PageProps>) {
|
||||
}
|
||||
|
||||
const cachedTeacherSchedules = new Map<string, { lastFetched: Date, results: ScheduleResult }>()
|
||||
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
|
||||
|
||||
@@ -381,8 +381,7 @@ export function getSettings(): AppSettings {
|
||||
|
||||
try {
|
||||
const settings = JSON.parse(row.value) as Partial<AppSettings>
|
||||
// Всегда добавляем дефолтные 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
|
||||
|
||||
Reference in New Issue
Block a user