Skip to content

Commit

Permalink
fix: import from old config file on each startup, as an editable over…
Browse files Browse the repository at this point in the history
…rides
  • Loading branch information
Julusian committed Feb 5, 2024
1 parent b38db50 commit 01eef76
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 16 deletions.
14 changes: 11 additions & 3 deletions pi-image/satellite-config
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#
# Since v1.7.0 of satellite this is no longer the main config file.
# It is read at startup to import configuration to the main config file.
# After it has been read, it gets reset back to defaults.
#
# More options are available in the web interface.
#

# Set this to the ip address or hostname of your companion installation
# examples:
# - COMPANION_IP=192.168.100.1
# - COMPANION_IP=companion.example.org
COMPANION_IP=127.0.0.1
# COMPANION_IP=127.0.0.1

# If you are connecting through a router or firewall which has remapped the port, you will need to change that here to match
COMPANION_PORT=16622
# COMPANION_PORT=16622

# Port for the REST server (0 to disable)
REST_PORT=9999
# REST_PORT=9999
3 changes: 2 additions & 1 deletion pi-image/satellite.service
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Wants=network-online.target
Type=simple
User=satellite
WorkingDirectory=/usr/local/src/companion-satellite
ExecStart=/opt/fnm/aliases/default/bin/node /usr/local/src/companion-satellite/dist/main.js
ExecStartPre=+/opt/fnm/aliases/default/bin/node /usr/local/src/companion-satellite/dist/fixup-pi-config.js /home/satellite/satellite-config.json
ExecStart=/opt/fnm/aliases/default/bin/node /usr/local/src/companion-satellite/dist/main.js /home/satellite/satellite-config.json
Restart=on-failure
KillSignal=SIGINT
TimeoutStopSec=60
Expand Down
14 changes: 14 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Conf, { Schema } from 'conf'
import path from 'path'

export interface SatelliteConfig {
remoteIp: string
Expand Down Expand Up @@ -44,3 +45,16 @@ export function ensureFieldsPopulated(store: Conf<SatelliteConfig>): void {
}
}
}

export function openHeadlessConfig(rawConfigPath: string): Conf<SatelliteConfig> {
const absoluteConfigPath = path.isAbsolute(rawConfigPath) ? rawConfigPath : path.join(process.cwd(), rawConfigPath)

const appConfig = new Conf<SatelliteConfig>({
schema: satelliteConfigSchema,
configName: path.parse(absoluteConfigPath).name,
projectName: 'companion-satellite',
cwd: path.dirname(absoluteConfigPath),
})
ensureFieldsPopulated(appConfig)
return appConfig
}
98 changes: 98 additions & 0 deletions src/fixup-pi-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* This is a small pre-launch step that gets run on SatellitePi.
* It's purpose is to import user defined overrides from the 'boot' partition
* Note: This gets run as root!
*/

import { stat, readFile, copyFile, chown } from 'fs/promises'
import { openHeadlessConfig } from './config'
import path from 'path'

const configFilePath = process.argv[2]
if (!configFilePath) throw new Error(`Missing config file path parameter`)

const appConfig = openHeadlessConfig(configFilePath)

// Ensure the satellite user owns the file. This is a bit dodgey guessing the ids like this..
chown(appConfig.path, 1000, 1000).catch(() => null)

const templatePathName = path.join(__dirname, '../pi-image/satellite-config')

const importFromPaths = [
// Paths to search for a config file to 'import' from
'/boot/satellite-config',
'/boot/firmware/satellite-config',
'/satellite-config',
// templatePathName, // For testing
]

Promise.resolve()
.then(async () => {
for (const importPath of importFromPaths) {
try {
const fileStat = await stat(importPath)
if (!fileStat.isFile()) throw new Error('Not a file')

const fileContentStr = await readFile(importPath)
const lines = fileContentStr.toString().split('\n')

console.log(`Importing config from ${importPath}`)

for (let line of lines) {
line = line.trim()

// Ignore any comments
if (line.startsWith('#')) continue

const splitIndex = line.indexOf('=')
if (splitIndex == -1) continue

const key = line.slice(0, splitIndex).trim()
const value = line.slice(splitIndex + 1).trim()

switch (key.toUpperCase()) {
case 'COMPANION_IP':
appConfig.set('remoteIp', value)
break
case 'COMPANION_PORT': {
const port = Number(value)
if (isNaN(port)) {
console.log('COMPANION_PORT is not a number!')
break
}
appConfig.set('remotePort', port)
break
}
case 'REST_PORT': {
const port = Number(value)
if (isNaN(port)) {
console.log('REST_PORT is not a number!')
break
}
if (port > 0) {
appConfig.set('restPort', port)
appConfig.set('restEnabled', true)
} else {
appConfig.set('restEnabled', false)
}
break
}
default:
console.log(`Unknown value: ${key}=${value}`)
break
}
}

if (templatePathName !== importPath) {
await copyFile(templatePathName, importPath)
}
} catch (e: any) {
if (e.code === 'ENOENT') continue
// Failed, try next file
console.log(`Unable to import from file "${importPath}"`, e)
}
}
})
.catch(() => {
// Ignore
})
14 changes: 2 additions & 12 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import meow from 'meow'
import { CompanionSatelliteClient } from './client'
import { DeviceManager } from './devices'
import { DEFAULT_PORT } from './lib'
import Conf from 'conf'
import path from 'path'
import { RestServer } from './rest'
import { SatelliteConfig, ensureFieldsPopulated, satelliteConfigSchema } from './config'
import { openHeadlessConfig } from './config'

const cli = meow(
`
Expand All @@ -25,15 +23,7 @@ if (cli.input.length === 0) {
}

const rawConfigPath = cli.input[0]
const absoluteConfigPath = path.isAbsolute(rawConfigPath) ? rawConfigPath : path.join(process.cwd(), rawConfigPath)

const appConfig = new Conf<SatelliteConfig>({
schema: satelliteConfigSchema,
configName: path.parse(absoluteConfigPath).name,
projectName: 'companion-satellite',
cwd: path.dirname(absoluteConfigPath),
})
ensureFieldsPopulated(appConfig)
const appConfig = openHeadlessConfig(rawConfigPath)

console.log('Starting', appConfig.path)

Expand Down

0 comments on commit 01eef76

Please sign in to comment.