1

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.

Jonas
  • 121,568
  • 97
  • 310
  • 388
Yerko Palma
  • 12,041
  • 5
  • 33
  • 57
  • Does it work if you just send an empty response (without the key)? Or maybe if you remove the `async` in the callback, it may not be necessary with the code you have. – joehand Aug 08 '18 at 16:22
  • @joehand If I remove the `async` keyword, I get the same error, but this time the server process is killed, with the snippet as is, the exception is logged, but the server keeps running – Yerko Palma Aug 08 '18 at 17:09

2 Answers2

2

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 })
}
Paul Frazee
  • 243
  • 1
  • 4
  • Totally right. I used node promisify function to write `const dat = await Dat('./game')`, which is actually the same as you wrote. Thanks :) – Yerko Palma Aug 09 '18 at 13:26
1

The snippet works if you export the function. Run with micro whatever.js and curl to localhost:3000 which should return the key.

const { send } = require('micro')
const Dat = require('dat-node')

module.exports = (request, response) => {
  Dat('./game', async (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') })
 })
}
aafrey
  • 21
  • 2