react-native-basic-xmpp
Version:
Fork of XMPP Library for React Native
215 lines (186 loc) • 5.51 kB
JavaScript
;
var React = require('react-native');
var { NativeAppEventEmitter, NativeModules } = React;
var RNXMPP = NativeModules.RNXMPP;
var ltx = require('ltx');
var EventEmitter = require('events').EventEmitter;
var map = {
connect: 'RNXMPPConnect',
disconnect: 'RNXMPPDisconnect',
error: 'RNXMPPError',
loginError: 'RNXMPPLoginError',
login: 'RNXMPPLogin',
stanza: 'RNXMPPStanza',
};
const EVENTS = {
CONNECT: 'connect',
LOGIN: 'login',
LOGIN_ERROR: 'loginError',
ERROR: 'error',
END: 'end',
STANZA: 'stanza',
};
class XMPP extends EventEmitter {
PLAIN = RNXMPP.PLAIN;
SCRAM = RNXMPP.SCRAMSHA1;
MD5 = RNXMPP.DigestMD5;
EVENTS = EVENTS;
constructor() {
super();
this.isConnected = false;
this.isLogged = false;
this.iqCallbacks = {};
NativeAppEventEmitter.addListener(
map.connect,
this.onConnected.bind(this),
);
NativeAppEventEmitter.addListener(
map.disconnect,
this.onDisconnected.bind(this),
);
NativeAppEventEmitter.addListener(map.error, this.onError.bind(this));
NativeAppEventEmitter.addListener(
map.loginError,
this.onLoginError.bind(this),
);
NativeAppEventEmitter.addListener(map.login, this.onLogin.bind(this));
NativeAppEventEmitter.addListener(map.stanza, this.onStanza.bind(this));
}
onConnected() {
this.isConnected = true;
this.emit(EVENTS.CONNECT);
}
onLogin() {
this.isLogged = true;
this.emit(EVENTS.LOGIN);
}
onDisconnected(error) {
this.emit(EVENTS.END);
if (error) {
this.emit(EVENTS.ERROR, error);
}
var iqCallbacks = this.iqCallbacks;
this.iqCallbacks = {};
var ids = Object.keys(iqCallbacks);
for (var i = 0; i < ids.length; i++) {
var cb = iqCallbacks[ids[i]];
try {
cb(new Error(`Disconnected: ${error}`));
} catch (e) {
this.emit(EVENTS.ERROR,
`Could not execute iq callback ${i} after disconnect: ${e}`);
}
}
this.isConnected = false;
this.isLogged = false;
}
onError(text) {
const error = text ? new Error(text) : new Error('Unknown error');
this.emit(EVENTS.ERROR, error);
}
onLoginError(text) {
this.isLogged = false;
const error = text ? new Error(text) : new Error('Unknown login error');
this.emit(EVENTS.LOGIN_ERROR, error);
}
iq(iq, cb) {
iq = iq.root();
if (cb) {
if (!iq.attrs.id) {
// Auto-generate id
do {
iq.attrs.id = Math.ceil(9999999 * Math.random());
} while (this.iqCallbacks.hasOwnProperty(iq.attrs.id));
}
this.iqCallbacks[iq.attrs.id] = cb;
}
this.sendStanza(iq);
}
onStanza(stanzaStr) {
try {
let stanza = ltx.parse(stanzaStr);
if (stanza.name == 'iq' && this.onIq(stanza)) {
return;
} else if (
stanza.name == 'message' ||
stanza.name == 'presence' ||
stanza.name == 'iq'
) {
this.emit(EVENTS.STANZA, stanza);
}
} catch (e) {
this.emit(EVENTS.ERROR, e)
}
}
onIq(iq) {
var id = iq.attrs.id;
var cb = this.iqCallbacks[id];
if (cb && iq.attrs.type == 'result') {
delete this.iqCallbacks[id];
cb(null, iq);
return true;
} else if (cb && iq.attrs.type == 'error') {
delete this.iqCallbacks[id];
cb(new Error(`Error: ${getStanzaError(iq)}`));
return true;
} else {
// Not handled, let onStanza() emit(STANZA, iq);
return false;
}
}
trustHosts(hosts) {
React.NativeModules.RNXMPP.trustHosts(hosts);
}
connect(
username,
password,
auth = RNXMPP.SCRAMSHA1,
hostname = null,
port = 5222,
) {
if (!hostname) {
hostname = `${username}@/`.split('@')[1].split('/')[0];
}
React.NativeModules.RNXMPP.setup(
username,
password,
auth,
hostname,
port,
);
React.NativeModules.RNXMPP.connect();
}
reconnect() {
React.NativeModules.RNXMPP.connect();
}
sendStanza(stanza) {
if (typeof stanza.root == 'function') {
stanza = stanza.root();
}
if (typeof stanza != 'string') {
stanza = stanza.toString();
}
RNXMPP.sendStanza(stanza);
}
disconnect() {
if (this.isConnected) {
React.NativeModules.RNXMPP.disconnect();
}
}
}
module.exports = new XMPP();
function getStanzaError(stanza) {
let errorEl;
if ((errorEl = stanza.getChild('error'))) {
for (let child of errorEl.children) {
let errorCode =
child &&
child.attrs.xmlns == 'urn:ietf:params:xml:ns:xmpp-stanzas' &&
child.name;
if (errorCode) {
return new Error(errorCode);
}
}
}
return new Error(`Error in: ${stanza.toString()}`);
}