Flash2PHP, js библиотека (beta)

Тот факт, что F2P не использует формат adobe, а оперирует данными в формате JSON с использованием стандартного сжатия, позволяет использовать его не только при взаимодействии flash-приложения с php сервером, но также и любого другого клиентского приложения. При этом сохраняется не только привычная логика, но также достигается универсальность серверной части - к одному серверу могут подключаться несколько клиентов, написанных на разных языках.
В частности, в ходе реализации проекта по созданию многопользовательской online-игры на htlm5+css3+js мною была реализована библиотека для взаимодействия с сервером на языка JavaScript.
В силу узкой направленности проекта библиотека была хорошо проверена в браузерах Chrome 13 и Safari 5. В браузерах Firefox 5 и Opera 11 при беглой проверке глюков тоже замечено не было. В IE не тестировалась. В JavaScript я новичок, поэтому класс написан плохо.
if (!ru) var ru = {};
if (!('vbinc' in ru)) ru.vbinc = {};
if (!('net' in ru.vbinc)) ru.vbinc.net = {};
/**
* Создаёт новый класс для посылки запросов к F2P серверу
* и обработки ответов от него.
* Можно делать сколько угодно запросов подряд, но при этом
* они всё равно буде выполнены по очереди
* @class
* @param {String} gateway адрес сервиса для запросов
* @param {String} [defaultPackage=''] адрес сервиса для запросов
* @param {Boolean} [useShort=false] использовать которкие имена или нет
*/
var F2PInvoker = ru.vbinc.net.F2PInvoker = function( gateway, defaultPackage, useShort )
{
/**
* Код ошибки неудачного запроса
* @constant
* @type Number
*/
F2PInvoker.ERRNO_REQUEST_FAILED = 1000001;
/**
* Код ошибки превышения таймаута ожидания
* @constant
* @type Number
*/
F2PInvoker.ERRNO_REQUEST_TIMEOUT = 1000002;
/**
* Код ошибки при парсинге результата
* @constant
* @type Number
*/
F2PInvoker.ERRNO_PARSE_RESULT = 1000003;
/**
* Неизвестный сервис
* @constant
* @type Number
*/
F2PInvoker.ERRNO_UNKNOWN_SERVICE = 19001;
/**
* Неизвестный метод
* @constant
* @type Number
*/
F2PInvoker.ERRNO_UNKNOWN_METHOD = 19002;
/**
* Неверные аргументы
* @constant
* @type Number
*/
F2PInvoker.ERRNO_WRONG_PARAMS = 19003;
/**
* Неверное количество аргументов
* @constant
* @type Number
*/
F2PInvoker.ERRNO_WRONG_NUM_ARGS = 19004;
/**
* Вызов заблокирован функцией beforeFilter
* @constant
* @type Number
*/
F2PInvoker.ERRNO_AUTH_BLOCKED = 19005;
/**
* Ошибка при вызове метода
* @constant
* @type Number
*/
F2PInvoker.ERRNO_CALL_METHOD_ERROR = 19006;
/**
* Ошибка при исполнении метода
* @constant
* @type Number
*/
F2PInvoker.ERRNO_EXECUTE_METHOD_ERROR = 19007;
/**
* Время ожидания ответа с сервера
* в секундах
* @type Number
*/
var timeout = 30;
/**
* Адрес сервера
* @private
* @type String
*/
var host = '';
/**
* Package сервисов
* @private
* @type String
*/
var servicePackage = '';
/**
* Использовать короткие имена или нет
* @private
* @type Boolean
*/
var useShortNames = false;
/**
* Объект для запросов
* @private
* @type XMLHttpRequest
*/
var xhr = new XMLHttpRequest();
/**
* Идентификатор таймера ожидания ответа с сервера
* @private
* @type Number
*/
var timeoutId = -1;
/**
* Массив объектов для запросов
* @private
* @type Array
*/
var queue = [];
/**
* В данное время отправлен запрос на сервер
* @private
* @type Boolean
*/
var busy = false;
var _serviceParam = '';
var _methodParam = '';
var _paramsParam = '';
// конструктор
(function()
{
if (!JSON) throw 'Для корректной работы необходима библиотека JSON (http://www.json.org/js.html)';
host = gateway;
servicePackage = defaultPackage || '';
useShortNames = useShortNames || false;
if (useShortNames) {
_serviceParam = 's';
_methodParam = 'm';
_paramsParam = 'p';
} else {
_serviceParam = 'service';
_methodParam = 'method';
_paramsParam = 'params';
}
xhr.onreadystatechange = function(){
// readyState может принимать следующие значения
// 0 - Unitialized
// 1 - Loading
// 2 - Loaded
// 3 - Interactive
// 4 - Complete
if (xhr.readyState == 4) onRequestComplete();
};
})();
/**
* Отсылает запрос на сервер
* @param {String} service Имя сервиса
* @param {String} method Название метода на сервере
* @param onResult функция - обработчик ответа с сервера.
* Если с сервера приходит ответ - в обработчик передаётся распарсенный объект,
* если ошибка запроса - передаётся объект с номером полями error и errno
* (для номера ошибки используются
* <tt>F2PInvoket.ERRNO_REQUEST_FAILED</tt>,
* <tt>F2PInvoket.ERRNO_REQUEST_TIMEOUT</tt>,
* <tt>F2PInvoket.ERRNO_PARSE_RESULT</tt>)
* @param _param любое число параметров для передачи на сервер
*/
this.request = function( service, method, onResult, _param ) {
var params = [];
for(var i=3; i<arguments.length; i++) {
params.push( arguments[i] );
}
if (servicePackage != '') service = servicePackage + '.' + service;
// добавляем запрос в очередь
queue.push( {
s : service,
m : method,
h : onResult,
p : params
} );
// если не заняты - отправляем сразу
sendRequest();
};
/**
* Устанавливает значение таймуата ожидания ответа от сервера
* @param {Number} value время в секундах
*/
this.setTimeout = function( value ) {
timeout = value;
};
var sendRequest = function() {
// если в очереди есть элементы
// - выполняем следующий запрос
if (!busy && queue.length > 0) {
reqData = queue[0];
busy = true;
// формируем параметры запроса
var params = '';
for (var i=0; i < reqData.p.length; i++) {
if (params != '') params += ',';
params += JSON.stringify( reqData.p[i] );
};
params = _serviceParam + '=' + reqData.s +
'&' + _methodParam + '=' + reqData.m +
( params != '' ? '&' + _paramsParam + '=[' + params + ']' : '' );
timeoutId = setTimeout( onTimeout, timeout * 1000 );
xhr.open( 'POST', host, true );
xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
xhr.send( params );
}
};
var onRequestComplete = function() {
// если статус ответа 200 - значит пришёл корректный ответ
if (xhr.status == 200) {
try {
var result = JSON.parse( xhr.responseText );
} catch (e) {
// ошибка парсинга данных
onError( F2PInvoker.ERRNO_PARSE_RESULT );
return;
}
// вызов обработчкиа
callHandler( result );
requestComplete();
} else {
onError( F2PInvoker.ERRNO_REQUEST_FAILED );
}
};
var onError = function( errno ) {
callHandler( { errno : errno } );
requestComplete();
};
var callHandler = function( obj ) {
queue[0].h( obj );
return true;
};
function onTimeout( errno ) {
xhr.abort();
onError( F2PInvoker.ERRNO_REQUEST_TIMEOUT );
};
var requestComplete = function() {
// убираем первый элемент из списка,
// т.к. считаем что этот запрос выполнен
queue.shift();
busy = false;
clearTimeout( timeoutId );
timeoutId = -1;
// выполняем следующий запрос
sendRequest();
};
};
Класс делает асинхронный запрос на сервер и передает распарсенный ответ с сервера в функцию-обработчик. Может использоваться в любом AJAX-приложении. Пример: вызов метода auth сервиса AuthService (пакет testproject) с аргументами login, pass:
// создание экземпляра F2PInvoker
var f2p = new ru.vbinc.net.F2PInvoker( 'http://f2purl/gateway.php', 'testproject' );
// инициализация дополнительных переменных
var login = 'user'; // логин для передачи на сервер
var pass = 'password'; // пароль для передачи на сервер
// обработчик результата выполнения запроса
function onResult( resObject ) {
// код обработчика
};
// вызов метода на сервера
f2p.request( 'AuthService', 'auth', onResult, login, pass );