jwchat核心文件是jsjac.js
这个文件看懂了,webIM基本就可以跑通了,不多说,看看jsjac的介绍:
JSJaC的全称为:JSJaC - JavaScript. Jabber Client Library,即使用JavaScript写成的Jabber客户端库。
其目的在于:方便基于Web的jabber/XMPP客户端的实现。
JSJaC的特点:
1、面向对象的接口
2、通信采用HTTPRequest对象,即AJAX技术
3、兼容性好:和大多数AJAX/JS框架实现兼容,比如,prototype, mootools, jQuery, dojo and YUI!等
1.登陆操作
index.html中,只进行了前台校验,没有和openfire服务器进行连接
校验通过之后,跳转到jwchat.html文件,init()方法连接服务器
很清晰的看出,连接操作由JSJaCHttpBindingConnection或者JSJaCHttpPollingConnection完成(jsjac.js是面向对象的接口,姑且可以将这两个方法按照OO思想理解)
JSJaCHttpBindingConnection源码:
JSJaCHttpPollingConnection源码:
Debugger在Debugger.js中
这个文件看懂了,webIM基本就可以跑通了,不多说,看看jsjac的介绍:
JSJaC的全称为:JSJaC - JavaScript. Jabber Client Library,即使用JavaScript写成的Jabber客户端库。
其目的在于:方便基于Web的jabber/XMPP客户端的实现。
JSJaC的特点:
1、面向对象的接口
2、通信采用HTTPRequest对象,即AJAX技术
3、兼容性好:和大多数AJAX/JS框架实现兼容,比如,prototype, mootools, jQuery, dojo and YUI!等
1.登陆操作
index.html中,只进行了前台校验,没有和openfire服务器进行连接
/*
* check if user want's to register new account and things
*/
function loginCheck(form) {
if (form.jid.value == '') {
alert("You need to supply a username");
return false;
}
if (form.pass.value == '') {
alert("You need to supply a password");
return false;
}
if (document.getElementById('tr_server').style.display != 'none') {
var val = document.getElementById('server').value;
if (val == '') {
alert("You need to supply a jabber server");
return false;
}
JABBERSERVER = val;
}
jid = form.jid.value + "@" + JABBERSERVER + "/";
if (form.res.value != '')
jid += form.res.value;
else
jid += DEFAULTRESOURCE;
if (!isValidJID(jid))
return false;
if (jwchats[jid] && !jwchats[jid].closed) {
jwchats[jid].focus();
return false;
}
pass = form.pass.value;
register = form.register.checked;
prio = form.prio[form.prio.selectedIndex].value;
connect_port = form.connect_port.value;
connect_host = form.connect_host.value;
connect_secure = form.connect_secure.checked;
jwchats[jid] = window.open('jwchat.html', makeWindowName(jid),
'width=620,height=590,resizable=yes');
return false;
}
校验通过之后,跳转到jwchat.html文件,init()方法连接服务器
/************************************************************************
* ****** INIT *******
************************************************************************
*/
var con, Debug, srcW;
function init() {
/* initialise debugger */
if (!Debug || typeof(Debug) == 'undefined' || !Debug.start) {
if (typeof(Debugger) != 'undefined'){
Debug = new Debugger(DEBUG_LVL,'jwchat' + cutResource(jid));}
else {
Debug = new Object();
Debug.log = function() {};
Debug.start = function() {};
}
}
if (DEBUG && (!USE_DEBUGJID || DEBUGJID == cutResource(jid)))
Debug.start();
Debug.log("jid: "+jid+"\npass: "+pass,2);
/* get some refs to static elements */
statusLed = frames["jwc_main"].document.getElementById('statusLed');
statusMsg = frames["jwc_main"].document.getElementById('statusMsg');
fmd = frames["jwc_main"].iRoster.document;
/* set title */
document.title = "JointSky Messenger - " + nick;
/* set nick */
frames["jwc_main"].document.getElementById('myNickname').innerHTML = nick;
/* set unit 2012.8.8 dml@wip Notice:This value should be catch from userInfo which is stored in openfire*/
frames["jwc_main"].document.getElementById('unit').innerHTML = "(ch)";
/* init empty roster */
roster = new Roster();
/* ***
* create new connection
*/
var oArg = {oDbg: Debug, httpbase: HTTPBASE, timerval: timerval};
if (BACKEND_TYPE == 'binding')
con = new JSJaCHttpBindingConnection(oArg);
else
con = new JSJaCHttpPollingConnection(oArg);
/* register handlers */
con.registerHandler('iq',handleIQSet);
con.registerHandler('presence',handlePresence);
con.registerHandler('message',handleMessage);
con.registerHandler('message',handleMessageError);
con.registerHandler('ondisconnect',handleDisconnect);
con.registerHandler('onconnect',handleConnected);
con.registerHandler('onerror',handleConError);
/* connect to remote */
oArg = {domain:JABBERSERVER,username:jid.substring(0,jid.indexOf('@')),resource:jid.substring(jid.indexOf('/')+1),pass:pass,register:register}
if (BACKEND_TYPE == 'binding') {
if (opener.connect_port && !isNaN(opener.connect_port))
oArg.port = opener.connect_port;
if (opener.connect_host && opener.connect_host != '')
oArg.host = opener.connect_host;
if (opener && opener.connect_secure)
oArg.secure = true;
}
con.connect(oArg);
}
很清晰的看出,连接操作由JSJaCHttpBindingConnection或者JSJaCHttpPollingConnection完成(jsjac.js是面向对象的接口,姑且可以将这两个方法按照OO思想理解)
JSJaCHttpBindingConnection源码:
function JSJaCHttpBindingConnection(oArg) {
this.base = JSJaCConnection;
this.base(oArg);
this._hold = JSJACHBC_MAX_HOLD;
this._inactivity = 0;
this._last_requests = new Object();
this._last_rid = 0;
this._min_polling = 0;
this._pause = 0;
this._wait = JSJACHBC_MAX_WAIT;
this.connect = JSJaCHBCConnect;
this.disconnect = JSJaCHBCDisconnect;
this.inherit = JSJaCHBCInherit;
this.isPolling = function() {
return (this._hold == 0)
};
this.setPollInterval = function(timerval) {
if (!timerval || isNaN(timerval)) {
this.oDbg.log("Invalid timerval: " + timerval, 1);
return - 1;
}
if (!this.isPolling()) this._timerval = 100;
else if (this._min_polling && timerval < this._min_polling * 1000) this._timerval = this._min_polling * 1000;
else if (this._inactivity && timerval > this._inactivity * 1000) this._timerval = this._inactivity * 1000;
else this._timerval = timerval;
return this._timerval;
};
this._getRequestString = JSJaCHBCGetRequestString;
this._getFreeSlot = function() {
for (var i = 0; i < this._hold + 1; i++) if (typeof(this._req[i]) == 'undefined' || typeof(this._req[i].r) == 'undefined' || this._req[i].r.readyState == 4) return i;
return - 1;
}
this._getHold = function() {
return this._hold;
}
this._getStreamID = JSJaCHBCGetStreamID;
this._getSuspendVars = function() {
return ('host,port,secure,_rid,_last_rid,_wait,_min_polling,_inactivity,_hold,_last_requests,_pause').split(',');
}
this._handleInitialResponse = JSJaCHBCHandleInitialResponse;
this._prepareResponse = JSJaCHBCPrepareResponse;
this._reInitStream = JSJaCHBCReInitStream;
this._resume = function() {
if (this._pause == 0 && this._rid >= this._last_rid) this._rid = this._last_rid - 1;
this._process();
this._inQto = setInterval("oCon._checkInQ();", JSJAC_CHECKINQUEUEINTERVAL);
this._interval = setInterval("oCon._checkQueue()", JSJAC_CHECKQUEUEINTERVAL);
}
this._setHold = function(hold) {
if (!hold || isNaN(hold) || hold < 0) hold = 0;
else if (hold > JSJACHBC_MAX_HOLD) hold = JSJACHBC_MAX_HOLD;
this._hold = hold;
return this._hold;
};
this._setupRequest = JSJaCHBCSetupRequest;
this._suspend = function() {
if (this._pause == 0) return;
var slot = this._getFreeSlot();
this._req[slot] = this._setupRequest(false);
var reqstr = "<body pause='" + this._pause + "' xmlns='http://jabber.org/protocol/httpbind' sid='" + this._sid + "' rid='" + this._rid + "'";
if (JSJAC_HAVEKEYS) {
reqstr += " key='" + this._keys.getKey() + "'";
if (this._keys.lastKey()) {
this._keys = new JSJaCKeys(hex_sha1, this.oDbg);
reqstr += " newkey='" + this._keys.getKey() + "'";
}
}
reqstr += ">";
while (this._pQueue.length) {
var curNode = this._pQueue[0];
reqstr += curNode;
this._pQueue = this._pQueue.slice(1, this._pQueue.length);
}
reqstr += "</body>";
var abortTimerID = setTimeout("oCon._req[" + slot + "].r.abort();", 5000);
this.oDbg.log("Disconnecting: " + reqstr, 4);
this._req[slot].r.send(reqstr);
clearTimeout(abortTimerID);
}
}
JSJaCHttpPollingConnection源码:
function JSJaCHttpPollingConnection(oArg) {
this.base = JSJaCConnection;
this.base(oArg);
JSJACPACKET_USE_XMLNS = false;
this.connect = JSJaCHPCConnect;
this.disconnect = JSJaCHPCDisconnect;
this.isPolling = function() {
return true;
};
this._getFreeSlot = function() {
if (typeof(this._req[0]) == 'undefined' || typeof(this._req[0].r) == 'undefined' || this._req[0].r.readyState == 4) return 0;
else return - 1;
}
this._getRequestString = JSJaCHPCGetRequestString;
this._getStreamID = JSJaCHPCGetStream;
this._getSuspendVars = function() {
return new Array();
}
this._prepareResponse = JSJaCHPCPrepareResponse;
this._reInitStream = JSJaCHPCReInitStream;
this._resume = function() {
this._process(this._timerval);
this._interval = setInterval("oCon._checkQueue()", JSJAC_CHECKQUEUEINTERVAL);
this._inQto = setInterval("oCon._checkInQ();", JSJAC_CHECKINQUEUEINTERVAL);
}
this._setupRequest = JSJaCHPCSetupRequest;
this._suspend = function() {};
}
登陆时,需要分析oArg这个参数
var oArg = {oDbg: Debug, httpbase: HTTPBASE, timerval: timerval};
其中,Debug是一个Debugger实例,init()中有声明
Debug = new Debugger(DEBUG_LVL,'jwchat ' + cutResource(jid));}
Debugger在Debugger.js中
function Debugger(lvl,id) {
this.lvl = lvl || 0;
if (this.lvl > DEBUGGER_MAX_LEVEL)
this.lvl = DEBUGGER_MAX_LEVEL;
this.id = id || '';
this.debugMsgs = new Array();
this.log = DebugLog;
this.setLevel = DebugSetLevel;
this.start = DebugStart;
this.stop = DebugStop;
HttpBase和timerval在config.js中设置,这个根据项目需要自行设置即可
按照以上所述,打开openfire服务器,运行登陆 http://127.0.0.1:9090/user-summary.jsp,online用户列表中查看到信息就说明登陆正常了。
需要注意的是,如果静止不动大约5-6分钟,服务自动提示连接超时,这个时候,需要修改org.jivesoftware.openfire.nio.ClientConnectionHandler类 ,xmpp.client.idle属性
@Override
int getMaxIdleTime() {
//设置超时时间 默认6分钟
// return JiveGlobals.getIntProperty("xmpp.client.idle", 6 * 60 * 1000) / 1000;
//设置超时时间 30分钟
return JiveGlobals.getIntProperty("xmpp.client.idle", 30 * 60 * 1000) / 1000;
}
或者,浏览器输入url:http://127.0.0.1:9090/client-connections-settings.jsp进行设置
再或者,直接修改ofproperty表中idle值