diff --git a/index.js b/index.js index 27ab365..0a2d4df 100644 --- a/index.js +++ b/index.js @@ -213,7 +213,7 @@ class NatAPI { opts.ttl = opts.ttl || this.ttl opts.gateway = opts.gateway || this.gateway - return { opts: opts, cb: cb } + return { opts, cb } } _map (opts, cb) { diff --git a/lib/pmp/index.js b/lib/pmp/index.js index 275caa8..eceded5 100644 --- a/lib/pmp/index.js +++ b/lib/pmp/index.js @@ -175,7 +175,7 @@ class Client extends EventEmitter { // assert.equal(pos, size, 'buffer not fully written!') // Add it to queue - this._queue.push({ buf: buf, cb: cb }) + this._queue.push({ buf, cb }) // Try to send next message this._next() @@ -253,7 +253,7 @@ class Client extends EventEmitter { } const req = this._queue[0] - const parsed = { msg: msg } + const parsed = { msg } parsed.vers = msg.readUInt8(0) parsed.op = msg.readUInt8(1) diff --git a/lib/upnp/device.js b/lib/upnp/device.js index 1bb262f..d98d783 100644 --- a/lib/upnp/device.js +++ b/lib/upnp/device.js @@ -1,6 +1,17 @@ -const request = require('request') const xml2js = require('xml2js') -const url = require('url') + +async function responseToXML (res) { + if (res.status !== 200) { + throw new Error('Request failed: ' + res.status) + } + + const data = await res.text() + const parser = new xml2js.Parser() + + return new Promise((resolve, reject) => { + parser.parseString(data, (err, body) => err ? reject(err) : resolve(body)) + }) +} class Device { constructor (url) { @@ -13,114 +24,80 @@ class Device { } run (action, args, callback) { - const self = this - - this._getService(this.services, function (err, info) { - if (err) return callback(err) - - const body = '' + - '' + - '' + - '' + - args.map((args) => { - return '<' + args[0] + '>' + - (args[1] ? args[1] : '') + - '' - }).join('') + - '' + - '' + - '' - - request({ - method: 'POST', - url: info.controlURL, - headers: { - 'Content-Type': 'text/xml; charset="utf-8"', - 'Content-Length': Buffer.byteLength(body), - Connection: 'close', - SOAPAction: JSON.stringify(info.service + '#' + action) - }, - body: body - }, function (err, res, data) { - if (err) return callback(err) - - if (res.statusCode !== 200) { - return callback(new Error('Request failed: ' + res.statusCode)) - } - - const parser = new xml2js.Parser() - parser.parseString(data, function (err, body) { - if (err) return callback(err) - - const soapns = self._getNamespace( - body, - 'http://schemas.xmlsoap.org/soap/envelope/' - ) - - callback(null, body[soapns + 'Body']) - }) - }) - }) + this.#run(action, args).then( + data => callback(null, data), + err => callback(err) + ) } - _getService (types, callback) { - const self = this - - this._getXml(this.url, function (err, info) { - if (err) return callback(err) - - const s = self._parseDescription(info).services.filter(function (service) { - return types.indexOf(service.serviceType) !== -1 - }) - - // Use the first available service - if (s.length === 0 || !s[0].controlURL || !s[0].SCPDURL) { - return callback(new Error('Service not found')) - } - - const base = new URL(info.baseURL || self.url) - function addPrefix (u) { - let uri - try { - uri = new URL(u) - } catch (err) { - // Is only the path of the URL - uri = new URL(u, base.href) - } - - uri.host = uri.host || base.host - uri.protocol = uri.protocol || base.protocol + async #run (action, args) { + const info = await this.#getService(this.services) + + const body = '' + + '' + + '' + + `` + + args.map((args) => + `<${args[0]}>${args[1] || ''}` + ).join('') + + `` + + '' + + '' + + const xml = await fetch(info.controlURL, { + method: 'POST', + headers: { + 'Content-Type': 'text/xml; charset="utf-8"', + 'SOAPAction': JSON.stringify(info.service + '#' + action) + }, + body + }).then(responseToXML) + + const soapns = this.#getNamespace( + xml, + 'http://schemas.xmlsoap.org/soap/envelope/' + ) + + return xml[soapns + 'Body'] + } - return url.format(uri) - } + async #getService (types) { + const info = await fetch(this.url).then(responseToXML) - callback(null, { - service: s[0].serviceType, - SCPDURL: addPrefix(s[0].SCPDURL), - controlURL: addPrefix(s[0].controlURL) - }) + const s = this.#parseDescription(info).services.filter(function (service) { + return types.indexOf(service.serviceType) !== -1 }) - } - _getXml (url, callback) { - request(url, function (err, res, data) { - if (err) return callback(err) + // Use the first available service + if (s.length === 0 || !s[0].controlURL || !s[0].SCPDURL) { + throw new Error('Service not found') + } - if (res.statusCode !== 200) { - return callback(new Error('Request failed: ', res.statusCode)) + const base = new URL(info.baseURL || this.url) + function addPrefix (u) { + let uri + try { + uri = new URL(u) + } catch (err) { + // Is only the path of the URL + uri = new URL(u, base.href) } - const parser = new xml2js.Parser() - parser.parseString(data, function (err, body) { - if (err) return callback(err) + uri.host = uri.host || base.host + uri.protocol = uri.protocol || base.protocol - callback(null, body) - }) - }) + return uri.toString() + } + + return { + service: s[0].serviceType, + SCPDURL: addPrefix(s[0].SCPDURL), + controlURL: addPrefix(s[0].controlURL) + } } - _parseDescription (info) { + #parseDescription (info) { const services = [] const devices = [] @@ -149,12 +126,12 @@ class Device { traverseDevices(info.device) return { - services: services, - devices: devices + services, + devices } } - _getNamespace (data, uri) { + #getNamespace (data, uri) { let ns if (data['@']) { diff --git a/lib/upnp/ssdp.js b/lib/upnp/ssdp.js index f3fc285..057dbcb 100644 --- a/lib/upnp/ssdp.js +++ b/lib/upnp/ssdp.js @@ -53,7 +53,7 @@ class Ssdp extends EventEmitter { } if (!this._bound) { - this._queue.push({ action: 'search', device: device, promise: promise }) + this._queue.push({ action: 'search', device, promise }) return promise } diff --git a/package.json b/package.json index c6f2362..d2e1591 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "async": "^3.2.0", "debug": "^4.2.0", "default-gateway": "^6.0.2", - "request": "^2.88.2", "unordered-array-remove": "^1.0.2", "xml2js": "^0.1.0" },