OverviewFilesCommitsIssuesDocsReleasesPeers

cthuloid / webui / lib / app.js

55 lines · javascript ref:
// 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()))
    }
  }
}