/ src / server / app.js
app.js
  1  import { config, readConfigs } from './configParser.js'
  2  import Kefir from 'kefir'
  3  import express from 'express'
  4  import cors from 'cors'
  5  import path from 'path'
  6  import { Server } from 'socket.io'
  7  import socketProtector from './safetySocks.js'
  8  import chalk from 'chalk'
  9  
 10  import dctrlDb from './dctrlDb.js'
 11  import state from './state.js'
 12  import reactions from './reactions.js'
 13  import auth from './auth.js'
 14  import exchangeRate from './exchangeRate.js'
 15  import rent from './rent.js'
 16  import link from './link.js'
 17  import lightning from './lightning.js'
 18  import applyRouter from './router.js'
 19  //import connector from './connector.js'
 20  
 21  // Okay, what's happening here in callback hell!?
 22  //
 23  // First, we load the config as defined mostly
 24  // in the .ao directory - see configParser
 25  //
 26  // Next, we apply the router as defined in
 27  // 'router.js', which defines some post endpoints
 28  // and redirects all GET to the index.html
 29  //
 30  // Finally, we begin the complex process of 
 31  // "starting the AO". 
 32  //
 33  // "Starting the AO" first consists of establishing
 34  // a connection to the database and reading all of
 35  // the logged events to generate the current 
 36  // application state.
 37  //
 38  // Afterwards, a few plugins are loaded and then
 39  // the db is set up to listen for changes and 
 40  // apply them to the application state.
 41  //
 42  // The last step is configuring the server to
 43  // listen on the given port (default 8003) and
 44  // accept websocket connections.
 45  //
 46  // Whenever an event is received from the changefeed
 47  // (or shadowfeed?), it is both applied to the application
 48  // state and sent to all clients via websocket. Finally, 
 49  // it is sent to the 'reactions' library to see if anything
 50  // needs to be done in response to this particular event:
 51  // doors opened, payments processed etc.
 52  
 53  
 54  // ~ Reimplementation with nostr relays ~
 55  //
 56  // Read the config. Apply the router.
 57  //
 58  // For the AO itself, all data will be stored
 59  // on the relay. The AO server will maintain
 60  // application state, listen for changes from
 61  // the relay and process / verify any reactions
 62  //
 63  // Relay will manage event propagation and clients
 64  // will open up a socket directly to the relay
 65  // instead of to the AO. A request can be made
 66  // to SOLAR for logging in, returning the nsec
 67  // to be used for signing, etc.
 68  
 69  
 70  
 71  readConfigs(() => {
 72      const app = express()
 73      app.use(cors())
 74  
 75      applyRouter(app)
 76      startDctrlAo()
 77      
 78      function startDctrlAo(){
 79          dctrlDb.startDb( (err, conn) => {
 80              if (err) return console.log(chalk.bold.red('db initialize failed:', err))
 81      
 82              let start = Date.now()
 83              state.initialize( err => {
 84                if (err) return console.log(chalk.bold.red('ao state initialization failed:'), err)
 85                exchangeRate.watchSpot()
 86                lightning.initClient(config)
 87                lightning.stormWallet()
 88                lightning.recordEveryInvoice(state.serverState.cash.pay_index)
 89                lightning.watchOnChain()
 90                // rent()
 91                // link()
 92      
 93                dctrlDb.changeFeed
 94                    .onValue( ev => state.applyEvent(state.serverState, ev))
 95  
 96                /*
 97                TODO: The next major change to AO-Z is building it to work with
 98                nostr relays. Initially, these means using a relay as the database.
 99  	      The complexity of AO having hardware/lightning interactions means
100  	      that we will need to maintain a "server".
101  
102  	      futr2 works alright, but strfry is a much better maintained system
103  	      written in a more robust language. 
104                */
105      
106                const server = app.listen(config.port, err => {
107                    console.log(chalk.blue.bold("http://localhost:" + config.port))
108                    const io = new Server(server, {
109                      cors: { 
110                          // Only really needed for dev
111                          origin: '*'
112                      }
113                    })
114                    socketProtector(io, {
115                        authenticate: auth.socketAuth,
116                        timeout: 2345,
117                    })
118                    Kefir.merge([
119                        dctrlDb.changeFeed.map(state.removeSensitive),
120                        dctrlDb.shadowFeed
121                    ]).onValue( ev => {
122                        state.applyEvent(state.pubState, ev)
123                        io.emit('eventstream', ev)
124                        console.log("def happened:", ev) 
125                    }).onValue(reactions)
126                })
127              })
128          })
129      }
130  })
131  
132  export default readConfigs