mibew/src/messenger/webim/js/source/mibewapi.js
Dmitriy Simushev 4aa44861b4 Add parameters to the Window-to-Core interaction
Add 'threadId' and 'token' obligatory parameters to the
Window-to-Core interaction type
2013-03-13 15:32:40 +00:00

518 lines
16 KiB
JavaScript

/**
* @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
*/
/**
* Mibew API class constructor
*
* @constructor
* @param {MibewAPIInteraction} interaction An object that represents
* interaction type
*/
function MibewAPI(interaction) {
/**
* Version of the MIBEW API protocol implemented by the object
*/
this.protocolVersion = "1.0";
// Check interaction type
if (typeof interaction != "object" ||
!(interaction instanceof MibewAPIInteraction)) {
throw new Error("Wrong interaction type");
}
/**
* An object that encapsulates type of the interaction
* @private
* @type MibewAPIInteraction
*/
this.interaction = interaction;
}
/**
* Validate function
*
* Throws an Error object if function is not valid.
*
* @param {Object} functionObject The function. See Mibew API for details.
* @param {Boolean} [filterReservedFunctions=false]. Determine if function
* name must not be in reserved list
* @thows Error
*/
MibewAPI.prototype.checkFunction = function(functionObject, filterReservedFunctions) {
filterReservedFunctions = filterReservedFunctions || false;
// Check function name
if (typeof functionObject["function"] == "undefined" ||
functionObject["function"] == "") {
throw new Error("Cannot call for function with no name");
}
if (filterReservedFunctions) {
for (var i = 0; i < this.interaction.reservedFunctionNames.length; i++) {
if (functionObject["function"] ==
this.interaction.reservedFunctionNames[i]) {
throw new Error(
"'" + functionObject["function"] +
"' is reserved function name"
);
}
}
}
// Check function's arguments
if (typeof functionObject.arguments != "object") {
throw new Error(
"There are no arguments in '" + functionObject["function"] +
"' function"
);
}
var obligatoryArgumentsCount = 0;
var obligatoryArgumentsList = this.interaction.getObligatoryArguments(
functionObject['function']
);
argumentsLoop:
for (var argName in functionObject.arguments){
for (var i = 0; i < obligatoryArgumentsList.length; i++) {
if (argName == obligatoryArgumentsList[i]) {
obligatoryArgumentsCount++;
continue argumentsLoop;
}
}
}
if (obligatoryArgumentsCount != obligatoryArgumentsList.length) {
throw new Error(
"Not all obligatory arguments are set in '" +
functionObject["function"] + "' function"
);
}
}
/**
* Validate request
*
* Throws an Error object if request is not valid.
*
* @param {Object} requestObject The Request. See Mibew API for details.
* @thows Error
*/
MibewAPI.prototype.checkRequest = function(requestObject) {
// Check token
if (typeof requestObject.token != "string") {
if (typeof requestObject.token == "undefined") {
throw new Error("Empty token");
} else {
throw new Error("Wrong token type");
}
}
if (requestObject.token == "") {
throw new Error("Empty token");
}
// Request must have at least one function
if (typeof requestObject.functions != "object" ||
!(requestObject.functions instanceof Array) ||
requestObject.functions.length == 0) {
throw new Error("Empty functions set");
}
// Check function
for (var i = 0; i < requestObject.functions.length; i++) {
this.checkFunction(requestObject.functions[i]);
}
}
/**
* Validate package.
*
* Throws an Error object if package is not valid.
*
* @param {Object} packageObject The package. See Mibew API for details.
* @thows Error
*/
MibewAPI.prototype.checkPackage = function (packageObject) {
// Check signature
if (typeof packageObject.signature == "undefined") {
throw new Error("Missed package signature");
}
// Check protocol
if (typeof packageObject.proto == "undefined") {
throw new Error("Missed protocol version");
}
if (packageObject.proto != this.protocolVersion) {
throw new Error("Wrong protocol version");
}
// Check async flag
if (typeof packageObject.async == "undefined") {
throw new Error("'async' flag is missed");
}
if (typeof packageObject.async != "boolean") {
throw new Error("Wrong 'async' flag value");
}
// Package must have at least one request
if (typeof packageObject.requests != "object" ||
!(packageObject.requests instanceof Array) ||
packageObject.requests.length == 0) {
throw new Error("Empty requests set");
}
// Check requests in package
for (var i = 0; i < packageObject.requests.length; i++) {
this.checkRequest(packageObject.requests[i]);
}
}
/**
* Search 'result' function in functionsList. If request contains more than
* one result functions throws an Error
*
* @param {Object[]} functionsList Array of functions. See MibewAPI for
* function structure details
* @param {Boolean|null} [existance="null"] (optional) Control existance of
* the 'result' function in request. Use boolean true if 'result' function
* must exists in request, boolean false if must not and null if it doesn't
* matter.
* @returns {Object|null} Function object if 'result' function found and
* null otherwise
* @throws Error
*/
MibewAPI.prototype.getResultFunction = function(functionsList, existance){
if (typeof existance == "undefined") {
existance = null;
}
var resultFunction = null;
// Try to find result function
for (var i in functionsList) {
if (! functionsList.hasOwnProperty(i)) {
continue;
}
if (functionsList[i]["function"] == 'result') {
if (resultFunction !== null) {
// Another result function found
throw new Error(
"Function 'result' already exists in functions list"
);
}
// First 'result' function found
resultFunction = functionsList[i];
}
}
if (existance === true && resultFunction === null) {
// 'result' function must present in request
throw new Error("There is no 'result' function in functions list");
}
if (existance === false && resultFunction !== null) {
throw new Error("There is 'result' function in functions list");
}
return resultFunction;
}
/**
* Builds result package
*
* @param {Object} resultArguments Arguments of the result function
* @param {String} token Token of the result package
* @returns {Object} Result package
*/
MibewAPI.prototype.buildResult = function(resultArguments, token) {
var mergedArguments = resultArguments;
var defaultArguments = this.interaction.getObligatoryArgumentsDefaults('result');
for (var argName in defaultArguments) {
if (! defaultArguments.hasOwnProperty(argName)) {
continue;
}
mergedArguments[argName] = defaultArguments[argName];
}
return {
'token': token,
'functions': [
{
'function' : 'result',
'arguments' : mergedArguments
}
]
}
}
/**
* Encodes package
*
* @param {Object[]} requests Array of the Requests. See Mibew API for
* details.
* @returns {String} Ready for transfer encoded package
*/
MibewAPI.prototype.encodePackage = function(requests) {
var packageObject = {};
packageObject.signature = "";
packageObject.proto = this.protocolVersion;
packageObject.async = true;
packageObject.requests = requests;
return encodeURIComponent(JSON.stringify(packageObject)).replace(/\%20/gi, '+');
}
/**
* Decodes package and validate package structure
*
* Throws an Error object if package cannot be decoded or is not valid
*
* @param {String} encodedPackage Encoded package
* @returns {Object} The Decoded package. See Mibew API for details.
* @throws Error
*/
MibewAPI.prototype.decodePackage = function(encodedPackage){
var decodedPackage = JSON.parse(decodeURIComponent(encodedPackage.replace(/\+/gi, ' ')));
this.checkPackage(decodedPackage);
return decodedPackage;
}
/**
* End of MibewAPI Class
*/
/**
* Represents interaction type
*
* @constructor
*/
function MibewAPIInteraction(){
/**
* Defines obligatory arguments and default values for them
*
* Keys of the array are function names ('*' for all functions). Values are
* arrays of obligatory arguments with key for name of an argument and value
* for default value.
*
* For example:
* <code>
* this.obligatoryArguments = {
* '*': {
* 'return': {},
* 'references': {}
* },
* 'result': {
* 'errorCode': 0
* }
* }
* </code>
* @type Object
* @private
*/
this.obligatoryArguments = {};
/**
* Reserved function's names
*
* Defines reserved(system) function's names described in the Mibew API.
* @type Array
*/
this.reservedFunctionNames = [];
}
/**
* Returns obligatory arguments for the functionName function
*
* @param {String} functionName Function name
* @returns {Array} An array of obligatory arguments
*/
MibewAPIInteraction.prototype.getObligatoryArguments = function(functionName) {
var obligatoryArguments = [];
// Add obligatory for all functions arguments
if (typeof this.obligatoryArguments['*'] == 'object') {
for (var arg in this.obligatoryArguments['*']) {
if (! this.obligatoryArguments['*'].hasOwnProperty(arg)) {
continue;
}
obligatoryArguments.push(arg);
}
}
// Add obligatory arguments for given function
if (typeof this.obligatoryArguments[functionName] == 'object') {
for (var arg in this.obligatoryArguments[functionName]) {
if (! this.obligatoryArguments[functionName].hasOwnProperty(arg)) {
continue;
}
obligatoryArguments.push(arg);
}
}
return obligatoryArguments;
}
/**
* Returns default values of obligatory arguments for the functionName function
*
* @param {String} functionName Function name
* @returns {Object} An object fields names are obligatory arguments and
* values are default values of them
*/
MibewAPIInteraction.prototype.getObligatoryArgumentsDefaults = function(functionName) {
var obligatoryArguments = {};
// Add obligatory for all functions arguments
if (typeof this.obligatoryArguments['*'] == 'object') {
for (var arg in this.obligatoryArguments['*']) {
if (! this.obligatoryArguments['*'].hasOwnProperty(arg)) {
continue;
}
obligatoryArguments[arg] = this.obligatoryArguments['*'][arg];
}
}
// Add obligatory arguments for given function
if (typeof this.obligatoryArguments[functionName] == 'object') {
for (var arg in this.obligatoryArguments[functionName]) {
if (! this.obligatoryArguments[functionName].hasOwnProperty(arg)) {
continue;
}
obligatoryArguments[arg] = this.obligatoryArguments[functionName][arg];
}
}
return obligatoryArguments;
}
/**
* End of MibewAPIInteraction class
*/
/**
* Represents Window to core interaction type
*
* @constructor
* @todo Think about real values!
*/
function MibewAPICoreInteraction() {
this.obligatoryArguments = {
'*': {
'threadId': null,
'token': null,
'return': {},
'references': {}
},
'result': {
'errorCode': 0
}
};
this.reservedFunctionNames = [
'result'
];
}
MibewAPICoreInteraction.prototype = new MibewAPIInteraction();
/**
* Implements functions execution context
*
* @constructor
*/
function MibewAPIExecutionContext() {
/**
* Values which returns after execution of all functions in request
* @private
*/
this.returnValues = {};
/**
* Results of execution of all function in request
* @private
*/
this.functionsResults = [];
}
/**
* Build arguments list by replace all references by values of execution
* context
*
* @param {Object} functionObject The Function. See MibewAPI for details.
* @returns {Array} Arguments list
* @throws Error
*/
MibewAPIExecutionContext.prototype.getArgumentsList = function(functionObject) {
var argumentsList = functionObject.arguments;
var references = functionObject.arguments.references;
var referenceTo, funcNum;
for (var variableName in references) {
if (! references.hasOwnProperty(variableName)) {
continue;
}
referenceTo = null;
funcNum = references[variableName];
// Check target function in context
if (typeof this.functionsResults[funcNum - 1] == "undefined") {
// Wrong function number
throw new Error("Wrong reference in '" +
functionObject['function'] + "' function. Function #" +
funcNum + " does not call yet."
);
}
// Check reference
if (typeof argumentsList[variableName] == "undefined" ||
argumentsList[variableName] == "") {
// Empty argument that should contains reference
throw new Error("Wrong reference in '" +
functionObject['function'] + "' function. " +
"Empty '" + variableName + "' argument."
);
}
referenceTo = argumentsList[variableName];
// Check target value
if (typeof this.functionsResults[funcNum - 1][referenceTo] ==
"undefined") {
throw new Error(
"Wrong reference in '" + functionObject['function'] +
"' function. There is no '" + referenceTo +
"' argument in #" + funcNum + " function results"
);
}
// Replace reference by target value
argumentsList[variableName] = this.functionsResults[funcNum - 1][referenceTo];
}
return argumentsList;
}
/**
* Returns requets results
*
* @returns {Object}
*/
MibewAPIExecutionContext.prototype.getResults = function(){
return this.returnValues;
}
/**
* Stores functions results in execution context and add values to request
* result
*
* @param {Object} functionObject The Function. See MibewAPI for details.
* @param {Object} results Object of the function results.
* @throws Error
*/
MibewAPIExecutionContext.prototype.storeFunctionResults = function(functionObject, results) {
var alias;
// Add value to request results
for (var argName in functionObject.arguments["return"]) {
if (! functionObject.arguments["return"].hasOwnProperty(argName)) {
continue;
}
alias = functionObject.arguments["return"][argName];
if (typeof results[argName] == "undefined") {
throw new Error(
"Variable with name '" + argName + "' is undefined in " +
"the results of the '" + functionObject['function'] +
"' function"
);
}
this.returnValues[alias] = results[argName];
}
// Store function results in execution context
this.functionsResults.push(results);
}
/**
* End of MibewAPIExecutionContext class
*/