node.jsverceldat-protocolvercel-micro

How to run dat-node as a micro service?


UPDATE: Added the full server code. Notice that the route for static content is working fine, only the one relative to Dat fails. Also, I'm running node 10.8.0 with no transpiler or anything, server is ran with micro -l tcp://0.0.0.0:$PORT


I'm trying to run dat-node with Zeit micro. I have this micro service

const { send } = require('micro')
const Dat = require('dat-node')
const handler = require('serve-handler')
const { router, get, post } = require('microrouter')

const static = async (request, response) => {
  await handler(request, response, {
  // static app folder
  public: 'static',
    // javascript header for es modules
    headers: {
      source: '**/*.mjs',
      headers: [{
        key: 'Content-Type',
        value: 'text/javascript'
      }]
    },
    // no directory listing
    directoryListing: false
  })
}

const createGame = (request, response) => {
  Dat('./game', (err, dat) => {
    if (err) throw err

    let progress = dat.importFiles({watch: true})

    progress.on('put', function (src, dest) {
      console.log('Importing ', src.name, ' into archive')
    })

    dat.joinNetwork()

    send(response, 200, { key: dat.key.toString('hex') })
  })
}

const joinGame = (request, response) => {

}

module.exports = router(
  post('/game', createGame),
  post('/game/:game', joinGame),
  get('/*', static)
)

I just want to create a dat archive and return the public key, but when I call send I get this error

(node:2054) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:469:11)
    at send (/home/ubuntu/workspace/node_modules/micro/lib/index.js:72:8)
    at Dat (/home/ubuntu/workspace/index.js:35:5)
    at /home/ubuntu/workspace/node_modules/dat-node/index.js:112:9
    at apply (/home/ubuntu/workspace/node_modules/thunky/index.js:44:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)(node:2054) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)(node:2054) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

So, I'm not sure where the header is being sent, maybe I'm just handling Dat callback in a wrong way? not sure how to implement this service.


Solution

  • The issue appears to be the usage of micro, not any issue with dat-node. When you are doing async work in micro, you need to use the async/await tools of Javascript (promises).

    Here is the fixed code:

    const createGame = async (request, response) => {
      var key = await new Promise((resolve) => {
        Dat('./game', (err, dat) => {
          if (err) throw err
    
          let progress = dat.importFiles({watch: true})
    
          progress.on('put', function (src, dest) {
            console.log('Importing ', src.name, ' into archive')
          })
    
          dat.joinNetwork()
          resolve(dat.key.toString('hex'))
        })
      })
      console.log('sending')
      send(response, 200, { key })
    }