-
Notifications
You must be signed in to change notification settings - Fork 30
/
index.js
executable file
·146 lines (127 loc) · 4.86 KB
/
index.js
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#! /usr/bin/env node
const program = require('commander')
const version = require('./package').version
const coap = require('coap')
const request = coap.request
const URI = require('uri-js')
const through = require('through2')
let method = 'GET' // default
const coapOptionSeperator = ','
function collectOptions (val, memo) {
const coapOptionRegex = new RegExp('\\d{1}\\' + coapOptionSeperator + '\\w+')
if (coapOptionRegex.test(val)) {
memo.push(val)
} else {
console.log('Error: Option \'%s\' is invalid.', val)
console.log('Please provide options in this way:')
console.log('-O 2048' + coapOptionSeperator + 'HelloWorld')
console.log('OR --coap-option 2048' + coapOptionSeperator + 'HelloWorld')
process.exit(-1)
}
return memo
}
program
.version(version)
.option('-o, --observe', 'Observe the given resource', false)
.option('-n, --no-new-line', 'No new line at the end of the stream', true)
.option('-p, --payload <payload>', 'The payload for POST and PUT requests')
.option('-b, --block2 <option>', 'set the block2 size option', parseInt)
.option('-q, --quiet', 'Do not print status codes of received packets', false)
.option('-c, --non-confirmable', 'non-confirmable', false)
.option('-t, --timeout <seconds>', 'The maximum send time in seconds')
.option('-T, --show-timing', 'Print request time, handy for simple performance tests', false)
.option('-O, --coap-option <option>', 'Add COAP-Options to the request, e.q. -O 2048,HelloWorld (repeatable)', collectOptions, [])
.option('-C, --content-format <content-format>', 'Include a Content-Format option in the request')
.option('-a, --accept <accept>', 'Include an Accept option in the request')
let inputUrl
;['GET', 'PUT', 'POST', 'DELETE'].forEach(function (name) {
program
.command(name.toLowerCase())
.argument('<url>')
.description('performs a ' + name + ' request')
.action(function (url) {
method = name
inputUrl = url
})
})
program.parse(process.argv)
const url = URI.parse(inputUrl)
if (url.scheme === undefined || url.host === undefined) {
console.log('Invalid URL. Protocol is not given or URL is malformed.')
process.exit(-1)
}
const requestParams = {
method,
observe: program.opts().observe,
confirmable: !program.opts().nonConfirmable,
hostname: url.host,
pathname: url.path,
protocol: url.scheme + ':',
port: url.port,
query: url.query,
accept: program.opts().accept,
contentFormat: program.opts().contentFormat
}
if (requestParams.protocol !== 'coap:' || !requestParams.hostname) {
console.log('Wrong URL. Protocol is not coap or no hostname found.')
process.exit(-1)
}
coap.parameters.exchangeLifetime = program.opts().timeout ? program.opts().timeout : 30
if (program.opts().block2 && (program.opts().block2 < 1 || program.opts().block2 > 6)) {
console.log('Invalid block2 size, valid range [1..6]')
console.log('block2 1: 32 bytes payload, block2 2: 64 bytes payload...')
process.exit(-1)
}
const startTime = new Date()
const req = request(requestParams)
if (program.opts().block2) {
req.setOption('Block2', Buffer.from([program.block2]))
}
if (typeof program.opts().coapOption !== 'undefined' && program.opts().coapOption.length > 0) {
const options = {}
// calling req.setOption() multiple times for the same key will overwrite previous values,
// therefore group options by name/key and add them all at once
program.opts().coapOption.forEach(function (singleOption) {
const i = singleOption.indexOf(coapOptionSeperator)
const key = singleOption.slice(0, i)
const value = singleOption.slice(i + 1)
const valueBuffer = value.startsWith('0x') ? Buffer.from(value.substring(2), 'hex') : Buffer.from(value)
if (!Object.prototype.hasOwnProperty.call(options, key)) options[key] = []
options[key].push(valueBuffer)
})
Object.entries(options).forEach(([key, values]) => {
req.setOption(key, values)
})
}
req.on('response', function (res) {
const endTime = new Date()
if (program.opts().showTiming) {
console.log('Request took ' + (endTime.getTime() - startTime.getTime()) + ' ms')
}
// print only status code on empty response
if (!res.payload.length && !program.opts().quiet) {
process.stderr.write('\x1b[1m(' + res.code + ')\x1b[0m\n')
}
res.pipe(through(function addNewLine (chunk, enc, callback) {
if (!program.opts().quiet) {
process.stderr.write('\x1b[1m(' + res.code + ')\x1b[0m\t')
}
if (program.opts().newLine && chunk) {
chunk = chunk.toString('utf-8') + '\n'
}
this.push(chunk)
callback()
})).pipe(process.stdout)
// needed because of some weird issue with
// empty responses and streams
if (!res.payload.length) {
process.exit(0)
}
})
if (method === 'GET' || method === 'DELETE' || program.opts().payload) {
req.end(program.opts().payload)
} else if (!process.stdin.isTTY) {
process.stdin.pipe(req)
} else {
req.end()
}