@xmpp/connection
Advanced tools
Comparing version 0.11.0 to 0.12.0
368
index.js
@@ -1,31 +0,31 @@ | ||
'use strict' | ||
"use strict"; | ||
const {EventEmitter, promise} = require('@xmpp/events') | ||
const jid = require('@xmpp/jid') | ||
const xml = require('@xmpp/xml') | ||
const StreamError = require('./lib/StreamError') | ||
const {parseHost, parseService} = require('./lib/util') | ||
const { EventEmitter, promise } = require("@xmpp/events"); | ||
const jid = require("@xmpp/jid"); | ||
const xml = require("@xmpp/xml"); | ||
const StreamError = require("./lib/StreamError"); | ||
const { parseHost, parseService } = require("./lib/util"); | ||
const NS_STREAM = 'urn:ietf:params:xml:ns:xmpp-streams' | ||
const NS_JABBER_STREAM = 'http://etherx.jabber.org/streams' | ||
const NS_STREAM = "urn:ietf:params:xml:ns:xmpp-streams"; | ||
const NS_JABBER_STREAM = "http://etherx.jabber.org/streams"; | ||
class Connection extends EventEmitter { | ||
constructor(options = {}) { | ||
super() | ||
this.jid = null | ||
this.timeout = 2000 | ||
this.options = options | ||
this.socketListeners = Object.create(null) | ||
this.parserListeners = Object.create(null) | ||
this.status = 'offline' | ||
this.socket = null | ||
this.parser = null | ||
this.root = null | ||
super(); | ||
this.jid = null; | ||
this.timeout = 2000; | ||
this.options = options; | ||
this.socketListeners = Object.create(null); | ||
this.parserListeners = Object.create(null); | ||
this.status = "offline"; | ||
this.socket = null; | ||
this.parser = null; | ||
this.root = null; | ||
} | ||
_reset() { | ||
this.jid = null | ||
this.status = 'offline' | ||
this._detachSocket() | ||
this._detachParser() | ||
this.jid = null; | ||
this.status = "offline"; | ||
this._detachSocket(); | ||
this._detachParser(); | ||
} | ||
@@ -39,14 +39,13 @@ | ||
xml(condition, {xmlns: NS_STREAM}, children), | ||
]) | ||
) | ||
// eslint-disable-next-line no-unused-vars | ||
} catch (err) {} | ||
]), | ||
); | ||
} catch {} | ||
return this._end() | ||
return this._end(); | ||
} | ||
_onData(data) { | ||
const str = data.toString('utf8') | ||
this.emit('input', str) | ||
this.parser.write(str) | ||
const str = data.toString("utf8"); | ||
this.emit("input", str); | ||
this.parser.write(str); | ||
} | ||
@@ -59,51 +58,51 @@ | ||
// and <unsupported-encoding/>. However, the more specific errors are RECOMMENDED." | ||
this._streamError('bad-format') | ||
this._detachParser() | ||
this.emit('error', error) | ||
this._streamError("bad-format"); | ||
this._detachParser(); | ||
this.emit("error", error); | ||
} | ||
_attachSocket(socket) { | ||
const sock = (this.socket = socket) | ||
const listeners = this.socketListeners | ||
this.socket = socket; | ||
const listeners = this.socketListeners; | ||
listeners.data = this._onData.bind(this) | ||
listeners.data = this._onData.bind(this); | ||
listeners.close = (dirty, event) => { | ||
this._reset() | ||
this._status('disconnect', {clean: !dirty, event}) | ||
} | ||
this._reset(); | ||
this._status("disconnect", { clean: !dirty, event }); | ||
}; | ||
listeners.connect = () => { | ||
this._status('connect') | ||
} | ||
this._status("connect"); | ||
}; | ||
listeners.error = error => { | ||
this.emit('error', error) | ||
} | ||
listeners.error = (error) => { | ||
this.emit("error", error); | ||
}; | ||
sock.on('close', listeners.close) | ||
sock.on('data', listeners.data) | ||
sock.on('error', listeners.error) | ||
sock.on('connect', listeners.connect) | ||
this.socket.on("close", listeners.close); | ||
this.socket.on("data", listeners.data); | ||
this.socket.on("error", listeners.error); | ||
this.socket.on("connect", listeners.connect); | ||
} | ||
_detachSocket() { | ||
const {socketListeners, socket} = this | ||
Object.getOwnPropertyNames(socketListeners).forEach(k => { | ||
socket.removeListener(k, socketListeners[k]) | ||
delete socketListeners[k] | ||
}) | ||
this.socket = null | ||
return socket | ||
const { socketListeners, socket } = this; | ||
Object.getOwnPropertyNames(socketListeners).forEach((k) => { | ||
socket.removeListener(k, socketListeners[k]); | ||
delete socketListeners[k]; | ||
}); | ||
this.socket = null; | ||
return socket; | ||
} | ||
_onElement(element) { | ||
const isStreamError = element.is('error', NS_JABBER_STREAM) | ||
const isStreamError = element.is("error", NS_JABBER_STREAM); | ||
if (isStreamError) { | ||
this._onStreamError(element) | ||
this._onStreamError(element); | ||
} | ||
this.emit('element', element) | ||
this.emit(this.isStanza(element) ? 'stanza' : 'nonza', element) | ||
this.emit("element", element); | ||
this.emit(this.isStanza(element) ? "stanza" : "nonza", element); | ||
@@ -113,3 +112,3 @@ if (isStreamError) { | ||
// "The entity that receives the stream error then SHALL close the stream" | ||
this._end() | ||
this._end(); | ||
} | ||
@@ -120,9 +119,9 @@ } | ||
_onStreamError(element) { | ||
const error = StreamError.fromElement(element) | ||
const error = StreamError.fromElement(element); | ||
if (error.condition === 'see-other-host') { | ||
return this._onSeeOtherHost(error) | ||
if (error.condition === "see-other-host") { | ||
return this._onSeeOtherHost(error); | ||
} | ||
this.emit('error', error) | ||
this.emit("error", error); | ||
} | ||
@@ -132,79 +131,75 @@ | ||
async _onSeeOtherHost(error) { | ||
const {protocol} = parseService(this.options.service) | ||
const { protocol } = parseService(this.options.service); | ||
const host = error.element.getChildText('see-other-host') | ||
const {port} = parseHost(host) | ||
const host = error.element.getChildText("see-other-host"); | ||
const { port } = parseHost(host); | ||
let service | ||
if (port) { | ||
service = `${protocol || 'xmpp:'}//${host}` | ||
} else { | ||
service = (protocol ? `${protocol}//` : '') + host | ||
} | ||
let service; | ||
service = port | ||
? `${protocol || "xmpp:"}//${host}` | ||
: (protocol ? `${protocol}//` : "") + host; | ||
try { | ||
await promise(this, 'disconnect') | ||
const {domain, lang} = this.options | ||
await this.connect(service) | ||
await this.open({domain, lang}) | ||
await promise(this, "disconnect"); | ||
const { domain, lang } = this.options; | ||
await this.connect(service); | ||
await this.open({ domain, lang }); | ||
} catch (err) { | ||
this.emit('error', err) | ||
this.emit("error", err); | ||
} | ||
} | ||
_attachParser(p) { | ||
const parser = (this.parser = p) | ||
const listeners = this.parserListeners | ||
_attachParser(parser) { | ||
this.parser = parser; | ||
const listeners = this.parserListeners; | ||
listeners.element = this._onElement.bind(this) | ||
listeners.error = this._onParserError.bind(this) | ||
listeners.element = this._onElement.bind(this); | ||
listeners.error = this._onParserError.bind(this); | ||
listeners.end = element => { | ||
this._detachParser() | ||
this._status('close', element) | ||
} | ||
listeners.end = (element) => { | ||
this._detachParser(); | ||
this._status("close", element); | ||
}; | ||
listeners.start = element => { | ||
this._status('open', element) | ||
} | ||
listeners.start = (element) => { | ||
this._status("open", element); | ||
}; | ||
parser.on('error', listeners.error) | ||
parser.on('element', listeners.element) | ||
parser.on('end', listeners.end) | ||
parser.on('start', listeners.start) | ||
this.parser.on("error", listeners.error); | ||
this.parser.on("element", listeners.element); | ||
this.parser.on("end", listeners.end); | ||
this.parser.on("start", listeners.start); | ||
} | ||
_detachParser() { | ||
const listeners = this.parserListeners | ||
Object.getOwnPropertyNames(listeners).forEach(k => { | ||
this.parser.removeListener(k, listeners[k]) | ||
delete listeners[k] | ||
}) | ||
this.parser = null | ||
const listeners = this.parserListeners; | ||
Object.getOwnPropertyNames(listeners).forEach((k) => { | ||
this.parser.removeListener(k, listeners[k]); | ||
delete listeners[k]; | ||
}); | ||
this.parser = null; | ||
} | ||
_jid(id) { | ||
this.jid = jid(id) | ||
return this.jid | ||
this.jid = jid(id); | ||
return this.jid; | ||
} | ||
_status(status, ...args) { | ||
this.status = status | ||
this.emit('status', status, ...args) | ||
this.emit(status, ...args) | ||
this.status = status; | ||
this.emit("status", status, ...args); | ||
this.emit(status, ...args); | ||
} | ||
async _end() { | ||
let el | ||
let el; | ||
try { | ||
el = await this.close() | ||
// eslint-disable-next-line no-unused-vars | ||
} catch (err) {} | ||
el = await this.close(); | ||
} catch {} | ||
try { | ||
await this.disconnect() | ||
// eslint-disable-next-line no-unused-vars | ||
} catch (err) {} | ||
await this.disconnect(); | ||
} catch {} | ||
return el | ||
return el; | ||
} | ||
@@ -216,15 +211,15 @@ | ||
async start() { | ||
if (this.status !== 'offline') { | ||
throw new Error('Connection is not offline') | ||
if (this.status !== "offline") { | ||
throw new Error("Connection is not offline"); | ||
} | ||
const {service, domain, lang} = this.options | ||
const { service, domain, lang } = this.options; | ||
await this.connect(service) | ||
await this.connect(service); | ||
const promiseOnline = promise(this, 'online') | ||
const promiseOnline = promise(this, "online"); | ||
await this.open({domain, lang}) | ||
await this.open({ domain, lang }); | ||
return promiseOnline | ||
return promiseOnline; | ||
} | ||
@@ -236,8 +231,8 @@ | ||
async connect(service) { | ||
this._status('connecting', service) | ||
const socket = new this.Socket() | ||
this._attachSocket(socket) | ||
this._status("connecting", service); | ||
const socket = new this.Socket(); | ||
this._attachSocket(socket); | ||
// The 'connect' status is set by the socket 'connect' listener | ||
socket.connect(this.socketParameters(service)) | ||
return promise(socket, 'connect') | ||
socket.connect(this.socketParameters(service)); | ||
return promise(socket, "connect"); | ||
} | ||
@@ -251,8 +246,8 @@ | ||
async disconnect(timeout = this.timeout) { | ||
if (this.socket) this._status('disconnecting') | ||
if (this.socket) this._status("disconnecting"); | ||
this.socket.end() | ||
this.socket.end(); | ||
// The 'disconnect' status is set by the socket 'close' listener | ||
await promise(this.socket, 'close', 'error', timeout) | ||
await promise(this.socket, "close", "error", timeout); | ||
} | ||
@@ -264,19 +259,19 @@ | ||
async open(options) { | ||
this._status('opening') | ||
this._status("opening"); | ||
if (typeof options === 'string') { | ||
options = {domain: options} | ||
if (typeof options === "string") { | ||
options = { domain: options }; | ||
} | ||
const {domain, lang, timeout = this.timeout} = options | ||
const { domain, lang, timeout = this.timeout } = options; | ||
const headerElement = this.headerElement() | ||
headerElement.attrs.to = domain | ||
headerElement.attrs['xml:lang'] = lang | ||
this.root = headerElement | ||
const headerElement = this.headerElement(); | ||
headerElement.attrs.to = domain; | ||
headerElement.attrs["xml:lang"] = lang; | ||
this.root = headerElement; | ||
this._attachParser(new this.Parser()) | ||
this._attachParser(new this.Parser()); | ||
await this.write(this.header(headerElement)) | ||
return promise(this, 'open', 'error', timeout) | ||
await this.write(this.header(headerElement)); | ||
return promise(this, "open", "error", timeout); | ||
} | ||
@@ -290,5 +285,5 @@ | ||
async stop() { | ||
const el = await this._end() | ||
if (this.status !== 'offline') this._status('offline', el) | ||
return el | ||
const el = await this._end(); | ||
if (this.status !== "offline") this._status("offline", el); | ||
return el; | ||
} | ||
@@ -302,11 +297,13 @@ | ||
async close(timeout = this.timeout) { | ||
const fragment = this.footer(this.footerElement()); | ||
const p = Promise.all([ | ||
promise(this.parser, 'end', 'error', timeout), | ||
this.write(this.footer(this.footerElement())), | ||
]) | ||
promise(this.parser, "end", "error", timeout), | ||
this.write(fragment), | ||
]); | ||
if (this.parser && this.socket) this._status('closing') | ||
const [el] = await p | ||
this.root = null | ||
return el | ||
if (this.parser && this.socket) this._status("closing"); | ||
const [el] = await p; | ||
this.root = null; | ||
return el; | ||
// The 'close' status is set by the parser 'end' listener | ||
@@ -320,12 +317,20 @@ } | ||
async restart() { | ||
this._detachParser() | ||
const {domain, lang} = this.options | ||
return this.open({domain, lang}) | ||
this._detachParser(); | ||
const { domain, lang } = this.options; | ||
return this.open({ domain, lang }); | ||
} | ||
async send(element) { | ||
element.parent = this.root | ||
this.emit('outgoing', element) | ||
await this.write(element) | ||
this.emit('send', element) | ||
async send(...elements) { | ||
let fragment = ""; | ||
for (const element of elements) { | ||
element.parent = this.root; | ||
fragment += element.toString(); | ||
} | ||
await this.write(fragment); | ||
for (const element of elements) { | ||
this.emit("send", element); | ||
} | ||
} | ||
@@ -336,34 +341,33 @@ | ||
this.send(element), | ||
promise(this, 'element', 'error', timeout), | ||
]).then(([, el]) => el) | ||
promise(this, "element", "error", timeout), | ||
]).then(([, el]) => el); | ||
} | ||
write(data) { | ||
write(string) { | ||
return new Promise((resolve, reject) => { | ||
// https://xmpp.org/rfcs/rfc6120.html#streams-close | ||
// "Refrain from sending any further data over its outbound stream to the other entity" | ||
if (this.status === 'closing') { | ||
reject(new Error('Connection is closing')) | ||
return | ||
if (this.status === "closing") { | ||
reject(new Error("Connection is closing")); | ||
return; | ||
} | ||
const str = data.toString('utf8') | ||
this.socket.write(str, err => { | ||
this.socket.write(string, (err) => { | ||
if (err) { | ||
return reject(err) | ||
return reject(err); | ||
} | ||
this.emit('output', str) | ||
resolve() | ||
}) | ||
}) | ||
this.emit("output", string); | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
isStanza(element) { | ||
const {name} = element | ||
return name === 'iq' || name === 'message' || name === 'presence' | ||
const { name } = element; | ||
return name === "iq" || name === "message" || name === "presence"; | ||
} | ||
isNonza(element) { | ||
return !this.isStanza(element) | ||
return !this.isStanza(element); | ||
} | ||
@@ -373,3 +377,3 @@ | ||
header(el) { | ||
return el.toString() | ||
return el.toString(); | ||
} | ||
@@ -379,6 +383,6 @@ | ||
headerElement() { | ||
return new xml.Element('', { | ||
version: '1.0', | ||
return new xml.Element("", { | ||
version: "1.0", | ||
xmlns: this.NS, | ||
}) | ||
}); | ||
} | ||
@@ -388,3 +392,3 @@ | ||
footer(el) { | ||
return el.toString() | ||
return el.toString(); | ||
} | ||
@@ -400,6 +404,6 @@ | ||
// Overrirde | ||
Connection.prototype.NS = '' | ||
Connection.prototype.Socket = null | ||
Connection.prototype.Parser = null | ||
Connection.prototype.NS = ""; | ||
Connection.prototype.Socket = null; | ||
Connection.prototype.Parser = null; | ||
module.exports = Connection | ||
module.exports = Connection; |
@@ -1,4 +0,4 @@ | ||
'use strict' | ||
"use strict"; | ||
const XMPPError = require('@xmpp/error') | ||
const XMPPError = require("@xmpp/error"); | ||
@@ -9,7 +9,7 @@ // https://xmpp.org/rfcs/rfc6120.html#streams-error | ||
constructor(...args) { | ||
super(...args) | ||
this.name = 'StreamError' | ||
super(...args); | ||
this.name = "StreamError"; | ||
} | ||
} | ||
module.exports = StreamError | ||
module.exports = StreamError; |
@@ -1,22 +0,22 @@ | ||
'use strict' | ||
"use strict"; | ||
function parseURI(URI) { | ||
let {port, hostname, protocol} = new URL(URI) | ||
let { port, hostname, protocol } = new URL(URI); | ||
// https://github.com/nodejs/node/issues/12410#issuecomment-294138912 | ||
if (hostname === '[::1]') { | ||
hostname = '::1' | ||
if (hostname === "[::1]") { | ||
hostname = "::1"; | ||
} | ||
return {port, hostname, protocol} | ||
return { port, hostname, protocol }; | ||
} | ||
function parseHost(host) { | ||
const {port, hostname} = parseURI(`http://${host}`) | ||
return {port, hostname} | ||
const { port, hostname } = parseURI(`http://${host}`); | ||
return { port, hostname }; | ||
} | ||
function parseService(service) { | ||
return service.includes('://') ? parseURI(service) : parseHost(service) | ||
return service.includes("://") ? parseURI(service) : parseHost(service); | ||
} | ||
Object.assign(module.exports, {parseURI, parseHost, parseService}) | ||
Object.assign(module.exports, { parseURI, parseHost, parseService }); |
@@ -7,3 +7,3 @@ { | ||
"bugs": "http://github.com/xmppjs/xmpp.js/issues", | ||
"version": "0.11.0", | ||
"version": "0.12.0", | ||
"license": "ISC", | ||
@@ -15,9 +15,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@xmpp/error": "^0.11.0", | ||
"@xmpp/events": "^0.11.0", | ||
"@xmpp/jid": "^0.11.0", | ||
"@xmpp/xml": "^0.11.0" | ||
"@xmpp/error": "^0.12.0", | ||
"@xmpp/events": "^0.12.0", | ||
"@xmpp/jid": "^0.12.0", | ||
"@xmpp/xml": "^0.12.0" | ||
}, | ||
"engines": { | ||
"node": ">= 10.0.0", | ||
"node": ">= 12.4.0", | ||
"yarn": ">= 1.0.0" | ||
@@ -28,3 +28,3 @@ }, | ||
}, | ||
"gitHead": "c0548a598826ae55cf195f296058b344064af7fd" | ||
"gitHead": "75f7bdf7805dced03f616b66dc16e2a067b46480" | ||
} |
@@ -1,128 +0,128 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter, promise, timeout} = require('@xmpp/events') | ||
const xml = require('@xmpp/xml') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter, promise, timeout } = require("@xmpp/events"); | ||
const xml = require("@xmpp/xml"); | ||
test('resets properties on socket close event', t => { | ||
const conn = new Connection() | ||
conn._attachSocket(new EventEmitter()) | ||
conn.jid = {} | ||
conn.status = 'online' | ||
conn.socket.emit('connect') | ||
conn.socket.emit('close') | ||
t.is(conn.jid, null) | ||
t.is(conn.status, 'disconnect') | ||
}) | ||
test("resets properties on socket close event", (t) => { | ||
const conn = new Connection(); | ||
conn._attachSocket(new EventEmitter()); | ||
conn.jid = {}; | ||
conn.status = "online"; | ||
conn.socket.emit("connect"); | ||
conn.socket.emit("close"); | ||
t.is(conn.jid, null); | ||
t.is(conn.status, "disconnect"); | ||
}); | ||
test.cb('timeout', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
conn.parser = new EventEmitter() | ||
test.cb("timeout", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.parser = new EventEmitter(); | ||
conn.footerElement = () => { | ||
return xml('hello') | ||
} | ||
return xml("hello"); | ||
}; | ||
conn.socket = new EventEmitter() | ||
conn.socket = new EventEmitter(); | ||
conn.socket.write = (data, cb) => { | ||
return cb() | ||
} | ||
return cb(); | ||
}; | ||
conn.on('output', el => { | ||
t.is(el, '<hello/>') | ||
}) | ||
conn.close().catch(err => { | ||
t.is(err.name, 'TimeoutError') | ||
t.end() | ||
}) | ||
}) | ||
conn.on("output", (el) => { | ||
t.is(el, "<hello/>"); | ||
}); | ||
conn.close().catch((err) => { | ||
t.is(err.name, "TimeoutError"); | ||
t.end(); | ||
}); | ||
}); | ||
test.cb('error on status closing', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
conn.parser = new EventEmitter() | ||
test.cb("error on status closing", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.parser = new EventEmitter(); | ||
conn.footerElement = () => { | ||
return xml('hello') | ||
} | ||
return xml("hello"); | ||
}; | ||
conn.socket = new EventEmitter() | ||
conn.socket = new EventEmitter(); | ||
conn.socket.write = (data, cb) => { | ||
return cb() | ||
} | ||
return cb(); | ||
}; | ||
conn.status = 'closing' | ||
conn.close().catch(err => { | ||
t.is(err.name, 'Error') | ||
t.is(err.message, 'Connection is closing') | ||
t.end() | ||
}) | ||
conn.parser.emit('end') | ||
}) | ||
conn.status = "closing"; | ||
conn.close().catch((err) => { | ||
t.is(err.name, "Error"); | ||
t.is(err.message, "Connection is closing"); | ||
t.end(); | ||
}); | ||
conn.parser.emit("end"); | ||
}); | ||
test('resolves', async t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
conn.parser = new EventEmitter() | ||
test("resolves", async (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.parser = new EventEmitter(); | ||
conn.footerElement = () => { | ||
return xml('hello') | ||
} | ||
return xml("hello"); | ||
}; | ||
conn.socket = new EventEmitter() | ||
conn.socket = new EventEmitter(); | ||
conn.socket.write = (data, cb) => { | ||
return cb() | ||
} | ||
return cb(); | ||
}; | ||
conn.on('output', el => { | ||
t.is(el, '<hello/>') | ||
}) | ||
conn.on("output", (el) => { | ||
t.is(el, "<hello/>"); | ||
}); | ||
const promiseClose = conn.close() | ||
conn.parser.emit('end', xml('goodbye')) | ||
const promiseClose = conn.close(); | ||
conn.parser.emit("end", xml("goodbye")); | ||
const el = await promiseClose | ||
const el = await promiseClose; | ||
t.is(el.toString(), `<goodbye/>`) | ||
}) | ||
t.is(el.toString(), `<goodbye/>`); | ||
}); | ||
test('emits closing status', t => { | ||
const conn = new Connection() | ||
conn.parser = new EventEmitter() | ||
test("emits closing status", (t) => { | ||
const conn = new Connection(); | ||
conn.parser = new EventEmitter(); | ||
conn.footerElement = () => { | ||
return xml('hello') | ||
} | ||
return xml("hello"); | ||
}; | ||
conn.socket = new EventEmitter() | ||
conn.socket = new EventEmitter(); | ||
conn.socket.write = (data, cb) => { | ||
return cb() | ||
} | ||
return cb(); | ||
}; | ||
const p = Promise.all([ | ||
promise(conn, 'status').then(status => t.is(status, 'closing')), | ||
promise(conn, "status").then((status) => t.is(status, "closing")), | ||
conn.close(), | ||
]) | ||
]); | ||
conn.parser.emit('end') | ||
return p | ||
}) | ||
conn.parser.emit("end"); | ||
return p; | ||
}); | ||
test('do not emit closing status if parser property is missing', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
conn.parser = null | ||
test("do not emit closing status if parser property is missing", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.parser = null; | ||
conn.footerElement = () => { | ||
return xml('hello') | ||
} | ||
return xml("hello"); | ||
}; | ||
conn.socket = new EventEmitter() | ||
conn.socket = new EventEmitter(); | ||
conn.socket.write = (data, cb) => { | ||
return cb() | ||
} | ||
return cb(); | ||
}; | ||
return Promise.all([ | ||
timeout(promise(conn, 'status'), 500).catch(err => | ||
t.is(err.name, 'TimeoutError') | ||
timeout(promise(conn, "status"), 500).catch((err) => | ||
t.is(err.name, "TimeoutError"), | ||
), | ||
conn.close().catch(err => t.pass(err)), | ||
]) | ||
}) | ||
conn.close().catch((err) => t.pass(err)), | ||
]); | ||
}); |
@@ -1,6 +0,6 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter, promise} = require('@xmpp/events') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter, promise } = require("@xmpp/events"); | ||
@@ -10,44 +10,47 @@ function socket(fn) { | ||
async connect() { | ||
await Promise.resolve() | ||
return fn.call(this) | ||
await Promise.resolve(); | ||
return fn.call(this); | ||
} | ||
} | ||
}; | ||
} | ||
test('emits "connecting" status', t => { | ||
const conn = new Connection() | ||
conn.Socket = socket(function() { | ||
this.emit('connect') | ||
}) | ||
test('emits "connecting" status', (t) => { | ||
const conn = new Connection(); | ||
// eslint-disable-next-line func-names | ||
conn.Socket = socket(function () { | ||
this.emit("connect"); | ||
}); | ||
return Promise.all([ | ||
promise(conn, 'connecting'), | ||
promise(conn, 'status').then(status => t.is(status, 'connecting')), | ||
conn.connect('url'), | ||
]) | ||
}) | ||
promise(conn, "connecting"), | ||
promise(conn, "status").then((status) => t.is(status, "connecting")), | ||
conn.connect("url"), | ||
]); | ||
}); | ||
test('rejects if an error is emitted before connected', async t => { | ||
const conn = new Connection() | ||
const error = {} | ||
test("rejects if an error is emitted before connected", async (t) => { | ||
const conn = new Connection(); | ||
const error = {}; | ||
conn.Socket = socket(function() { | ||
this.emit('error', error) | ||
}) | ||
conn.on('error', err => t.is(err, error)) | ||
// eslint-disable-next-line func-names | ||
conn.Socket = socket(function () { | ||
this.emit("error", error); | ||
}); | ||
conn.on("error", (err) => t.is(err, error)); | ||
try { | ||
await conn.connect('url') | ||
await conn.connect("url"); | ||
} catch (err) { | ||
t.is(err, error) | ||
t.is(err, error); | ||
} | ||
}) | ||
}); | ||
test('resolves if socket connects', async t => { | ||
const conn = new Connection() | ||
conn.Socket = socket(function() { | ||
this.emit('connect') | ||
}) | ||
await conn.connect('url') | ||
t.pass() | ||
}) | ||
test("resolves if socket connects", async (t) => { | ||
const conn = new Connection(); | ||
// eslint-disable-next-line func-names | ||
conn.Socket = socket(function () { | ||
this.emit("connect"); | ||
}); | ||
await conn.connect("url"); | ||
t.pass(); | ||
}); |
@@ -1,51 +0,53 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter} = require('@xmpp/events') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter } = require("@xmpp/events"); | ||
test.cb("rejects with TimeoutError if socket doesn't close", t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
const sock = (conn.socket = new EventEmitter()) | ||
sock.end = () => {} | ||
conn.disconnect().catch(err => { | ||
t.is(err.name, 'TimeoutError') | ||
t.end() | ||
}) | ||
t.is(conn.status, 'disconnecting') | ||
}) | ||
test.cb("rejects with TimeoutError if socket doesn't close", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.socket = new EventEmitter(); | ||
conn.socket.end = () => {}; | ||
conn.disconnect().catch((err) => { | ||
t.is(err.name, "TimeoutError"); | ||
t.end(); | ||
}); | ||
t.is(conn.status, "disconnecting"); | ||
}); | ||
test.cb('resolves', t => { | ||
t.plan(3) | ||
const conn = new Connection() | ||
const sock = new EventEmitter() | ||
conn._attachSocket(sock) | ||
sock.emit('connect') | ||
sock.end = () => {} | ||
test.cb("resolves", (t) => { | ||
t.plan(3); | ||
const conn = new Connection(); | ||
const sock = new EventEmitter(); | ||
conn._attachSocket(sock); | ||
sock.emit("connect"); | ||
sock.end = () => {}; | ||
conn | ||
.disconnect() | ||
.then(() => { | ||
t.is(conn.status, 'disconnect') | ||
return t.end() | ||
t.is(conn.status, "disconnect"); | ||
return t.end(); | ||
}) | ||
.catch(t.fail) | ||
t.is(conn.status, 'disconnecting') | ||
sock.emit('close') | ||
t.is(conn.status, 'disconnect') | ||
}) | ||
.catch(t.fail); | ||
t.is(conn.status, "disconnecting"); | ||
sock.emit("close"); | ||
t.is(conn.status, "disconnect"); | ||
}); | ||
test.cb('rejects if socket.end throws', t => { | ||
t.plan(1) | ||
const conn = new Connection() | ||
const sock = (conn.socket = new EventEmitter()) | ||
const error = new Error('foobar') | ||
sock.end = () => { | ||
throw error | ||
} | ||
test.cb("rejects if socket.end throws", (t) => { | ||
t.plan(1); | ||
conn.disconnect().catch(err => { | ||
t.is(err, error) | ||
t.end() | ||
}) | ||
}) | ||
const error = new Error("foobar"); | ||
const conn = new Connection(); | ||
conn.socket = new EventEmitter(); | ||
conn.socket.end = () => { | ||
throw error; | ||
}; | ||
conn.disconnect().catch((err) => { | ||
t.is(err, error); | ||
t.end(); | ||
}); | ||
}); |
@@ -1,68 +0,68 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
test('#_end', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
test("#_end", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.close = () => { | ||
t.pass() | ||
return Promise.resolve() | ||
} | ||
t.pass(); | ||
return Promise.resolve(); | ||
}; | ||
conn.disconnect = () => { | ||
t.pass() | ||
return Promise.resolve() | ||
} | ||
t.pass(); | ||
return Promise.resolve(); | ||
}; | ||
return conn._end() | ||
}) | ||
return conn._end(); | ||
}); | ||
test('#_end with close rejection', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
test("#_end with close rejection", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.close = () => { | ||
t.pass() | ||
return Promise.reject() | ||
} | ||
t.pass(); | ||
return Promise.reject(); | ||
}; | ||
conn.disconnect = () => { | ||
t.pass() | ||
return Promise.resolve() | ||
} | ||
t.pass(); | ||
return Promise.resolve(); | ||
}; | ||
return conn._end() | ||
}) | ||
return conn._end(); | ||
}); | ||
test('#_end with disconnect rejection', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
test("#_end with disconnect rejection", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.close = () => { | ||
t.pass() | ||
return Promise.resolve() | ||
} | ||
t.pass(); | ||
return Promise.resolve(); | ||
}; | ||
conn.disconnect = () => { | ||
t.pass() | ||
return Promise.reject() | ||
} | ||
t.pass(); | ||
return Promise.reject(); | ||
}; | ||
return conn._end() | ||
}) | ||
return conn._end(); | ||
}); | ||
test('#_end with close and disconnect rejection', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
test("#_end with close and disconnect rejection", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.close = () => { | ||
t.pass() | ||
return Promise.reject() | ||
} | ||
t.pass(); | ||
return Promise.reject(); | ||
}; | ||
conn.disconnect = () => { | ||
t.pass() | ||
return Promise.reject() | ||
} | ||
t.pass(); | ||
return Promise.reject(); | ||
}; | ||
return conn._end() | ||
}) | ||
return conn._end(); | ||
}); |
@@ -1,15 +0,15 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter} = require('@xmpp/events') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter } = require("@xmpp/events"); | ||
test('emit error on socket error', t => { | ||
const conn = new Connection() | ||
conn._attachSocket(new EventEmitter()) | ||
const error = new Error('foobar') | ||
conn.on('error', err => { | ||
t.is(err, error) | ||
}) | ||
conn.socket.emit('error', error) | ||
}) | ||
test("emit error on socket error", (t) => { | ||
const conn = new Connection(); | ||
conn._attachSocket(new EventEmitter()); | ||
const error = new Error("foobar"); | ||
conn.on("error", (err) => { | ||
t.is(err, error); | ||
}); | ||
conn.socket.emit("error", error); | ||
}); |
@@ -1,20 +0,20 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
test('#_onData', t => { | ||
t.plan(2) | ||
const foo = '<foo>' | ||
const conn = new Connection() | ||
test("#_onData", (t) => { | ||
t.plan(2); | ||
const foo = "<foo>"; | ||
const conn = new Connection(); | ||
conn.parser = { | ||
write(str) { | ||
t.is(str, foo) | ||
t.is(str, foo); | ||
}, | ||
} | ||
}; | ||
conn.on('input', data => { | ||
t.is(data, foo) | ||
}) | ||
conn._onData(foo) | ||
}) | ||
conn.on("input", (data) => { | ||
t.is(data, foo); | ||
}); | ||
conn._onData(foo); | ||
}); |
@@ -1,23 +0,23 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const xml = require('@xmpp/xml') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const xml = require("@xmpp/xml"); | ||
test.cb('#_onElement', t => { | ||
t.plan(2) | ||
const foo = <foo /> | ||
const conn = new Connection() | ||
conn.on('element', el => { | ||
t.is(el, foo) | ||
}) | ||
conn.on('nonza', el => { | ||
t.is(el, foo) | ||
t.end() | ||
}) | ||
conn._onElement(foo) | ||
}) | ||
test.cb("#_onElement", (t) => { | ||
t.plan(2); | ||
const foo = <foo />; | ||
const conn = new Connection(); | ||
conn.on("element", (el) => { | ||
t.is(el, foo); | ||
}); | ||
conn.on("nonza", (el) => { | ||
t.is(el, foo); | ||
t.end(); | ||
}); | ||
conn._onElement(foo); | ||
}); | ||
test.cb('#_onElement stream:error', t => { | ||
t.plan(7) | ||
test.cb("#_onElement stream:error", (t) => { | ||
t.plan(7); | ||
// prettier-ignore | ||
@@ -27,27 +27,27 @@ | ||
const foo = xml('error', {xmlns: 'http://etherx.jabber.org/streams'}, [ | ||
xml('foo-bar', {xmlns: 'urn:ietf:params:xml:ns:xmpp-streams'}), | ||
xml('text', {}, 'hello'), | ||
const foo = xml("error", { xmlns: "http://etherx.jabber.org/streams" }, [ | ||
xml("foo-bar", { xmlns: "urn:ietf:params:xml:ns:xmpp-streams" }), | ||
xml("text", {}, "hello"), | ||
application, | ||
]) | ||
const conn = new Connection() | ||
]); | ||
const conn = new Connection(); | ||
conn._end = () => { | ||
t.end() | ||
return Promise.resolve() | ||
} | ||
t.end(); | ||
return Promise.resolve(); | ||
}; | ||
conn.on('element', el => { | ||
t.is(el, foo) | ||
}) | ||
conn.on('nonza', el => { | ||
t.is(el, foo) | ||
}) | ||
conn.on('error', error => { | ||
t.is(error.name, 'StreamError') | ||
t.is(error.condition, 'foo-bar') | ||
t.is(error.message, 'foo-bar - hello') | ||
t.is(error.application, application) | ||
t.is(error.element, foo) | ||
}) | ||
conn._onElement(foo) | ||
}) | ||
conn.on("element", (el) => { | ||
t.is(el, foo); | ||
}); | ||
conn.on("nonza", (el) => { | ||
t.is(el, foo); | ||
}); | ||
conn.on("error", (error) => { | ||
t.is(error.name, "StreamError"); | ||
t.is(error.condition, "foo-bar"); | ||
t.is(error.message, "foo-bar - hello"); | ||
t.is(error.application, application); | ||
t.is(error.element, foo); | ||
}); | ||
conn._onElement(foo); | ||
}); |
@@ -1,27 +0,27 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter} = require('@xmpp/events') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter } = require("@xmpp/events"); | ||
test('calls _detachParser, sends a bad-format stream error and emit an error', t => { | ||
t.plan(3) | ||
const conn = new Connection() | ||
const parser = new EventEmitter() | ||
conn._attachParser(parser) | ||
test("calls _detachParser, sends a bad-format stream error and emit an error", (t) => { | ||
t.plan(3); | ||
const conn = new Connection(); | ||
const parser = new EventEmitter(); | ||
conn._attachParser(parser); | ||
const error = {} | ||
const error = {}; | ||
conn._detachParser = () => { | ||
t.pass() | ||
} | ||
t.pass(); | ||
}; | ||
conn._streamError = condition => { | ||
t.is(condition, 'bad-format') | ||
} | ||
conn._streamError = (condition) => { | ||
t.is(condition, "bad-format"); | ||
}; | ||
conn.on('error', err => { | ||
t.is(err, error) | ||
}) | ||
conn.on("error", (err) => { | ||
t.is(err, error); | ||
}); | ||
parser.emit('error', error) | ||
}) | ||
parser.emit("error", error); | ||
}); |
@@ -1,24 +0,24 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter} = require('@xmpp/events') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter } = require("@xmpp/events"); | ||
test('calls _reset and _status', t => { | ||
t.plan(3) | ||
const conn = new Connection() | ||
const sock = new EventEmitter() | ||
conn._attachSocket(sock) | ||
test("calls _reset and _status", (t) => { | ||
t.plan(3); | ||
const conn = new Connection(); | ||
const sock = new EventEmitter(); | ||
conn._attachSocket(sock); | ||
const evt = {} | ||
conn._status = (status, {clean, event}) => { | ||
t.is(clean, false) | ||
t.is(event, evt) | ||
} | ||
const evt = {}; | ||
conn._status = (status, { clean, event }) => { | ||
t.is(clean, false); | ||
t.is(event, evt); | ||
}; | ||
conn._reset = () => { | ||
t.pass() | ||
} | ||
t.pass(); | ||
}; | ||
sock.emit('close', true, evt) | ||
}) | ||
sock.emit("close", true, evt); | ||
}); |
@@ -1,13 +0,13 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
test('rejects if connection is not offline', t => { | ||
const conn = new Connection() | ||
conn.status = 'online' | ||
return conn.start().catch(err => { | ||
t.true(err instanceof Error) | ||
t.is(err.message, 'Connection is not offline') | ||
}) | ||
}) | ||
test("rejects if connection is not offline", (t) => { | ||
const conn = new Connection(); | ||
conn.status = "online"; | ||
return conn.start().catch((err) => { | ||
t.true(err instanceof Error); | ||
t.is(err.message, "Connection is not offline"); | ||
}); | ||
}); |
@@ -1,37 +0,42 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
test('resolves if socket property is undefined', async t => { | ||
const conn = new Connection() | ||
conn.footerElement = () => <foo /> | ||
conn.socket = undefined | ||
await conn.stop() | ||
t.pass() | ||
}) | ||
test("resolves if socket property is undefined", async (t) => { | ||
const conn = new Connection(); | ||
conn.footerElement = () => <foo />; | ||
conn.socket = undefined; | ||
await conn.stop(); | ||
t.pass(); | ||
}); | ||
test('resolves if close rejects', async t => { | ||
const conn = new Connection() | ||
conn.close = () => Promise.reject() | ||
conn.disconnect = () => Promise.resolve() | ||
await conn.stop() | ||
t.pass() | ||
}) | ||
test("resolves if close rejects", async (t) => { | ||
const conn = new Connection(); | ||
conn.close = () => Promise.reject(); | ||
conn.disconnect = () => Promise.resolve(); | ||
await conn.stop(); | ||
t.pass(); | ||
}); | ||
test('resolves if disconnect rejects', async t => { | ||
const conn = new Connection() | ||
conn.disconnect = () => Promise.reject() | ||
conn.close = () => Promise.resolve() | ||
await conn.stop() | ||
t.pass() | ||
}) | ||
test("resolves if disconnect rejects", async (t) => { | ||
const conn = new Connection(); | ||
conn.disconnect = () => Promise.reject(); | ||
conn.close = () => Promise.resolve(); | ||
await conn.stop(); | ||
t.pass(); | ||
}); | ||
test('resolves with the result of close', async t => { | ||
const conn = new Connection() | ||
conn.socket = {} | ||
const el = {} | ||
conn.close = () => Promise.resolve(el) | ||
conn.disconnect = () => Promise.resolve() | ||
t.is(await conn.stop(), el) | ||
}) | ||
test("resolves with the result of close", async (t) => { | ||
const conn = new Connection(); | ||
conn.socket = {}; | ||
const el = {}; | ||
conn.close = () => Promise.resolve(el); | ||
conn.disconnect = () => Promise.resolve(); | ||
t.is(await conn.stop(), el); | ||
}); | ||
test("does not throw if connection is not established", async (t) => { | ||
const conn = new Connection(); | ||
await t.notThrowsAsync(conn.stop()); | ||
}); |
@@ -1,11 +0,11 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const xml = require('@xmpp/xml') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const xml = require("@xmpp/xml"); | ||
test('#_streamError', t => { | ||
t.plan(2) | ||
const conn = new Connection() | ||
conn.send = el => { | ||
test("#_streamError", (t) => { | ||
t.plan(2); | ||
const conn = new Connection(); | ||
conn.send = (el) => { | ||
t.deepEqual( | ||
@@ -16,13 +16,13 @@ el, | ||
xml('foo-bar', {xmlns: 'urn:ietf:params:xml:ns:xmpp-streams'}), | ||
]) | ||
) | ||
return Promise.resolve() | ||
} | ||
]), | ||
); | ||
return Promise.resolve(); | ||
}; | ||
conn._end = () => { | ||
t.pass() | ||
return Promise.resolve() | ||
} | ||
t.pass(); | ||
return Promise.resolve(); | ||
}; | ||
return conn._streamError('foo-bar') | ||
}) | ||
return conn._streamError("foo-bar"); | ||
}); |
@@ -1,33 +0,33 @@ | ||
'use strict' | ||
"use strict"; | ||
const test = require('ava') | ||
const Connection = require('..') | ||
const {EventEmitter} = require('@xmpp/events') | ||
const xml = require('@xmpp/xml') | ||
const test = require("ava"); | ||
const Connection = require(".."); | ||
const { EventEmitter } = require("@xmpp/events"); | ||
const xml = require("@xmpp/xml"); | ||
test('new Connection()', t => { | ||
const conn = new Connection() | ||
t.is(conn.jid, null) | ||
t.is(conn.timeout, 2000) | ||
t.true(conn instanceof EventEmitter) | ||
}) | ||
test("new Connection()", (t) => { | ||
const conn = new Connection(); | ||
t.is(conn.jid, null); | ||
t.is(conn.timeout, 2000); | ||
t.true(conn instanceof EventEmitter); | ||
}); | ||
test('isStanza()', t => { | ||
const conn = new Connection() | ||
test("isStanza()", (t) => { | ||
const conn = new Connection(); | ||
t.is(conn.isStanza(xml('foo')), false) | ||
t.is(conn.isStanza(xml("foo")), false); | ||
t.is(conn.isStanza(xml('presence')), true) | ||
t.is(conn.isStanza(xml('iq')), true) | ||
t.is(conn.isStanza(xml('message')), true) | ||
}) | ||
t.is(conn.isStanza(xml("presence")), true); | ||
t.is(conn.isStanza(xml("iq")), true); | ||
t.is(conn.isStanza(xml("message")), true); | ||
}); | ||
test('isNonza()', t => { | ||
const conn = new Connection() | ||
test("isNonza()", (t) => { | ||
const conn = new Connection(); | ||
t.is(conn.isNonza(xml('foo')), true) | ||
t.is(conn.isNonza(xml("foo")), true); | ||
t.is(conn.isNonza(xml('presence')), false) | ||
t.is(conn.isNonza(xml('iq')), false) | ||
t.is(conn.isNonza(xml('message')), false) | ||
}) | ||
t.is(conn.isNonza(xml("presence")), false); | ||
t.is(conn.isNonza(xml("iq")), false); | ||
t.is(conn.isNonza(xml("message")), false); | ||
}); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
23820
844
1
+ Added@xmpp/error@0.12.1(transitive)
+ Added@xmpp/events@0.12.1(transitive)
+ Added@xmpp/jid@0.12.1(transitive)
+ Added@xmpp/xml@0.12.1(transitive)
- Removed@xmpp/error@0.11.0(transitive)
- Removed@xmpp/events@0.11.0(transitive)
- Removed@xmpp/jid@0.11.0(transitive)
- Removed@xmpp/xml@0.11.0(transitive)
Updated@xmpp/error@^0.12.0
Updated@xmpp/events@^0.12.0
Updated@xmpp/jid@^0.12.0
Updated@xmpp/xml@^0.12.0