mirror of
https://github.com/Mibew/java.git
synced 2025-01-22 17:40:35 +03:00
Move JavaScript's ChatServer class to separate file
This commit is contained in:
parent
83636a02ef
commit
d53e1d8020
@ -7,14 +7,7 @@
|
||||
*/
|
||||
var FrameUtils={getDocument:function(a){return a.contentDocument?a.contentDocument:a.contentWindow?a.contentWindow.document:a.document?a.document:null},initFrame:function(a){var b=this.getDocument(a);b.open();b.write("<html><head>");b.write('<link rel="stylesheet" type="text/css" media="all" href="'+Chat.cssfile+'">');b.write("</head><body bgcolor='#FFFFFF' text='#000000' link='#C28400' vlink='#C28400' alink='#C28400'>");b.write("<table width='100%' cellspacing='0' cellpadding='0' border='0'><tr><td valign='top' class='message' id='content'></td></tr></table><a id='bottom' name='bottom'></a>");
|
||||
b.write("</body></html>");b.close();a.onload=function(){a.myHtml&&(FrameUtils.getDocument(a).getElementById("content").innerHTML+=a.myHtml,FrameUtils.scrollDown(a))}},insertIntoFrame:function(a,b){var c=this.getDocument(a).getElementById("content");null==c?(a.myHtml||(a.myHtml=""),a.myHtml+=b):c.innerHTML+=b},scrollDown:function(a){var b=this.getDocument(a).getElementById("bottom");if("opera"==myAgent)try{a.contentWindow.scrollTo(0,this.getDocument(a).getElementById("content").clientHeight)}catch(c){}b&&
|
||||
b.scrollIntoView(!1)}};ChatServer=Class.create();
|
||||
ChatServer.prototype={initialize:function(a){this.updateTimer=null;this.options={servl:"",requestsFrequency:2,onTimeout:function(){},onTransportError:function(){},onCallError:function(){},onUpdateError:function(){},onResponseError:function(){}}.extend(a);this.callbacks={};this.callPeriodically=[];this.ajaxOptions={_method:"post",asynchronous:!0,timeout:5E3,onComplete:this.receiveResponse.bind(this),onException:this.onTransportError.bind(this),onTimeout:this.onTimeout.bind(this)};this.ajaxRequest=
|
||||
null;this.buffer=[];this.functions={};this.mibewAPI=new MibewAPI(new MibewAPICoreInteraction)},callFunctions:function(a,b,c){try{if(!(a instanceof Array))throw Error("The first arguments must be an array");for(var d in a)a.hasOwnProperty(d)&&this.mibewAPI.checkFunction(a[d],!1);var e=this.generateToken();this.callbacks[e]=b;this.buffer.push({token:e,functions:a});c&&this.update()}catch(f){return this.options.onCallError(f),!1}return!0},callFunctionsPeriodically:function(a,b){this.callPeriodically.push({functionsListBuilder:a,
|
||||
callbackFunction:b})},generateToken:function(){var a;do a="wnd"+(new Date).getTime().toString()+Math.round(50*Math.random()).toString();while(a in this.callbacks);return a},processRequest:function(a){var b=new MibewAPIExecutionContext,c=this.mibewAPI.getResultFunction(a.functions,this.callbacks.hasOwnProperty(a.token));if(null===c)for(var d in a.functions)a.functions.hasOwnProperty(d)&&(this.processFunction(a.functions[d],b),this.buffer.push(this.mibewAPI.buildResult(b.getResults(),a.token)));else this.callbacks.hasOwnProperty(a.token)&&
|
||||
(this.callbacks[a.token](c.arguments),delete this.callbacks[a.token])},processFunction:function(a,b){if(this.functions.hasOwnProperty(a["function"])){var c=b.getArgumentsList(a),d={},e;for(e in this.functions[a["function"]])this.functions[a["function"]].hasOwnProperty(e)&&d.extend(this.functions[a["function"]][e](c));b.storeFunctionResults(a,d)}},sendRequests:function(a){this.ajaxRequest=new Ajax.Request(this.options.servl,this.ajaxOptions.extend({parameters:"data="+this.mibewAPI.encodePackage(a)}))},
|
||||
runUpdater:function(){null==this.updateTimer&&this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3*this.options.requestsFrequency)},restartUpdater:function(){this.updateTimer&&clearTimeout(this.updateTimer);this.ajaxRequest._options&&(this.ajaxRequest._options.onComplete=void 0);this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3)},update:function(){this.updateTimer&&clearTimeout(this.updateTimer);for(var a=0;a<this.callPeriodically.length;a++)this.callFunctions(this.callPeriodically[a].functionsListBuilder(),
|
||||
this.callPeriodically[a].callbackFunction);if(0==this.buffer.length)this.runUpdater();else try{this.sendRequests(this.buffer),this.buffer=[]}catch(b){this.options.onUpdateError(b)}},receiveResponse:function(a){""==a.response&&this.runUpdater();try{var b=this.mibewAPI.decodePackage(a.response),c;for(c in b.requests)this.processRequest(b.requests[c])}catch(d){this.options.onResponseError(d)}finally{this.runUpdater()}},registerFunction:function(a,b){a in this.functions||(this.functions[a]=[]);this.functions[a].push(b)},
|
||||
onTransportError:function(a,b){this.restartUpdater();this.options.onTransportError(b)},onTimeout:function(){this.restartUpdater();this.options.onTimeout()}};ChatThreadUpdater=Class.create();
|
||||
b.scrollIntoView(!1)}};ChatThreadUpdater=Class.create();
|
||||
ChatThreadUpdater.prototype={initialize:function(a,b,c){this._options=c;this.thread=b;this.chatServer=a;this.focused=this.skipNextsound=this.cansend=!0;this.ownThread=null!=this._options.message;FrameUtils.initFrame(this._options.container);this._options.message&&(this._options.message.onkeydown=this.handleKeyDown.bind(this),this._options.message.onfocus=function(){this.focused=!0}.bind(this),this._options.message.onblur=function(){this.focused=!1}.bind(this));this.chatServer.callFunctionsPeriodically(this.updateFunctionBuilder.bind(this),
|
||||
this.updateChatState.bind(this));this.chatServer.registerFunction("updateMessages",this.updateMessages.bind(this));this.chatServer.registerFunction("setupAvatar",this.setupAvatar.bind(this));this.chatServer.runUpdater()},handleException:function(){this.setStatus("offline, reconnecting");this.enableInput(!0)},handleTimeout:function(){this.setStatus("timeout, reconnecting");this.enableInput(!0)},enableInput:function(a){this._options.message&&(this._options.message.disabled=!a)},refresh:function(){this.chatServer.restartUpdater()},
|
||||
postMessage:function(a){""!=a&&this.cansend&&(this.cansend=!1,this.skipNextsound=!0,"opera"!=myRealAgent&&this.enableInput(!1),this.chatServer.callFunctions([{"function":"post",arguments:{references:{},"return":{},message:a,threadId:this.thread.threadid,token:this.thread.token,user:this.thread.user}}],function(){this.enableInput(!0);this.cansend=!0;this.skipNextsound=!1;this._options.message&&(this._options.message.value="",this._options.message.focus())}.bind(this),!0))},changeName:function(a){this.skipNextsound=
|
||||
|
15
src/messenger/webim/js/164/chatserver.js
Normal file
15
src/messenger/webim/js/164/chatserver.js
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
This file is part of Mibew Messenger project.
|
||||
http://mibew.org
|
||||
|
||||
Copyright (c) 2005-2011 Mibew Messenger Community
|
||||
License: http://mibew.org/license.php
|
||||
*/
|
||||
ChatServer=Class.create();
|
||||
ChatServer.prototype={initialize:function(a){this.updateTimer=null;this.options={servl:"",requestsFrequency:2,onTimeout:function(){},onTransportError:function(){},onCallError:function(){},onUpdateError:function(){},onResponseError:function(){}}.extend(a);this.callbacks={};this.callPeriodically=[];this.ajaxOptions={_method:"post",asynchronous:!0,timeout:5E3,onComplete:this.receiveResponse.bind(this),onException:this.onTransportError.bind(this),onTimeout:this.onTimeout.bind(this)};this.ajaxRequest=
|
||||
null;this.buffer=[];this.functions={};this.mibewAPI=new MibewAPI(new MibewAPICoreInteraction)},callFunctions:function(a,b,d){try{if(!(a instanceof Array))throw Error("The first arguments must be an array");for(var c in a)a.hasOwnProperty(c)&&this.mibewAPI.checkFunction(a[c],!1);var e=this.generateToken();this.callbacks[e]=b;this.buffer.push({token:e,functions:a});d&&this.update()}catch(f){return this.options.onCallError(f),!1}return!0},callFunctionsPeriodically:function(a,b){this.callPeriodically.push({functionsListBuilder:a,
|
||||
callbackFunction:b})},generateToken:function(){var a;do a="wnd"+(new Date).getTime().toString()+Math.round(50*Math.random()).toString();while(a in this.callbacks);return a},processRequest:function(a){var b=new MibewAPIExecutionContext,d=this.mibewAPI.getResultFunction(a.functions,this.callbacks.hasOwnProperty(a.token));if(null===d)for(var c in a.functions)a.functions.hasOwnProperty(c)&&(this.processFunction(a.functions[c],b),this.buffer.push(this.mibewAPI.buildResult(b.getResults(),a.token)));else this.callbacks.hasOwnProperty(a.token)&&
|
||||
(this.callbacks[a.token](d.arguments),delete this.callbacks[a.token])},processFunction:function(a,b){if(this.functions.hasOwnProperty(a["function"])){var d=b.getArgumentsList(a),c={},e;for(e in this.functions[a["function"]])this.functions[a["function"]].hasOwnProperty(e)&&c.extend(this.functions[a["function"]][e](d));b.storeFunctionResults(a,c)}},sendRequests:function(a){this.ajaxRequest=new Ajax.Request(this.options.servl,this.ajaxOptions.extend({parameters:"data="+this.mibewAPI.encodePackage(a)}))},
|
||||
runUpdater:function(){null==this.updateTimer&&this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3*this.options.requestsFrequency)},restartUpdater:function(){this.updateTimer&&clearTimeout(this.updateTimer);this.ajaxRequest._options&&(this.ajaxRequest._options.onComplete=void 0);this.update();this.updateTimer=setTimeout(this.update.bind(this),1E3)},update:function(){this.updateTimer&&clearTimeout(this.updateTimer);for(var a=0;a<this.callPeriodically.length;a++)this.callFunctions(this.callPeriodically[a].functionsListBuilder(),
|
||||
this.callPeriodically[a].callbackFunction);if(0==this.buffer.length)this.runUpdater();else try{this.sendRequests(this.buffer),this.buffer=[]}catch(b){this.options.onUpdateError(b)}},receiveResponse:function(a){""==a.response&&this.runUpdater();try{var b=this.mibewAPI.decodePackage(a.response),d;for(d in b.requests)this.processRequest(b.requests[d])}catch(c){this.options.onResponseError(c)}finally{this.runUpdater()}},registerFunction:function(a,b){a in this.functions||(this.functions[a]=[]);this.functions[a].push(b)},
|
||||
onTransportError:function(a,b){this.restartUpdater();this.options.onTransportError(b)},onTimeout:function(){this.restartUpdater();this.options.onTimeout()}};
|
@ -44,6 +44,10 @@
|
||||
<arg value="mibew_api:1:common"/>
|
||||
<arg value="--js"/>
|
||||
<arg value="mibew_api.js"/>
|
||||
<arg value="--module"/>
|
||||
<arg value="chatserver:1:common"/>
|
||||
<arg value="--js"/>
|
||||
<arg value="chatserver.js"/>
|
||||
</java>
|
||||
|
||||
<java jar="${closure.c}" fork="true">
|
||||
|
@ -59,383 +59,6 @@ var FrameUtils = {
|
||||
}
|
||||
};
|
||||
|
||||
ChatServer = Class.create();
|
||||
/**
|
||||
* @todo Think about error handling
|
||||
*/
|
||||
ChatServer.prototype = {
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
initialize: function(options) {
|
||||
var chatServer = this;
|
||||
|
||||
/**
|
||||
* Update timer
|
||||
*/
|
||||
this.updateTimer = null;
|
||||
|
||||
/**
|
||||
* Options for the ChatServer object
|
||||
* @private
|
||||
* @todo Check onResponseError handler
|
||||
*/
|
||||
this.options = {
|
||||
// Server gateway URL
|
||||
servl: "",
|
||||
// Frequency for automatic updater
|
||||
requestsFrequency: 2,
|
||||
// Call on request timeout
|
||||
onTimeout: function() {},
|
||||
// Call when transport error was caught
|
||||
onTransportError: function(e) {},
|
||||
// Call when callFunctions related error was caught
|
||||
onCallError: function(e) {},
|
||||
// Call when update related error was caught
|
||||
onUpdateError: function(e) {},
|
||||
// Call when response related error was caught
|
||||
onResponseError: function(e) {}
|
||||
}.extend(options);
|
||||
|
||||
/**
|
||||
* Binds request's token and callback function
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
this.callbacks = {};
|
||||
|
||||
/**
|
||||
* Array of periodically called functions
|
||||
* @type Array
|
||||
* @private
|
||||
*/
|
||||
this.callPeriodically = [];
|
||||
|
||||
/**
|
||||
* Options for an Ajax.Request object
|
||||
* @type Array
|
||||
* @private
|
||||
*/
|
||||
this.ajaxOptions = {
|
||||
_method: 'post',
|
||||
asynchronous: true,
|
||||
timeout: 5000,
|
||||
onComplete: chatServer.receiveResponse.bind(chatServer),
|
||||
onException: chatServer.onTransportError.bind(chatServer),
|
||||
onTimeout: chatServer.onTimeout.bind(chatServer)
|
||||
}
|
||||
|
||||
/**
|
||||
* An object of the Ajax.Request class
|
||||
* @type Ajax.Request
|
||||
* @private
|
||||
*/
|
||||
this.ajaxRequest = null;
|
||||
|
||||
/**
|
||||
* This buffer store requests and responses between sending packages
|
||||
* @private
|
||||
*/
|
||||
this.buffer = [];
|
||||
|
||||
/**
|
||||
* Contains object of registered functions handlers
|
||||
* @private
|
||||
*/
|
||||
this.functions = {}
|
||||
|
||||
/**
|
||||
* An instance of the MibewAPI class
|
||||
* @type MibewAPI
|
||||
* @private
|
||||
*/
|
||||
this.mibewAPI = new MibewAPI(new MibewAPICoreInteraction());
|
||||
},
|
||||
|
||||
/**
|
||||
* Make call to the chat server
|
||||
*
|
||||
* @param {Oblect[]} functionsList List of the function objects. See Mibew API
|
||||
* for details.
|
||||
* @param {Function} callbackFunction
|
||||
* @param {Boolean} forceSend Force requests buffer send right after call
|
||||
* @returns {Boolean} boolean true on success and false on failure
|
||||
*/
|
||||
callFunctions: function(functionsList, callbackFunction, forceSend) {
|
||||
try {
|
||||
// Check function objects
|
||||
if (!(functionsList instanceof Array)) {
|
||||
throw new Error("The first arguments must be an array");
|
||||
}
|
||||
for (var i in functionsList) {
|
||||
// Filter 'Prototype' properties
|
||||
if (! functionsList.hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
this.mibewAPI.checkFunction(functionsList[i], false);
|
||||
}
|
||||
|
||||
// Generate request token
|
||||
var token = this.generateToken();
|
||||
// Store callback function
|
||||
this.callbacks[token] = callbackFunction;
|
||||
|
||||
// Add request to buffer
|
||||
this.buffer.push({
|
||||
'token': token,
|
||||
'functions': functionsList
|
||||
});
|
||||
if (forceSend) {
|
||||
// Force update
|
||||
this.update();
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle errors
|
||||
this.options.onCallError(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Call function at every request to build functions list
|
||||
*
|
||||
* @param {Function} functionsListBuilder Call before every request to build a
|
||||
* list of functions that must be called
|
||||
* @param {Function} callbackFunction Call after response received
|
||||
*/
|
||||
callFunctionsPeriodically: function(functionsListBuilder, callbackFunction) {
|
||||
this.callPeriodically.push({
|
||||
functionsListBuilder: functionsListBuilder,
|
||||
callbackFunction: callbackFunction
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates unique request token
|
||||
*
|
||||
* @private
|
||||
* @returns {String} Request token
|
||||
*/
|
||||
generateToken: function() {
|
||||
var token;
|
||||
do {
|
||||
// Create token
|
||||
token = "wnd" +
|
||||
(new Date()).getTime().toString() +
|
||||
(Math.round(Math.random() * 50)).toString();
|
||||
// Check token uniqueness
|
||||
} while(token in this.callbacks);
|
||||
return token;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process request
|
||||
*
|
||||
* @param {Object} requestObject Request object. See Mibew API for details.
|
||||
* @private
|
||||
*/
|
||||
processRequest: function(requestObject) {
|
||||
var context = new MibewAPIExecutionContext();
|
||||
|
||||
// Get result function
|
||||
var resultFunction = this.mibewAPI.getResultFunction(
|
||||
requestObject.functions,
|
||||
this.callbacks.hasOwnProperty(requestObject.token)
|
||||
);
|
||||
|
||||
if (resultFunction === null) {
|
||||
// Result function not found
|
||||
for (var i in requestObject.functions) {
|
||||
if (! requestObject.functions.hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
// Execute functions
|
||||
this.processFunction(requestObject.functions[i], context);
|
||||
// Build and store result
|
||||
this.buffer.push(this.mibewAPI.buildResult(
|
||||
context.getResults(),
|
||||
requestObject.token
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Result function found
|
||||
if (this.callbacks.hasOwnProperty(requestObject.token)) {
|
||||
// Invoke callback
|
||||
this.callbacks[requestObject.token](resultFunction.arguments);
|
||||
// Remove callback
|
||||
delete this.callbacks[requestObject.token];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process function
|
||||
*
|
||||
* @param {Object} functionObject Function object. See Mibew API for details
|
||||
* @param {MibewAPIExecutionContext} context Execution context
|
||||
* @private
|
||||
*/
|
||||
processFunction: function(functionObject, context) {
|
||||
if (! this.functions.hasOwnProperty(functionObject["function"])) {
|
||||
return;
|
||||
}
|
||||
// Get function arguments with replaced refences
|
||||
var functionArguments = context.getArgumentsList(functionObject);
|
||||
|
||||
var results = {};
|
||||
for (var i in this.functions[functionObject["function"]]) {
|
||||
if (! this.functions[functionObject["function"]].hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
// Get results
|
||||
results.extend(this.functions[functionObject["function"]][i](
|
||||
functionArguments
|
||||
));
|
||||
}
|
||||
|
||||
// Add function results to the execution context
|
||||
context.storeFunctionResults(functionObject, results);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send the request to the chat server
|
||||
*
|
||||
* @param {Object[]} requestsList Array of requests that must be sent to the
|
||||
* chat server
|
||||
* @private
|
||||
*/
|
||||
sendRequests: function(requestsList) {
|
||||
// Create new AJAX request
|
||||
this.ajaxRequest = new Ajax.Request(
|
||||
this.options.servl,
|
||||
this.ajaxOptions.extend({
|
||||
parameters: 'data=' + this.mibewAPI.encodePackage(requestsList)
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up next automatic updater iteration
|
||||
*/
|
||||
runUpdater: function() {
|
||||
if (this.updateTimer == null) {
|
||||
this.update();
|
||||
}
|
||||
this.updateTimer = setTimeout(
|
||||
this.update.bind(this),
|
||||
this.options.requestsFrequency * 1000
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Restarts the automatic updater
|
||||
*/
|
||||
restartUpdater: function() {
|
||||
// Clear timeout
|
||||
if (this.updateTimer) {
|
||||
clearTimeout(this.updateTimer);
|
||||
}
|
||||
// Clear request onComplete callback
|
||||
if (this.ajaxRequest._options) {
|
||||
this.ajaxRequest._options.onComplete = undefined;
|
||||
}
|
||||
// Update thread
|
||||
this.update();
|
||||
// Restart updater. Try to reconnect after a while
|
||||
this.updateTimer = setTimeout(
|
||||
this.update.bind(this),
|
||||
1000
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send request for update thread and client code's requests
|
||||
* @private
|
||||
*/
|
||||
update: function() {
|
||||
if (this.updateTimer) {
|
||||
clearTimeout(this.updateTimer);
|
||||
}
|
||||
for (var i = 0; i < this.callPeriodically.length; i++) {
|
||||
this.callFunctions(
|
||||
this.callPeriodically[i].functionsListBuilder(),
|
||||
this.callPeriodically[i].callbackFunction
|
||||
);
|
||||
}
|
||||
// Check buffer length
|
||||
if (this.buffer.length == 0) {
|
||||
// Rerun updater later
|
||||
this.runUpdater();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Send requests
|
||||
this.sendRequests(this.buffer);
|
||||
// Clear requests buffer
|
||||
this.buffer = [];
|
||||
} catch (e) {
|
||||
// Handle errors
|
||||
this.options.onUpdateError(e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process response from the Core
|
||||
*
|
||||
* @param {String} responseObject The response object provided by
|
||||
* Ajax.Request class
|
||||
* @private
|
||||
*/
|
||||
receiveResponse: function(responseObject) {
|
||||
// Do not parse empty responses
|
||||
if (responseObject.response == '') {
|
||||
this.runUpdater();
|
||||
}
|
||||
try {
|
||||
var packageObject = this.mibewAPI.decodePackage(responseObject.response);
|
||||
for (var i in packageObject.requests) {
|
||||
this.processRequest(packageObject.requests[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
this.options.onResponseError(e);
|
||||
} finally {
|
||||
this.runUpdater();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add function that can be called by the Core
|
||||
*
|
||||
* @param {String} functionName Name of the function
|
||||
* @param {Function} handler Provided function
|
||||
*/
|
||||
registerFunction: function(functionName, handler) {
|
||||
if (!(functionName in this.functions)) {
|
||||
this.functions[functionName] = [];
|
||||
}
|
||||
this.functions[functionName].push(handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Call on all AJAX transport errors
|
||||
* @param {Ajax.Request} transport AJAX Transport object
|
||||
* @param {Error} e Error object
|
||||
*/
|
||||
onTransportError: function (transport, e) {
|
||||
this.restartUpdater();
|
||||
this.options.onTransportError(e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Call on all timeouts
|
||||
*/
|
||||
onTimeout: function(transport) {
|
||||
this.restartUpdater();
|
||||
this.options.onTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
ChatThreadUpdater = Class.create();
|
||||
ChatThreadUpdater.prototype = {
|
||||
/**
|
||||
|
387
src/messenger/webim/js/source/chatserver.js
Normal file
387
src/messenger/webim/js/source/chatserver.js
Normal file
@ -0,0 +1,387 @@
|
||||
/**
|
||||
* @preserve This file is part of Mibew Messenger project.
|
||||
* http://mibew.org
|
||||
*
|
||||
* Copyright (c) 2005-2011 Mibew Messenger Community
|
||||
* License: http://mibew.org/license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implemets server interaction functionality
|
||||
*/
|
||||
ChatServer = Class.create();
|
||||
/**
|
||||
* @todo Think about error handling
|
||||
*/
|
||||
ChatServer.prototype = {
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
initialize: function(options) {
|
||||
var chatServer = this;
|
||||
|
||||
/**
|
||||
* Update timer
|
||||
*/
|
||||
this.updateTimer = null;
|
||||
|
||||
/**
|
||||
* Options for the ChatServer object
|
||||
* @private
|
||||
* @todo Check onResponseError handler
|
||||
*/
|
||||
this.options = {
|
||||
// Server gateway URL
|
||||
servl: "",
|
||||
// Frequency for automatic updater
|
||||
requestsFrequency: 2,
|
||||
// Call on request timeout
|
||||
onTimeout: function() {},
|
||||
// Call when transport error was caught
|
||||
onTransportError: function(e) {},
|
||||
// Call when callFunctions related error was caught
|
||||
onCallError: function(e) {},
|
||||
// Call when update related error was caught
|
||||
onUpdateError: function(e) {},
|
||||
// Call when response related error was caught
|
||||
onResponseError: function(e) {}
|
||||
}.extend(options);
|
||||
|
||||
/**
|
||||
* Binds request's token and callback function
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
this.callbacks = {};
|
||||
|
||||
/**
|
||||
* Array of periodically called functions
|
||||
* @type Array
|
||||
* @private
|
||||
*/
|
||||
this.callPeriodically = [];
|
||||
|
||||
/**
|
||||
* Options for an Ajax.Request object
|
||||
* @type Array
|
||||
* @private
|
||||
*/
|
||||
this.ajaxOptions = {
|
||||
_method: 'post',
|
||||
asynchronous: true,
|
||||
timeout: 5000,
|
||||
onComplete: chatServer.receiveResponse.bind(chatServer),
|
||||
onException: chatServer.onTransportError.bind(chatServer),
|
||||
onTimeout: chatServer.onTimeout.bind(chatServer)
|
||||
}
|
||||
|
||||
/**
|
||||
* An object of the Ajax.Request class
|
||||
* @type Ajax.Request
|
||||
* @private
|
||||
*/
|
||||
this.ajaxRequest = null;
|
||||
|
||||
/**
|
||||
* This buffer store requests and responses between sending packages
|
||||
* @private
|
||||
*/
|
||||
this.buffer = [];
|
||||
|
||||
/**
|
||||
* Contains object of registered functions handlers
|
||||
* @private
|
||||
*/
|
||||
this.functions = {}
|
||||
|
||||
/**
|
||||
* An instance of the MibewAPI class
|
||||
* @type MibewAPI
|
||||
* @private
|
||||
*/
|
||||
this.mibewAPI = new MibewAPI(new MibewAPICoreInteraction());
|
||||
},
|
||||
|
||||
/**
|
||||
* Make call to the chat server
|
||||
*
|
||||
* @param {Oblect[]} functionsList List of the function objects. See Mibew API
|
||||
* for details.
|
||||
* @param {Function} callbackFunction
|
||||
* @param {Boolean} forceSend Force requests buffer send right after call
|
||||
* @returns {Boolean} boolean true on success and false on failure
|
||||
*/
|
||||
callFunctions: function(functionsList, callbackFunction, forceSend) {
|
||||
try {
|
||||
// Check function objects
|
||||
if (!(functionsList instanceof Array)) {
|
||||
throw new Error("The first arguments must be an array");
|
||||
}
|
||||
for (var i in functionsList) {
|
||||
// Filter 'Prototype' properties
|
||||
if (! functionsList.hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
this.mibewAPI.checkFunction(functionsList[i], false);
|
||||
}
|
||||
|
||||
// Generate request token
|
||||
var token = this.generateToken();
|
||||
// Store callback function
|
||||
this.callbacks[token] = callbackFunction;
|
||||
|
||||
// Add request to buffer
|
||||
this.buffer.push({
|
||||
'token': token,
|
||||
'functions': functionsList
|
||||
});
|
||||
if (forceSend) {
|
||||
// Force update
|
||||
this.update();
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle errors
|
||||
this.options.onCallError(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Call function at every request to build functions list
|
||||
*
|
||||
* @param {Function} functionsListBuilder Call before every request to build
|
||||
* a list of functions that must be called
|
||||
* @param {Function} callbackFunction Call after response received
|
||||
*/
|
||||
callFunctionsPeriodically: function(functionsListBuilder, callbackFunction) {
|
||||
this.callPeriodically.push({
|
||||
functionsListBuilder: functionsListBuilder,
|
||||
callbackFunction: callbackFunction
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates unique request token
|
||||
*
|
||||
* @private
|
||||
* @returns {String} Request token
|
||||
*/
|
||||
generateToken: function() {
|
||||
var token;
|
||||
do {
|
||||
// Create token
|
||||
token = "wnd" +
|
||||
(new Date()).getTime().toString() +
|
||||
(Math.round(Math.random() * 50)).toString();
|
||||
// Check token uniqueness
|
||||
} while(token in this.callbacks);
|
||||
return token;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process request
|
||||
*
|
||||
* @param {Object} requestObject Request object. See Mibew API for details.
|
||||
* @private
|
||||
*/
|
||||
processRequest: function(requestObject) {
|
||||
var context = new MibewAPIExecutionContext();
|
||||
|
||||
// Get result function
|
||||
var resultFunction = this.mibewAPI.getResultFunction(
|
||||
requestObject.functions,
|
||||
this.callbacks.hasOwnProperty(requestObject.token)
|
||||
);
|
||||
|
||||
if (resultFunction === null) {
|
||||
// Result function not found
|
||||
for (var i in requestObject.functions) {
|
||||
if (! requestObject.functions.hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
// Execute functions
|
||||
this.processFunction(requestObject.functions[i], context);
|
||||
// Build and store result
|
||||
this.buffer.push(this.mibewAPI.buildResult(
|
||||
context.getResults(),
|
||||
requestObject.token
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Result function found
|
||||
if (this.callbacks.hasOwnProperty(requestObject.token)) {
|
||||
// Invoke callback
|
||||
this.callbacks[requestObject.token](resultFunction.arguments);
|
||||
// Remove callback
|
||||
delete this.callbacks[requestObject.token];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process function
|
||||
*
|
||||
* @param {Object} functionObject Function object. See Mibew API for details
|
||||
* @param {MibewAPIExecutionContext} context Execution context
|
||||
* @private
|
||||
*/
|
||||
processFunction: function(functionObject, context) {
|
||||
if (! this.functions.hasOwnProperty(functionObject["function"])) {
|
||||
return;
|
||||
}
|
||||
// Get function arguments with replaced refences
|
||||
var functionArguments = context.getArgumentsList(functionObject);
|
||||
|
||||
var results = {};
|
||||
for (var i in this.functions[functionObject["function"]]) {
|
||||
if (! this.functions[functionObject["function"]].hasOwnProperty(i)) {
|
||||
continue;
|
||||
}
|
||||
// Get results
|
||||
results.extend(this.functions[functionObject["function"]][i](
|
||||
functionArguments
|
||||
));
|
||||
}
|
||||
|
||||
// Add function results to the execution context
|
||||
context.storeFunctionResults(functionObject, results);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send the request to the chat server
|
||||
*
|
||||
* @param {Object[]} requestsList Array of requests that must be sent to the
|
||||
* chat server
|
||||
* @private
|
||||
*/
|
||||
sendRequests: function(requestsList) {
|
||||
// Create new AJAX request
|
||||
this.ajaxRequest = new Ajax.Request(
|
||||
this.options.servl,
|
||||
this.ajaxOptions.extend({
|
||||
parameters: 'data=' + this.mibewAPI.encodePackage(requestsList)
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up next automatic updater iteration
|
||||
*/
|
||||
runUpdater: function() {
|
||||
if (this.updateTimer == null) {
|
||||
this.update();
|
||||
}
|
||||
this.updateTimer = setTimeout(
|
||||
this.update.bind(this),
|
||||
this.options.requestsFrequency * 1000
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Restarts the automatic updater
|
||||
*/
|
||||
restartUpdater: function() {
|
||||
// Clear timeout
|
||||
if (this.updateTimer) {
|
||||
clearTimeout(this.updateTimer);
|
||||
}
|
||||
// Clear request onComplete callback
|
||||
if (this.ajaxRequest._options) {
|
||||
this.ajaxRequest._options.onComplete = undefined;
|
||||
}
|
||||
// Update thread
|
||||
this.update();
|
||||
// Restart updater. Try to reconnect after a while
|
||||
this.updateTimer = setTimeout(
|
||||
this.update.bind(this),
|
||||
1000
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send request for update thread and client code's requests
|
||||
* @private
|
||||
*/
|
||||
update: function() {
|
||||
if (this.updateTimer) {
|
||||
clearTimeout(this.updateTimer);
|
||||
}
|
||||
for (var i = 0; i < this.callPeriodically.length; i++) {
|
||||
this.callFunctions(
|
||||
this.callPeriodically[i].functionsListBuilder(),
|
||||
this.callPeriodically[i].callbackFunction
|
||||
);
|
||||
}
|
||||
// Check buffer length
|
||||
if (this.buffer.length == 0) {
|
||||
// Rerun updater later
|
||||
this.runUpdater();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Send requests
|
||||
this.sendRequests(this.buffer);
|
||||
// Clear requests buffer
|
||||
this.buffer = [];
|
||||
} catch (e) {
|
||||
// Handle errors
|
||||
this.options.onUpdateError(e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process response from the Core
|
||||
*
|
||||
* @param {String} responseObject The response object provided by
|
||||
* Ajax.Request class
|
||||
* @private
|
||||
*/
|
||||
receiveResponse: function(responseObject) {
|
||||
// Do not parse empty responses
|
||||
if (responseObject.response == '') {
|
||||
this.runUpdater();
|
||||
}
|
||||
try {
|
||||
var packageObject = this.mibewAPI.decodePackage(responseObject.response);
|
||||
for (var i in packageObject.requests) {
|
||||
this.processRequest(packageObject.requests[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
this.options.onResponseError(e);
|
||||
} finally {
|
||||
this.runUpdater();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add function that can be called by the Core
|
||||
*
|
||||
* @param {String} functionName Name of the function
|
||||
* @param {Function} handler Provided function
|
||||
*/
|
||||
registerFunction: function(functionName, handler) {
|
||||
if (!(functionName in this.functions)) {
|
||||
this.functions[functionName] = [];
|
||||
}
|
||||
this.functions[functionName].push(handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Call on all AJAX transport errors
|
||||
* @param {Ajax.Request} transport AJAX Transport object
|
||||
* @param {Error} e Error object
|
||||
*/
|
||||
onTransportError: function (transport, e) {
|
||||
this.restartUpdater();
|
||||
this.options.onTransportError(e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Call on all timeouts
|
||||
*/
|
||||
onTimeout: function(transport) {
|
||||
this.restartUpdater();
|
||||
this.options.onTimeout()
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ var chatParams = {
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chatserver.js"></script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script>
|
||||
<style type="text/css">
|
||||
#header{
|
||||
|
@ -38,6 +38,7 @@ var chatParams = {
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chatserver.js"></script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script>
|
||||
<style type="text/css">
|
||||
.tplimage {
|
||||
|
@ -79,6 +79,7 @@
|
||||
window.onresize = setTrueHeight;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript" src="${webimroot}/js/${jsver}/chatserver.js"></script>
|
||||
<script type="text/javascript" src="${webimroot}/js/${jsver}/chat.js"></script>
|
||||
</head>
|
||||
<body class="body">
|
||||
|
@ -38,6 +38,7 @@ var chatParams = {
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chatserver.js"></script>
|
||||
<script type="text/javascript" language="javascript" src="${webimroot}/js/${jsver}/chat.js"></script>
|
||||
<style type="text/css">
|
||||
.isound { background: url(${tplroot}/images/buttons/sound.gif) no-repeat; width: 19px; height: 19px; }
|
||||
|
Loading…
Reference in New Issue
Block a user