суббота, 22 ноября 2008 г.

AS3 + VKontakte API

Давненько я не писал сюда ничего. На днях решил попробовать писать на AS3 (Action Script 3) в среде Adobe Flash CS3 с использованием "ВКонтакте API". Помучавшись с запросами к api.vkontakte.ru нашёл классы, призванные облегчить нам общение с ВКонтактом: vkontakte-as3

Всё бы хорошо, если не ограничение на 3 запроса в секунду . . . Классы, кстати вовсе не учитывают этого ограничения и лупят все запросы подряд. Написал простенький класс для распределения запросов по времени:

import flash.utils.*;
package main
{
 import ru.vkontakte.VKApp;

 public class TimeMgr
 {
    public var vk:VKApp = null;
    private var isWaiting:Boolean = false;
    private var prePreLastTime:Number = 0; // PrePreLast query time
    private var preLastTime:Number = 0;  // PreLast query time
    private var lastTime:Number = 0;  // Last query time
    private var arr:Array = new Array();
    private var realFunc:Function = null;
 
    public function TimeMgr(vk_:VKApp) {
     vk = vk_;
    }
 
    public function addQuery( ... args):void
    {
     arr.push(args);
     if (isWaiting == false) {
        isWaiting = true;
        sendQuery(arr[0]);
     }
    }
 
    private function justReleased(res:XML)
    {
     // Если ошибка
     if ((res.name() != 'response') &&
        (res.toString().indexOf('Too many') == 0))
     {
        setTimeout(sendQuery, 1000, arr[0]);
        return;
     }
 
     // Отправка по месту назначения
     if (realFunc != null)
        setTimeout(realFunc, 0, res);
 
     // Отправка следущего запроса из очереди
     arr.shift();
     if (arr.length > 0)
        sendQuery(arr[0]);
     else
        isWaiting = false;
    }
 
    private function sendQuery(arg:Array)
    {
     // Куда передать ответ
     if (arg[0] == vk.getVariable)
        realFunc = arg[2];
     else if (arg[0] == vk.putVariable)
        realFunc = arg[3];
 
     var t:Number = (new Date()).time;
     if (t - prePreLastTime >= 1500) {
        if (arg[0] == vk.getVariable)
         vk.getVariable(arg[1], justReleased);
        else if (arg[0] == vk.putVariable)
         vk.putVariable(arg[1], arg[2], justReleased);
     } else {
        if (arg[0] == vk.getVariable)
         setTimeout( arg[0], 1500 - (t - prePreLastTime),
                     arg[1], justReleased);
        else if (arg[0] == vk.putVariable)
         setTimeout( arg[0], 1500 - (t - prePreLastTime),
                     arg[1], arg[2], justReleased);
     }
 
     prePreLastTime = preLastTime;
     preLastTime = lastTime;
     lastTime = t;
    }
 }
}


* This source code was highlighted with Source Code Highlighter.

Теперь пишем код так:
// Не забудьте инициализацию vk:VKApp
var timer:TimeMgr = new TimeMgr(vk);

// Функция вызываемая при получении ответа севера
function vFunc(res:XML):void {
 trace(res.name() + ':' + res.toString());
}

// <span style="font-style:italic;">Было раньше:</span>
// vk.putVariable(50, 'Test data', null);
// vk.getVariable(50, vFunc);

// <span style="font-style:italic;">Стало теперь:</span>
timer.addQuery(vk.putVariable, 50, 'Test data', null);
timer.addQuery(vk.getVariable, 50, vFunc);


* This source code was highlighted with Source Code Highlighter.


Запросов можно делать теперь сколько угодно, менеджер сам распределит их по времени. А вообще считаю это ограничение слишком уж строгим, ну хоть 10 в секунду было бы уже нормально. Можно было бы делать достаточно динамичные игры. Например, сетевой змейке - 3 запроса в секунду явно перекрыли кислород . . .


Полезные ссылки:
1. Повышение производительности AS3 приложений
2. Bitwise gems - fast integer math


Читать дальше