Skip to content

Commit

Permalink
refactor host-files a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
SnosMe committed Dec 14, 2023
1 parent 8035f8b commit 2423765
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 86 deletions.
50 changes: 29 additions & 21 deletions main/src/host-files/GameConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,47 @@ import fs from 'fs/promises'
import path from 'path'
import ini from 'ini'
import { app } from 'electron'
import process from 'process';
import { hotkeyToString, CodeToKey } from '../../../ipc/KeyToCode'
import { guessFileLocation } from './utils'
import type { Logger } from '../RemoteLogger'
import type { ServerEvents } from '../server'

const POSSIBLE_PATH =
(process.platform === 'win32') ? [
path.join(app.getPath('documents'), 'My Games', 'Path of Exile', 'production_Config.ini')
] : (process.platform === 'linux') ? [
// TODO
] : (process.platform === 'darwin') ? [
path.join(app.getPath('appData'), 'Path of Exile', 'Preferences', 'production_Config.ini')
] : []

export class GameConfig {
private filePath?: string | null
private _wantedPath: string | null = null
private _actualPath: string | null = null
get actualPath () { return this._actualPath }

private _showModsKey: string = 'Alt'
get showModsKey () { return this._showModsKey }
private _showModsKey: string | null = null
get showModsKeyNullable () { return this._showModsKey }
get showModsKey () { return this._showModsKey ?? 'Alt' }

constructor (
private server: ServerEvents,
private logger: Logger
) {}

async readConfig (filePath: string | null) {
if (this.filePath === filePath) return
async readConfig (filePath: string) {
if (this._wantedPath !== filePath) {
this._wantedPath = filePath
this._actualPath = null
} else {
return
}

if (!filePath) {
if (process.platform === 'darwin') {
filePath = path.join(app.getPath('appData'), 'Path of Exile', 'Preferences', 'production_Config.ini')
if (!filePath.length) {
const guessedPath = await guessFileLocation(POSSIBLE_PATH)
if (guessedPath != null) {
filePath = guessedPath
} else {
filePath = path.join(app.getPath('documents'), 'My Games', 'Path of Exile', 'production_Config.ini')
}

try {
await fs.access(filePath)
// this.server.sendEventTo('any', {
// name: 'MAIN->CLIENT::file-path-changed',
// payload: { file: 'game-config', path: filePath }
// })
} catch {
this.logger.write('error [GameConfig] Failed to find game configuration file in the default location.')
return
}
Expand All @@ -46,9 +54,9 @@ export class GameConfig {
const parsed = ini.parse(contents)

this._showModsKey = this.parseConfigHotkey(
parsed['ACTION_KEYS']?.['show_advanced_item_descriptions']) ?? 'Alt'
parsed['ACTION_KEYS']?.['show_advanced_item_descriptions'])

this.filePath = filePath
this._actualPath = filePath
} catch {
this.logger.write('error [GameConfig] Failed to read game configuration file.')
}
Expand Down
120 changes: 57 additions & 63 deletions main/src/host-files/GameLogWatcher.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,87 @@
import { promises as fs, watchFile, unwatchFile } from 'fs'
import { app } from 'electron';
import { app } from 'electron'
import { guessFileLocation } from './utils'
import { ServerEvents } from '../server'
import { Logger } from '../RemoteLogger'

const POSSIBLE_PATH =
(process.platform === 'win32') ? [
'C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\logs\\Client.txt',
'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile\\logs\\Client.txt'
] : (process.platform === 'linux') ? [
// TODO
] : (process.platform === 'darwin') ? [
`${app.getPath('home')}/Library/Caches/com.GGG.PathOfExile/Logs/Client.txt`
] : []

export class GameLogWatcher {
private offset = 0
private filePath?: string
private file?: fs.FileHandle
private isReading = false
private readBuff = Buffer.allocUnsafe(64 * 1024)
private _wantedPath: string | null = null
get actualPath () { return this._state?.path ?? null }
private _state: {
offset: number
path: string
file: fs.FileHandle
isReading: boolean
readBuff: Buffer
} | null = null

constructor (
private server: ServerEvents,
private logger: Logger,
) {}

async restart (logFile: string | null) {
if (this.filePath === logFile) return

if (!logFile) {
let possiblePaths: string[] = []
if (process.platform === 'win32') {
possiblePaths = [
'C:\\Program Files (x86)\\Grinding Gear Games\\Path of Exile\\logs\\Client.txt',
'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Path of Exile\\logs\\Client.txt'
]
} else if (process.platform === 'darwin') {
possiblePaths = [
`${app.getPath('home')}/Library/Caches/com.GGG.PathOfExile/Logs/Client.txt`
]
}

for (const filePath of possiblePaths) {
try {
await fs.access(filePath)
// this.server.sendEventTo('any', {
// name: 'MAIN->CLIENT::file-path-changed',
// payload: { file: 'game-log', path: filePath }
// })
logFile = filePath
break
} catch {}
async restart (logFile: string) {
if (this._wantedPath !== logFile) {
this._wantedPath = logFile
if (this._state) {
unwatchFile(this._state.path)
await this._state.file.close()
this._state = null
}
} else {
return
}

if (logFile) {
try {
await this.watch(logFile)
} catch {
this.logger.write('error [GameLogWatcher] Failed to watch file.')
if (!logFile.length) {
const guessedPath = await guessFileLocation(POSSIBLE_PATH)
if (guessedPath != null) {
logFile = guessedPath
} else {
return
}
}
}

private async watch (path: string) {
if (this.file) {
unwatchFile(this.filePath!)
await this.file.close()
this.file = undefined
this.isReading = false
try {
const file = await fs.open(logFile, 'r')
const stats = await file.stat()
watchFile(logFile, { interval: 450 }, this.handleFileChange.bind(this))
this._state = {
path: logFile,
file: file,
offset: stats.size,
isReading: false,
readBuff: Buffer.allocUnsafe(64 * 1024),
}
} catch {
this.logger.write('error [GameLogWatcher] Failed to watch file.')
}

watchFile(path, { interval: 450 }, () => {
this.handleFileChange()
})
this.filePath = path

this.file = await fs.open(path, 'r')
const stats = await this.file.stat()
this.offset = stats.size
}

private handleFileChange () {
if (!this.isReading) {
this.isReading = true
if (this._state && !this._state.isReading) {
this._state.isReading = true
this.readToEOF()
}
}

private async readToEOF () {
if (!this.file) {
this.isReading = false
return
}
if (!this._state) return

const { bytesRead } = await this.file.read(this.readBuff, 0, this.readBuff.length, this.offset)
const { file, readBuff, offset } = this._state
const { bytesRead } = await file.read(readBuff, 0, readBuff.length, offset)

if (bytesRead) {
const str = this.readBuff.toString('utf8', 0, bytesRead)
const str = readBuff.toString('utf8', 0, bytesRead)
const lines = str.split('\n').map(line => line.trim()).filter(line => line.length)
this.server.sendEventTo('broadcast', {
name: 'MAIN->CLIENT::game-log',
Expand All @@ -96,10 +90,10 @@ export class GameLogWatcher {
}

if (bytesRead) {
this.offset += bytesRead
this._state.offset += bytesRead
this.readToEOF()
} else {
this.isReading = false
this._state.isReading = false
}
}
}
17 changes: 17 additions & 0 deletions main/src/host-files/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import fs from 'fs/promises'

export async function guessFileLocation (entries: Iterable<string>): Promise<string | null> {
let found: string | null = null
for (const path of entries) {
try {
await fs.access(path, fs.constants.R_OK)
if (found != null) {
// don't allow multiple matches (i.e. standalone + Steam)
return null
} else {
found = path
}
} catch {}
}
return found
}
4 changes: 2 additions & 2 deletions main/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ app.on('ready', async () => {
eventPipe.onEventAnyClient('CLIENT->MAIN::update-host-config', (cfg) => {
overlay.updateOpts(cfg.overlayKey, cfg.windowTitle)
shortcuts.updateActions(cfg.shortcuts, cfg.stashScroll, cfg.logKeys, cfg.restoreClipboard, cfg.language)
gameLogWatcher.restart(cfg.clientLog)
gameConfig.readConfig(cfg.gameConfig)
gameLogWatcher.restart(cfg.clientLog ?? '')
gameConfig.readConfig(cfg.gameConfig ?? '')
appUpdater.checkAtStartup()
tray.overlayKey = cfg.overlayKey
})
Expand Down

0 comments on commit 2423765

Please sign in to comment.