// The controller as a library: store + rig + HTTP server, started and stopped as
// one. stortron's index.js and the Android app's worklet both start it here, so
// the phone runs exactly the code stortron runs.
//
// Deliberately imports NO discovery: the Linux one spawns avahi-browse through
// bare-subprocess, which a phone has neither of. The caller passes its own --
// avahi on a desktop, Android's NsdManager over IPC in the app -- or none, and
// units are added by address.
import EventEmitter from 'bare-events'
import { Store } from './store.js'
import { Rig } from './rig.js'
import { createServer } from './server.js'
// No automatic discovery: present, quiet, never "broken".
class NoDiscovery extends EventEmitter {
constructor () {
super()
this.available = true
this.reason = ''
}
start () {}
stop () {}
}
// assets: embedded page files (scripts/gen-assets.js) for a packed bundle; null
// reads static/ from disk.
export function createApp ({ configDir, host = '127.0.0.1', port = 4050, discovery = null, assets = null, rigOpts = {} }) {
const store = new Store(configDir)
const rig = new Rig({ store, discovery: discovery || new NoDiscovery(), ...rigOpts })
const server = createServer(rig, { assets })
let started = false
return {
rig,
server,
listen () {
if (!started) { rig.start(); started = true }
return new Promise((resolve, reject) => {
server.once('error', reject)
server.listen(port, host, () => {
server.off('error', reject)
resolve({ host, port: server.address().port })
})
})
},
close () {
if (started) rig.stop() // flushes the debounced config save
started = false
return new Promise((resolve) => server.close(() => resolve()))
}
}
}