forked from bitfocus/companion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
executable file
·197 lines (168 loc) · 6.04 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env node
// Setup some fixes before loading any imports
import './lib/Util/FixImports.js'
// Setup logging before anything else runs
import './lib/Log/Controller.js'
// Now we can think about startup
import { Command } from 'commander'
import Registry from './lib/Registry.js'
import os from 'os'
import path from 'path'
import fs from 'fs-extra'
import envPaths from 'env-paths'
import { nanoid } from 'nanoid'
import logger from './lib/Log/Controller.js'
import { ConfigReleaseDirs } from './launcher/Paths.cjs'
const program = new Command()
program.command('check-launches', { hidden: true }).action(() => {
// This is a 'test' command used to make sure builds are able to run
console.log('It launches!')
process.exit(89)
})
program
.option('--list-interfaces', 'List the available network interfaces that can be passed to --admin-interface')
.option('--admin-port <number>', 'Set the port the admin ui should bind to', 8000)
.option(
'--admin-interface <string>',
'Set the interface the admin ui should bind to. The first ip on this interface will be used'
)
.option('--admin-address <string>', 'Set the ip address the admin ui should bind to (default: "0.0.0.0")')
.option(
'--config-dir <string>',
'Use the specified directory for storing configuration. The default path varies by system, and is different to 2.2 (the old path will be used if existing config is found)'
)
.option('--extra-module-path <string>', 'Search an extra directory for modules to load')
.option('--machine-id <string>', 'Unique id for this installation')
.option('--log-level <string>', 'Log level to output to console')
program.command('start', { isDefault: true, hidden: true }).action(() => {
const options = program.opts()
if (options.listInterfaces) {
console.error('Available Interfaces:')
const interfaces = os.networkInterfaces()
for (const [ifname, ifgroup] of Object.entries(interfaces)) {
for (const ifAddr of ifgroup) {
// onlt show non-ipv4 addresses for now
if ('IPv4' === ifAddr.family) {
console.error(ifname, ifAddr.address)
}
}
}
process.exit(0)
}
logger.logger.info('Application starting')
if (isNaN(options.adminPort)) {
console.error(`Port number is not valid`)
process.exit(1)
}
if (options.adminAddress && options.adminInterface) {
console.error(`Only one of admin-interface and admin-address can be specified`)
process.exit(1)
}
let adminIp = options.adminAddress || '0.0.0.0' // default to admin global
if (options.adminInterface) {
adminIp = null
const interfaceInfo = os.networkInterfaces()[options.adminInterface]
if (interfaceInfo) {
for (const ifAddr of interfaceInfo) {
// only show non-ipv4 addresses for now
if ('IPv4' === ifAddr.family) {
adminIp = ifAddr.address
break
}
}
}
if (!adminIp) {
console.error(`Invalid interface name "${options.adminInterface}"`)
process.exit(1)
}
}
let configDir = options.configDir
if (!configDir) {
// Check the old location first
configDir = path.join(process.env[process.platform == 'win32' ? 'USERPROFILE' : 'HOME'], 'companion')
if (!fs.pathExistsSync(configDir)) {
// Creating a new folder, so use the proper place
const paths = envPaths('companion')
configDir = paths.config
}
}
// some files are always in the root configDir
const machineIdPath = path.join(configDir, 'machid')
const readmePath = path.join(configDir, 'README.txt')
// Handle the rename from `develop` to `v3.0`, setting up a link for backwards compatibility
const developDir = path.join(configDir, 'develop')
const v30Dir = path.join(configDir, 'v3.0')
if (fs.existsSync(developDir) && !fs.existsSync(v30Dir)) {
fs.moveSync(developDir, v30Dir)
fs.symlinkSync(v30Dir, developDir, process.platform === 'win32' ? 'junction' : undefined)
}
// develop should use subfolder. This should be disabled when ready for mass testing
const rootConfigDir = configDir
configDir = path.join(configDir, ConfigReleaseDirs[ConfigReleaseDirs.length - 1])
try {
fs.ensureDirSync(configDir)
} catch (e) {
console.error(`Failed to create config directory. Do you have the correct permissions?`)
process.exit(1)
}
// Make sure README file exists in the config dir
if (!fs.existsSync(readmePath)) {
fs.writeFileSync(
readmePath,
'Since Companion 3.0, each release your config gets put into a new folder.\n' +
'This makes it much easier and safer to downgrade to older releases, as their configuration will be left untouched.\n' +
"When launching a version whose folder doesn't yet exist, the config will be copied from one of the previous releases, looking in release order.\n" +
'\n' +
'The db file in this folder is used for 2.4 or older, use the appropriate folders for newer configs\n'
)
}
// copy an older db if needed
if (configDir !== rootConfigDir && !fs.existsSync(path.join(configDir, 'db'))) {
// try and import the non-develop copy. we only need to take `db` for this
for (let i = ConfigReleaseDirs.length - 1; i--; i >= 0) {
const previousDbPath =
i > 0 ? path.join(rootConfigDir, ConfigReleaseDirs[i], 'db') : path.join(rootConfigDir, 'db')
if (fs.existsSync(previousDbPath)) {
// Found the one to copy
fs.copyFileSync(previousDbPath, path.join(configDir, 'db'))
break
}
}
}
if (options.logLevel) {
logger.setLogLevel(options.logLevel)
}
let machineId = options.machineId
if (!machineId) {
// Use stored value
if (fs.pathExistsSync(machineIdPath)) {
let text = ''
try {
text = fs.readFileSync(machineIdPath)
if (text) {
machineId = text.toString()
}
} catch (e) {
console.warn(`Error reading machid file: ${e}`)
}
} else {
machineId = nanoid()
try {
fs.writeFileSync(machineIdPath, machineId)
} catch (e) {
console.warn(`Error writing machid file: ${e}`)
}
}
}
const registry = new Registry(configDir, machineId)
registry
.ready(options.extraModulePath, adminIp, options.adminPort)
.then(() => {
console.log('Started')
})
.catch((e) => {
console.error(`Startup failed: ${e} ${e.stack}`)
process.exit(1)
})
})
program.parse()