@jsxc/jsxc
Version:
Real-time XMPP chat application with video calls, file transfer and encrypted communication
119 lines (103 loc) • 3.73 kB
text/typescript
import { Strophe } from 'strophe.js';
import Log from '../../util/Log';
import SM from '../../StateMachine';
import Client from '../../Client';
import InvalidParameterError from '../../errors/InvalidParameterError';
import ConnectionError from '../../errors/ConnectionError';
import AuthenticationError from '../../errors/AuthenticationError';
import UUID from '@util/UUID';
export function login(url: string, jid: string, sid: string, rid: string);
export function login(url: string, jid: string, password: string);
export function login() {
if (arguments.length === 3) {
return loginWithPassword(arguments[0], arguments[1], arguments[2]);
} else if (arguments.length === 4) {
return attachConnection(arguments[0], arguments[1], arguments[2], arguments[3]);
} else {
Log.warn('This should not happen');
}
}
function loginWithPassword(url: string, jid: string, password: string): Promise<{}> {
testBasicConnectionParameters(url, jid);
let connection = prepareConnection(url);
Log.debug('Try to establish a new connection.');
if (jid.indexOf('/') < 0) {
jid += '/jsxc-' + UUID.v4().slice(0, 8);
}
return new Promise(function (resolve, reject) {
connection.connect(jid, password, function (status, condition) {
resolveConnectionPromise(status, condition, connection, resolve, reject);
});
});
}
function attachConnection(url: string, jid: string, sid: string, rid: string) {
testBasicConnectionParameters(url, jid);
let connection = prepareConnection(url);
Log.debug('Try to attach old connection.');
return new Promise(function (resolve, reject) {
connection.attach(jid, sid, rid, function (status, condition) {
resolveConnectionPromise(status, condition, connection, resolve, reject);
});
});
}
function resolveConnectionPromise(status, condition, connection, resolve, reject) {
switch (status) {
case Strophe.Status.DISCONNECTED:
case Strophe.Status.CONNFAIL:
reject(new ConnectionError(condition));
break;
case Strophe.Status.AUTHFAIL:
reject(new AuthenticationError(condition));
break;
case Strophe.Status.ATTACHED:
// flush connection in order we reuse a rid
connection.flush();
setTimeout(() => {
// attached doesn't mean the connection is working, but if something
// is wrong the server will immediately response with a connection failure.
resolve({
connection,
status,
condition,
});
}, 1000);
break;
case Strophe.Status.CONNECTED:
resolve({
connection,
status,
condition,
});
break;
default:
Log.debug('Strophe Connection Status: ', Object.keys(Strophe.Status)[status]);
}
}
function testBasicConnectionParameters(url: string, jid: string) {
if (!jid) {
throw new InvalidParameterError('I can not log in without a jid.');
}
if (!url) {
throw new InvalidParameterError('I can not log in without an URL.');
}
}
function prepareConnection(url: string): Strophe.Connection {
let connection = new Strophe.Connection(url, <any>{
mechanisms: [
(<any>Strophe).SASLAnonymous,
(<any>Strophe).SASLExternal,
(<any>Strophe).SASLPlain,
(<any>Strophe).SASLSHA1,
],
});
if (Client.isDebugMode()) {
connection.xmlInput = function (data) {
Log.debug('<', data);
};
connection.xmlOutput = function (data) {
Log.debug('>', data);
};
}
SM.changeState(SM.STATE.ESTABLISHING);
return connection;
}