-
-
Notifications
You must be signed in to change notification settings - Fork 36
/
unix-read.ts
71 lines (63 loc) · 2.11 KB
/
unix-read.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { promisify } from 'util'
import { read as fsRead } from 'fs'
import { BindingsError } from './errors'
import debugFactory from 'debug'
import { LinuxPortBinding } from './linux'
import { DarwinPortBinding } from './darwin'
const logger = debugFactory('serialport/bindings-cpp/unixRead')
const readAsync = promisify(fsRead)
const readable = (binding: LinuxPortBinding | DarwinPortBinding) => {
return new Promise<void>((resolve, reject) => {
if (!binding.poller) {
throw new Error('No poller on bindings')
}
binding.poller.once('readable', err => (err ? reject(err) : resolve()))
})
}
interface UnixReadOptions {
binding: LinuxPortBinding | DarwinPortBinding
buffer: Buffer
offset: number
length: number
fsReadAsync?: typeof readAsync
}
export const unixRead = async ({
binding,
buffer,
offset,
length,
fsReadAsync = readAsync,
}: UnixReadOptions): Promise<{ buffer: Buffer; bytesRead: number }> => {
logger('Starting read')
if (!binding.isOpen || !binding.fd) {
throw new BindingsError('Port is not open', { canceled: true })
}
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) {
throw new BindingsError('Port is not open', { canceled: true })
}
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
}
}