journalInterface js -> ts
This commit is contained in:
parent
84ec21161f
commit
ad2786d735
8 changed files with 116 additions and 58 deletions
43
package-lock.json
generated
43
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.194",
|
||||
"bootstrap": "^5.3.0-alpha3",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
|
@ -24,8 +25,12 @@
|
|||
"@electron-forge/maker-squirrel": "^6.1.1",
|
||||
"@electron-forge/maker-zip": "^6.1.1",
|
||||
"@electron-forge/plugin-vite": "^6.1.1",
|
||||
"@tsconfig/node20": "^1.0.0",
|
||||
"@types/node": "^20.1.2",
|
||||
"@types/tail": "^2.2.1",
|
||||
"electron": "24.2.0",
|
||||
"sass": "^1.62.1"
|
||||
"sass": "^1.62.1",
|
||||
"typescript": "^5.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron-forge/cli": {
|
||||
|
@ -1170,6 +1175,12 @@
|
|||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node20": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-1.0.0.tgz",
|
||||
"integrity": "sha512-AwbXtpWEaRUjbGVwdlusNqwet+jeSk3Nnqf/8+77WJ1/9d6xnqs2QpE9Pdwv8RCoXxtMedWEtlmWY+/irBPcUw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
|
@ -1218,6 +1229,11 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.194",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz",
|
||||
"integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g=="
|
||||
},
|
||||
"node_modules/@types/minimatch": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||
|
@ -1226,9 +1242,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz",
|
||||
"integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==",
|
||||
"version": "20.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz",
|
||||
"integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/responselike": {
|
||||
|
@ -1240,6 +1256,12 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/tail": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/tail/-/tail-2.2.1.tgz",
|
||||
"integrity": "sha512-j75Gs5MiIpNR14wztQ4vtViUqxZi+lcgflyXC7P9iMgNnMab7XcV5p+2590IO3njsWWn5l8C+55ILk2CDDyaHg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
|
||||
|
@ -6471,6 +6493,19 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
}
|
||||
},
|
||||
"node_modules/unique-filename": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
|
||||
|
|
|
@ -24,10 +24,15 @@
|
|||
"@electron-forge/maker-squirrel": "^6.1.1",
|
||||
"@electron-forge/maker-zip": "^6.1.1",
|
||||
"@electron-forge/plugin-vite": "^6.1.1",
|
||||
"@tsconfig/node20": "^1.0.0",
|
||||
"@types/node": "^20.1.2",
|
||||
"@types/tail": "^2.2.1",
|
||||
"electron": "24.2.0",
|
||||
"sass": "^1.62.1"
|
||||
"sass": "^1.62.1",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.194",
|
||||
"bootstrap": "^5.3.0-alpha3",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
|
|
7
src/@types/journalLines.d.ts
vendored
7
src/@types/journalLines.d.ts
vendored
|
@ -132,9 +132,10 @@ export interface planetScan<scanType> extends journalEntry<'Scan'> {
|
|||
}
|
||||
|
||||
export type autoScan = starScan<'AutoScan'> & asteroidScan<'AutoScan'> & planetScan<'AutoScan'>
|
||||
export type discoveryScan = starScan<'Detailed'> & asteroidScan<'Detailed'> & planetScan<'Detailed'>
|
||||
export type fssScan = starScan<'Detailed'> & asteroidScan<'Detailed'> & planetScan<'Detailed'>
|
||||
export type dssScan = starScan<'Detailed'> & asteroidScan<'Detailed'> & planetScan<'Detailed'>
|
||||
export type detailedScan = starScan<'Detailed'> & asteroidScan<'Detailed'> & planetScan<'Detailed'>
|
||||
export type discoveryScan = detailedScan
|
||||
export type fssScan = detailedScan
|
||||
export type dssScan = detailedScan
|
||||
|
||||
export interface startFsdJump extends journalEntry<'StartJump'> {
|
||||
JumpType: 'Hyperspace',
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { Tail as TailType } from 'tail'
|
||||
import type { autoScan, completeFsdJump, detailedScan, journalEntry, planetScan } from '../@types/journalLines'
|
||||
import { Body } from '../models/Body'
|
||||
import { System } from '../models/System'
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const max = require('lodash/max')
|
||||
const { globSync } = require('glob')
|
||||
import { globSync } from 'glob'
|
||||
const os = require('os')
|
||||
const lineReader = require('reverse-line-reader')
|
||||
const chokidar = require('chokidar')
|
||||
const Tail = require('tail').Tail
|
||||
const find = require('lodash/find')
|
||||
const findIndex = require('lodash/findIndex')
|
||||
import { maxBy, findIndex, find } from 'lodash'
|
||||
|
||||
// Set log() to console.log() so whenever I get around to setting up a log file, I don't have to
|
||||
// search and replace all the console.log()'s.
|
||||
|
@ -20,8 +20,8 @@ const log = console.log.bind(console)
|
|||
export class JournalInterface extends EventEmitter {
|
||||
journalDir: null|string
|
||||
journalPattern: string
|
||||
currentJournal: string
|
||||
location: null|System
|
||||
currentJournal: string|undefined
|
||||
location: System
|
||||
|
||||
|
||||
constructor(isPackaged: boolean) {
|
||||
|
@ -44,7 +44,7 @@ export class JournalInterface extends EventEmitter {
|
|||
log(`New journal file found, now watching ${path.basename(this.currentJournal)}.`)
|
||||
|
||||
// LineReader seems to be async, so start async processes here.
|
||||
this.location = null
|
||||
this.location = new System('Unknown')
|
||||
|
||||
log('JournalInterface initialized. Attempting to find current location.')
|
||||
this.getCurrentLocation()
|
||||
|
@ -53,10 +53,10 @@ export class JournalInterface extends EventEmitter {
|
|||
/* -------------------------------------------------------------------- getLatestJournal ---- */
|
||||
|
||||
// https://stackoverflow.com/questions/15696218/get-the-most-recent-file-in-a-directory-node-js
|
||||
getLatestJournal(): string {
|
||||
getLatestJournal(): string|undefined {
|
||||
const journals = globSync(this.journalPattern)
|
||||
|
||||
return max(journals, file => {
|
||||
return maxBy(journals, file => {
|
||||
const fullPath = path.join(this.journalDir, file)
|
||||
return fs.statSync(fullPath).mtime
|
||||
})
|
||||
|
@ -67,7 +67,7 @@ export class JournalInterface extends EventEmitter {
|
|||
// Get current location on setup, so if app is restarted, user can pick up where they left off
|
||||
// Rather than waiting til they jump to the next system to use the program again.
|
||||
getCurrentLocation(): void {
|
||||
lineReader.eachLine(this.currentJournal, (raw, last) => {
|
||||
lineReader.eachLine(this.currentJournal, (raw: string, last: boolean) => {
|
||||
if (raw) { // skip blank line at end of file
|
||||
const line = JSON.parse(raw)
|
||||
|
||||
|
@ -82,8 +82,10 @@ export class JournalInterface extends EventEmitter {
|
|||
}
|
||||
}
|
||||
}).then(() => {
|
||||
log('Attempting to find scanned bodies in current system.')
|
||||
this.getScannedBodies()
|
||||
if (this.location) {
|
||||
log('Attempting to find scanned bodies in current system.')
|
||||
this.getScannedBodies()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -91,22 +93,22 @@ export class JournalInterface extends EventEmitter {
|
|||
|
||||
// Look for all scanned bodies before last FSDJump, for same reasons as getCurrentLocation().
|
||||
getScannedBodies(): void {
|
||||
let detailedScanLine: Object|null = null
|
||||
let detailedScanLine: detailedScan|null = null
|
||||
|
||||
lineReader.eachLine(this.currentJournal, (raw, last) => {
|
||||
lineReader.eachLine(this.currentJournal, (raw: string, last: boolean) => {
|
||||
|
||||
if (raw) { // Skip blank line at end of file.
|
||||
const line = JSON.parse(raw)
|
||||
const line: journalEntry = JSON.parse(raw)
|
||||
|
||||
// Check if previous line was ScanType = Detailed, and handle that.
|
||||
if (detailedScanLine !== null) {
|
||||
if (line.event === 'SAAScanComplete') {
|
||||
// This was a DSS, so set the DSS flag to true and add to list.
|
||||
detailedScanLine.DSSDone = true
|
||||
this.location.bodies.push(new Body(detailedScanLine))
|
||||
// This was a DSS, so add to list with DSS flag set to true.
|
||||
this.location.bodies.push(new Body(detailedScanLine, true))
|
||||
} else {
|
||||
// Else, check that the body hasn't already been added (by a DSS scan line).
|
||||
let r = find(this.location.bodies, {'BodyName': detailedScanLine.BodyName, 'BodyID': detailedScanLine.BodyID})
|
||||
let dupChecker = {'BodyName': detailedScanLine.BodyName, 'BodyID': detailedScanLine.BodyID}
|
||||
let r = find(this.location.bodies, dupChecker)
|
||||
|
||||
if (r === undefined) {
|
||||
// Body was not already logged, so add to list.
|
||||
|
@ -119,28 +121,29 @@ export class JournalInterface extends EventEmitter {
|
|||
}
|
||||
|
||||
// Now move on to evaluating the current line.
|
||||
if (line.event === 'Scan') {
|
||||
if (line.event === 'Scan' && 'ScanType' in line) {
|
||||
// If ScanType = Detailed and body is not a star, save the line so we can check
|
||||
// the one immediately above for event = SAAScanComplete, which indicates this
|
||||
// was a DSS.
|
||||
if (line.ScanType === 'Detailed' && line.StarType === undefined) {
|
||||
detailedScanLine = line
|
||||
if (line.ScanType === 'Detailed' && !('StarType' in line)) {
|
||||
detailedScanLine = (line as detailedScan)
|
||||
|
||||
} else if (line.StarType !== undefined) { // Save stars to bodies list.
|
||||
this.location.bodies.push(new Body(line))
|
||||
} else if ('StarType' in line) { // Save stars to bodies list.
|
||||
this.location.bodies.push(new Body((line as autoScan|detailedScan)))
|
||||
|
||||
} else if (line.ScanType === 'AutoScan') { // Save auto/discovery scan bodies.
|
||||
// Check if planet, and then do the duplicate check (otherwise it's an
|
||||
// astroid, as we've already accounted for stars).
|
||||
if (line.PlanetClass !== undefined) {
|
||||
let r = find(this.location.bodies, ['BodyID', line.BodyID])
|
||||
if ('PlanetClass' in line) {
|
||||
let dupChecker = {'BodyName': (line as planetScan<'AutoScan'>).BodyName, 'BodyID': (line as planetScan<'AutoScan'>).BodyID}
|
||||
let r = find(this.location.bodies, dupChecker)
|
||||
|
||||
if (r === undefined) {
|
||||
this.location.bodies.push(new Body(line))
|
||||
this.location.bodies.push(new Body((line as autoScan)))
|
||||
}
|
||||
|
||||
} else { // Asteroids.
|
||||
this.location.bodies.push(new Body(line))
|
||||
this.location.bodies.push(new Body((line as autoScan)))
|
||||
}
|
||||
}
|
||||
} else if (line.event === 'FSDJump') {
|
||||
|
@ -159,10 +162,10 @@ export class JournalInterface extends EventEmitter {
|
|||
// Set up journal directory watcher to catch new journal files as the game seems to sometimes
|
||||
// make more than one journal per day.
|
||||
// Also for instances where UTC day switches over mid-play session.
|
||||
watchDirectory() {
|
||||
watchDirectory(): void {
|
||||
const watcher = chokidar.watch(this.journalPattern, {usePolling: true, persistent: true})
|
||||
|
||||
watcher.on('add', newFile => this.currentJournal = this.getLatestJournal())
|
||||
watcher.on('add', () => this.currentJournal = this.getLatestJournal())
|
||||
|
||||
log('Watching journal folder for changes...')
|
||||
}
|
||||
|
@ -170,22 +173,22 @@ export class JournalInterface extends EventEmitter {
|
|||
/* ----------------------------------------------------------------------- parseScanLine ---- */
|
||||
|
||||
// Parse and handle scan lines.
|
||||
parseScanLine(line, DSS = false) {
|
||||
const dupChecker = {'BodyName': line.BodyName, 'BodyID': line.bodyID}
|
||||
let body = null
|
||||
parseScanLine(line: autoScan|detailedScan, DSS: boolean = false) {
|
||||
const dupChecker = {'BodyName': line.BodyName, 'BodyID': line.BodyID}
|
||||
let body: Body|null = null
|
||||
|
||||
// If it's a DSS scan, then we should have already added the body to the list. But we'll
|
||||
// check to make sure.
|
||||
if (DSS) {
|
||||
// Using findIndex() rather than find() so we can edit the body if found
|
||||
let bodyIndex = findIndex(this.location.bodies, dupChecker)
|
||||
// Using findIndex() rather than find() so we can edit the body if found.
|
||||
// @ts-ignore since it doesn't understand dupChecker is a valid predicate.
|
||||
let bodyIndex: number = findIndex(this.location.bodies, dupChecker)
|
||||
|
||||
if (bodyIndex > -1) { // Body was found in list, so simply toggle the DSS flag.
|
||||
body = this.location.bodies[bodyIndex]
|
||||
body = (this.location.bodies[bodyIndex] as Body)
|
||||
body.DSSDone = true
|
||||
} else { // Body was missed on initial journal scan, so add it to the list.
|
||||
line.DSSDone = true
|
||||
body = new Body(line)
|
||||
body = new Body(line, true)
|
||||
this.location.bodies.push(body)
|
||||
}
|
||||
|
||||
|
@ -212,14 +215,14 @@ export class JournalInterface extends EventEmitter {
|
|||
/* --------------------------------------------------------------------------- parseLine ---- */
|
||||
|
||||
// Parse and handle journal lines.
|
||||
parseLine(raw) {
|
||||
const line = JSON.parse(raw)
|
||||
let DSSFlag = false
|
||||
parseLine(raw: string) {
|
||||
const line: journalEntry = JSON.parse(raw)
|
||||
let DSSFlag: boolean = false
|
||||
|
||||
switch (line.event) {
|
||||
// CMDR jumped to new system, so update current location.
|
||||
case 'FSDJump': {
|
||||
this.location = new System(line.StarSystem)
|
||||
this.location = new System((line as completeFsdJump).StarSystem)
|
||||
log(`FSD Jump detected, current location updated to ${this.location.name}.`)
|
||||
this.emit('ENTERED_NEW_SYSTEM')
|
||||
break
|
||||
|
@ -235,7 +238,7 @@ export class JournalInterface extends EventEmitter {
|
|||
// A scan occurred, so let's hand that info off to the appropriate function and then
|
||||
// reset the DSS flag.
|
||||
case 'Scan': {
|
||||
this.parseScanLine(line, DSSFlag)
|
||||
this.parseScanLine((line as autoScan|detailedScan), DSSFlag)
|
||||
DSSFlag = false
|
||||
break
|
||||
}
|
||||
|
@ -250,8 +253,8 @@ export class JournalInterface extends EventEmitter {
|
|||
/* ------------------------------------------------------------------------ watchJournal ---- */
|
||||
|
||||
// Watch the journal for changes.
|
||||
watchJournal() {
|
||||
const tail = new Tail(this.currentJournal, {useWatchFile: true})
|
||||
watchJournal(): void {
|
||||
const tail: TailType = new Tail(this.currentJournal, {useWatchFile: true})
|
||||
|
||||
log(`Watching ${path.basename(this.currentJournal)}...`)
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import type { autoScan, detailedScan } from "../@types/journalLines"
|
||||
|
||||
export class Body {
|
||||
constructor(journalLine = null) {
|
||||
this.DSSDone = false
|
||||
DSSDone: boolean
|
||||
|
||||
constructor(journalLine: autoScan|detailedScan|null = null, DSS: boolean = false) {
|
||||
this.DSSDone = DSS
|
||||
|
||||
if (journalLine !== null) {
|
||||
Object.assign(this, journalLine)
|
|
@ -1,5 +1,10 @@
|
|||
import { Body } from "./Body"
|
||||
|
||||
export class System {
|
||||
constructor(StarSystem) {
|
||||
name: string
|
||||
bodies: Body[]
|
||||
|
||||
constructor(StarSystem: string) {
|
||||
// In future, this is where we preform EDSM lookup
|
||||
|
||||
this.name = StarSystem
|
|
@ -55,12 +55,11 @@ journal.watchDirectory()
|
|||
journal.watchJournal()
|
||||
|
||||
const test = {name: 'Test', ID: 'TestID'}
|
||||
console.log(new Body(test))
|
||||
|
||||
/* --------------------------------------------------------------------------- init complete ---- */
|
||||
|
||||
journal.once('INIT_COMPLETE', () => {
|
||||
if (journal.location !== null) {
|
||||
if (journal.location.name !== 'Unknown') {
|
||||
$('#currentSystem')
|
||||
.addClass('charted')
|
||||
.removeClass('highlighted text-center')
|
||||
|
|
6
tsconfig.json
Normal file
6
tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"compilerOptions": {},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
Reference in a new issue