Just Blog about nothing

3Сен/11Off

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

Flash2PHP logo (alpha)

Тот факт, что 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 );
Метки записи: , , Комментарии
Комментарии (0) Пинги (0)

Извините, комментировать здесь запрещено.

Trackbacks are disabled.

Social Widgets powered by AB-WebLog.com.