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伺服器進行串連
/* * 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;elsejid += 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屬性
@Overrideint 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值