chore: sprint D — sandbox, self-hosted fonts, logger с ротацией
#6 sandbox: true на обоих BrowserWindow (раньше false). Preload использует только contextBridge + ipcRenderer (оба sandbox-safe), никаких Node-built-ins. OS-уровневый sandbox изолирует renderer от GPU/IPC процессов; даже RCE в зависимости renderer'а не получит Node-доступа через preload. #17 self-host шрифтов через @fontsource/* пакеты. Раньше тянулись с fonts.googleapis.com — внешняя CSP-зависимость + отсутствие интернета = шрифты не загружались. Теперь .woff/.woff2 в bundle (22 файла × 15-30KB = ~500KB). Подкрутили CSP: убрали https://fonts.* origins, добавили connect-src 'self', base-uri 'self', frame-ancestors 'none'. #22 src/main/logger.ts — структурный лог с уровнями (debug/info/warn/error) и ротацией. Пишет в %APPDATA%/Exercise Reminder/logs/latest.log (≤1MB) и дублирует в console. При 1MB latest.log → prev.log (предыдущий prev.log удаляется). LAUDE_DEBUG=1 включает debug-уровень. Подключён в hot paths: store (corrupt/atomic write fails), updater (silent check errors), gsi-server (bad requests, handler throws), games/registry (GSI start, reconcile, match_end summary), games/dota2 (rejected token, POST_GAME detection). Особенно полезно для диагностики «челленджи не срабатывают»: лог покажет (а) пришёл ли вообще GSI payload (token verify), (б) детектировался ли POST_GAME, (в) сколько challenges были enabled и которые из них дали 0 reps. Logger — единственный файл с `eslint-disable no-console` (он намеренно дублирует в stderr).
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
isSteamRunning
|
||||
} from './steam-launch-options'
|
||||
import type { GameId, GameStatus, LaunchOptionStatus } from '@shared/types'
|
||||
import { log } from '../logger'
|
||||
|
||||
const APP_ID = '570'
|
||||
const INSTALL_DIR = 'dota 2 beta'
|
||||
@@ -198,6 +199,8 @@ export class Dota2Provider implements GameProvider {
|
||||
this.latest = undefined
|
||||
}
|
||||
|
||||
private rejectedTokenLogged = false
|
||||
|
||||
private handle(g: DotaGsi): void {
|
||||
// Verify the per-install token. Dota always sends auth.token; anything
|
||||
// without it (or with the wrong one) is some other process on localhost
|
||||
@@ -207,6 +210,15 @@ export class Dota2Provider implements GameProvider {
|
||||
typeof incoming !== 'string' ||
|
||||
!safeEqualStrings(incoming, this.token)
|
||||
) {
|
||||
// Логируем только ОДИН раз за процесс — Dota шлёт payload каждые
|
||||
// ~100ms во время матча, иначе zass'мём latest.log.
|
||||
if (!this.rejectedTokenLogged) {
|
||||
this.rejectedTokenLogged = true
|
||||
log.warn(
|
||||
'[dota2] GSI payload with invalid/missing token rejected. ' +
|
||||
'Если приложение переустанавливалось — заново подключи Dota 2 в Games.'
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -235,8 +247,12 @@ export class Dota2Provider implements GameProvider {
|
||||
if (prev && prev !== state && state === 'DOTA_GAMERULES_STATE_POST_GAME') {
|
||||
// De-dupe: Dota can fire POST_GAME repeatedly while the scoreboard is open.
|
||||
const now = Date.now()
|
||||
if (now - this.lastMatchEndAt < 30_000) return
|
||||
if (now - this.lastMatchEndAt < 30_000) {
|
||||
log.debug('[dota2] suppressed duplicate POST_GAME within 30s window')
|
||||
return
|
||||
}
|
||||
this.lastMatchEndAt = now
|
||||
log.info('[dota2] POST_GAME detected, emitting match_end event')
|
||||
|
||||
const p = this.latest?.player ?? {}
|
||||
const m = this.latest?.map ?? {}
|
||||
|
||||
Reference in New Issue
Block a user