Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.env
tracker.json
node_modules
dist/
dist/
tkrcfg.json
5 changes: 5 additions & 0 deletions src/exceptions/InvalidHTConfigException.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default class InvalidHTConfigException extends Error {
constructor() {
super('Invalid HTConfig file!')
}
}
5 changes: 5 additions & 0 deletions src/exceptions/NotImplementedException.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default class NotImplementedException extends Error {
constructor() {
super('Method is not implemented')
}
}
58 changes: 39 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,62 @@ import gameCheck from './checks/game.check.js'
import { init, serializeDbToDisk } from './utils/db2.js'
import cron from 'node-cron'

const timeoutTime = parseInt((process.env.TIMEOUT_TIME as string))
import getConfig from './utils/config-parser.js'

const { config } = await getConfig()

const timeoutTime = config.timeoutMs
let cycle = 0

debug('HypeTrack started on %s.', new Date())
// TODO: Web and Mesa.

// Initialize DB2.
await init()
await serializeDbToDisk() // Initially serialize a copy of the database to disk.
// Initialize DB2 if config says to do so.
config.db2.initializeOnBoot && await init()

// This cron job serializes the database to disk every five minutes.
cron.schedule('*/5 * * * *', async () => {
await serializeDbToDisk()
})
if (config.db2.serializeOnBoot) {
await serializeDbToDisk() // Initially serialize a copy of the database to disk.
}

if (typeof config.db2.serializeCronString === 'string') {
// This cron job serializes the database to disk every five minutes.
cron.schedule(config.db2.serializeCronString, async () => {
await serializeDbToDisk()
})
}

// This detects interrupts, and will serialize the DB to disk before breaking.
// TODO: I don't think this works on Windows.
process.on('SIGINT', async () => {
console.log('Interrupt caught! Serializing database to disk.')
await serializeDbToDisk()
console.log('Interrupt caught!')
if (config.db2.serializeOnInterrupt) {
console.log('Serializing database to disk')
await serializeDbToDisk()
}
process.exit(0)
})

// TODO: Have a way to have this dynamically expandable.
// TODO: Figure out what needs priority here.
const commonChecks = config.checks.filter(check => check.type === 'common')
const streamChecks = config.checks.filter(check => check.type === 'stream')
const gameChecks = config.checks.filter(check => check.type === 'game')

let checkCount = 0;
[commonChecks, streamChecks, gameChecks].forEach(checks => checkCount += checks.length)
debug('Starting %d checks.', checkCount)
setInterval(async () => {
debug('We\'re on check cycle %d.', cycle)
await commonCheck('https://api.prod.hype.space', 'hypeapi')
await commonCheck('https://ws.prod.hype.space', 'hypeapi-websocket')
await commonCheck('https://telemetry.prod.hype.space', 'api-telemetry')

await streamCheck('internet_high')
await streamCheck('intranet_high')
await streamCheck('wirecast_high')
for (const check of commonChecks) {
await commonCheck(check.params[0], check.params[1])
}

for (const check of streamChecks) {
await streamCheck(check.params[0])
}

typeof process.env.HQ_TOKEN !== 'undefined' && await gameCheck()
if (gameChecks.length > 0) {
await gameCheck()
}

// Increment cycle
debug('Cycle %d ended.', cycle)
Expand Down
10 changes: 10 additions & 0 deletions src/types/HTCheck.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { type HTCheckType } from "./HTCheckType.type"

export type HTCheck = {
/** Type of check */
type: HTCheckType,

/** Params to pass to the check method. */
// rome-ignore lint/suspicious/noExplicitAny: Types can be anything on this, honestly. Too lazy to give it explicit types.
params: any[]
}
4 changes: 4 additions & 0 deletions src/types/HTCheckType.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type HTCheckType =
| 'common'
| 'stream'
| 'game'
12 changes: 12 additions & 0 deletions src/types/HTConfig.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type HTDB2Config } from "./HTDB2Config.type"
import { type HTCheck } from "./HTCheck.type"
export type HTConfig = {
/** Options to configure DB2 (the in-memory database) */
db2: HTDB2Config

/** The time to wait between checks. */
timeoutMs: number,

/** Configured checks to run. */
checks: HTCheck[]
}
9 changes: 9 additions & 0 deletions src/types/HTConfigFile.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type HTConfig } from './HTConfig.type'

export type HTConfigFile = {
/** Schema version */
__v: number,

/** Config root */
config: HTConfig
}
13 changes: 13 additions & 0 deletions src/types/HTDB2Config.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export type HTDB2Config = {
/** Whether or not the database should be initialized on start of tracker. */
initializeOnBoot: boolean

/** Whether or not to serialize the database to disk when the program starts */
serializeOnBoot: boolean

/** Cron string to determine how often the database gets serialized to disk. */
serializeCronString: string

/** Whether or not to serialize the DB to disk on interrupt. */
serializeOnInterrupt: boolean
}
31 changes: 31 additions & 0 deletions src/utils/config-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import fs from 'node:fs/promises'
import InvalidHTConfigException from '../exceptions/InvalidHTConfigException'
import { type HTConfigFile } from '../types/HTConfigFile.type'

let config: HTConfigFile

export default async function getConfigFile (fileName: string = "tkrcfg.json") {
if (config) {
return config
}

// Open file.
const file = await fs.open(fileName, 'r')

// Read file.
const fileContents = await file.readFile()

// Parse file.
const parsedFile = JSON.parse(fileContents.toString()) as HTConfigFile

// Check if file is valid.
if (!parsedFile) {
throw new InvalidHTConfigException()
}

// Save config.
config = parsedFile

// Return json.
return parsedFile
}
49 changes: 49 additions & 0 deletions tkrcfg.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"__v": 1,
"config": {
"db2": {
"serializeOnBoot": true,
"serializeCronString": "*/5 * * * *"
},
"timeoutMs": 5000,
"checks": [
{
"type": "common",
"params": [
"api.prod.hype.space",
"hypeapi"
]
},
{
"type": "common",
"params": [
"ws.prod.hype.space",
"hypeapi-websocket"
]
},
{
"type": "common",
"params": [
"telemetry.prod.hype.space",
"api-telemetry"
]
},
{
"type": "stream",
"params": ["internet_high"]
},
{
"type": "stream",
"params": ["intranet_high"]
},
{
"type": "stream",
"params": ["wirecast_high"]
},
{
"type": "game",
"params": []
}
]
}
}