up
This commit is contained in:
+67
-8
@@ -13,6 +13,7 @@ import { createReadStream } from 'node:fs'
|
||||
import { stat } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { Readable } from 'node:stream'
|
||||
import { DiagnosticLog } from './diagnostics.js'
|
||||
import { Controller, parseCommand } from './controller.js'
|
||||
import { WindowSettings, fitControlBounds, preferredDisplayId } from './window-settings.js'
|
||||
import { parseRange } from './range.js'
|
||||
@@ -43,8 +44,18 @@ let settings: WindowSettings
|
||||
let sleepBlocker: number | null = null
|
||||
let hostNotice = ''
|
||||
let suspended = false
|
||||
let diagnostics: DiagnosticLog | null = null
|
||||
const lastErrors = { main: false, music: false, scene: false }
|
||||
let saveTimer: ReturnType<typeof setTimeout> | undefined
|
||||
const controller = new Controller((state) => {
|
||||
for (const channel of ['main', 'music', 'scene'] as const) {
|
||||
const failed =
|
||||
channel === 'scene'
|
||||
? state.scene.status === 'error'
|
||||
: state.channels[channel].status === 'error'
|
||||
if (failed && !lastErrors[channel]) diagnostics?.record('media-error', { channel })
|
||||
lastErrors[channel] = failed
|
||||
}
|
||||
for (const window of [control, output])
|
||||
if (window && !window.isDestroyed()) window.webContents.send('state', state)
|
||||
})
|
||||
@@ -101,6 +112,23 @@ function closeOutput(reason = '', destroy = true) {
|
||||
if (reason) outputEpoch++
|
||||
const window = output
|
||||
if (!window && (!reason || controller.state.timer.status !== 'running')) return
|
||||
diagnostics?.record('output-close', {
|
||||
reason: !reason
|
||||
? 'operator'
|
||||
: reason.includes('сон')
|
||||
? 'power'
|
||||
: reason.includes('полноэкран')
|
||||
? 'fullscreen'
|
||||
: reason.includes('Процесс')
|
||||
? 'renderer'
|
||||
: reason.includes('не отвечает')
|
||||
? 'unresponsive'
|
||||
: reason.includes('загрузить')
|
||||
? 'document'
|
||||
: reason.includes('Параметры')
|
||||
? 'geometry'
|
||||
: 'display',
|
||||
})
|
||||
output = null
|
||||
if (window) closingWindow = window
|
||||
selectedDisplay = null
|
||||
@@ -123,6 +151,7 @@ function saveWindowSettings() {
|
||||
try {
|
||||
settings.save()
|
||||
} catch {
|
||||
diagnostics?.record('settings-error')
|
||||
hostNotice = 'Не удалось сохранить расположение окон; материалы игры не затронуты'
|
||||
}
|
||||
}
|
||||
@@ -180,6 +209,7 @@ async function show(displayId: number) {
|
||||
saveWindowSettings()
|
||||
secure(window)
|
||||
controller.output(true)
|
||||
diagnostics?.record('output-open')
|
||||
try {
|
||||
sleepBlocker = powerSaveBlocker.start('prevent-display-sleep')
|
||||
} catch {
|
||||
@@ -241,10 +271,18 @@ app.on('second-instance', () => {
|
||||
app
|
||||
.whenReady()
|
||||
.then(async () => {
|
||||
diagnostics = new DiagnosticLog(join(app.getPath('userData'), 'logs'))
|
||||
diagnostics.record('app-start', {
|
||||
version: app.getVersion(),
|
||||
electron: process.versions.electron,
|
||||
platform: process.platform,
|
||||
arch: process.arch,
|
||||
})
|
||||
settings = new WindowSettings(join(app.getPath('userData'), 'windows.json'))
|
||||
try {
|
||||
await settings.load()
|
||||
} catch (error) {
|
||||
diagnostics.record('settings-error')
|
||||
hostNotice = error instanceof Error ? error.message : 'Не удалось восстановить окна'
|
||||
}
|
||||
const packages = new PackageStore(join(app.getPath('userData'), 'packages'))
|
||||
@@ -258,8 +296,14 @@ app
|
||||
decrypt: (value) => safeStorage.decryptString(value),
|
||||
})
|
||||
await online.initialize()
|
||||
let previousConnection = online.state.connection
|
||||
const logConnection = () => {
|
||||
const status = online!.state.connection
|
||||
if (status !== previousConnection) diagnostics?.record('connection', { status })
|
||||
previousConnection = status
|
||||
}
|
||||
const onlineTick = setInterval(() => {
|
||||
void online?.poll()
|
||||
void online?.poll().then(logConnection)
|
||||
}, 1000)
|
||||
const timerTick = setInterval(() => controller.tick(), 250)
|
||||
app.on('before-quit', () => {
|
||||
@@ -271,6 +315,7 @@ app
|
||||
clearInterval(onlineTick)
|
||||
online?.close()
|
||||
packages.cancel()
|
||||
diagnostics?.record('app-stop')
|
||||
})
|
||||
const handleAppRequest: Parameters<typeof protocol.handle>[1] = async (request) => {
|
||||
const url = new URL(request.url)
|
||||
@@ -378,7 +423,20 @@ app
|
||||
ipcMain.handle('online-action', async (event, intent: unknown) => {
|
||||
requireControl(event)
|
||||
if (selectingPackage) throw new Error('Подождите проверки пакета')
|
||||
return online!.act(intent)
|
||||
const action =
|
||||
intent && typeof intent === 'object' && 'action' in intent ? intent.action : null
|
||||
try {
|
||||
const result = await online!.act(intent)
|
||||
if (['download', 'check', 'remove'].includes(String(action)))
|
||||
diagnostics?.record('package', { action, status: 'success' })
|
||||
return result
|
||||
} catch (error) {
|
||||
if (['download', 'check', 'remove'].includes(String(action)))
|
||||
diagnostics?.record('package', { action, status: 'failed' })
|
||||
throw error
|
||||
} finally {
|
||||
logConnection()
|
||||
}
|
||||
})
|
||||
ipcMain.handle('close-output', (event) => {
|
||||
requireControl(event)
|
||||
@@ -484,8 +542,8 @@ app
|
||||
return
|
||||
try {
|
||||
controller.reportScene(report)
|
||||
} catch (error) {
|
||||
console.error('Ошибка подтверждения сцены', error)
|
||||
} catch {
|
||||
diagnostics?.record('invalid-report')
|
||||
}
|
||||
})
|
||||
ipcMain.on('report', (event, report: unknown) => {
|
||||
@@ -496,8 +554,8 @@ app
|
||||
return
|
||||
try {
|
||||
controller.report(report)
|
||||
} catch (error) {
|
||||
console.error('Ошибка отчёта проигрывателя', error)
|
||||
} catch {
|
||||
diagnostics?.record('invalid-report')
|
||||
}
|
||||
})
|
||||
screen.on('display-removed', (_event, display) => {
|
||||
@@ -526,8 +584,9 @@ app
|
||||
})
|
||||
await control.loadURL('screen-app://app/index.html')
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
.catch(() => {
|
||||
diagnostics?.record('startup-error')
|
||||
console.error('SCREEN_STARTUP_FAILED')
|
||||
app.quit()
|
||||
})
|
||||
app.on('window-all-closed', () => app.quit())
|
||||
|
||||
Reference in New Issue
Block a user