const fs = require('fs') const debug = require('debug') const logger = debug('serialport/bindings/unixRead') const { promisify } = require('util') const readAsync = promisify(fs.read) const readable = binding => { return new Promise((resolve, reject) => { binding.poller.once('readable', err => (err ? reject(err) : resolve())) }) } const unixRead = async ({ binding, buffer, offset, length, fsReadAsync = readAsync }) => { logger('Starting read') if (!binding.isOpen) { const err = new Error('Port is not open') err.canceled = true throw err } try { const { bytesRead } = await fsReadAsync(binding.fd, buffer, offset, length, null) if (bytesRead === 0) { return unixRead({ binding, buffer, offset, length, fsReadAsync }) } logger('Finished read', bytesRead, 'bytes') return { bytesRead, buffer } } catch (err) { logger('read error', err) if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') { if (!binding.isOpen) { const err = new Error('Port is not open') err.canceled = true throw err } logger('waiting for readable because of code:', err.code) await readable(binding) return unixRead({ binding, buffer, offset, length, fsReadAsync }) } const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed err.code === 'ENXIO' || // No such device or address probably usb disconnect err.code === 'UNKNOWN' || err.errno === -1 // generic error if (disconnectError) { err.disconnect = true logger('disconnecting', err) } throw err } } module.exports = unixRead