Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Psycho Tiger

Рейтинг: 5.00. Голосов: 3.

Пацаны, гоу Вконтакте?

Запись от Psycho Tiger размещена 21.12.2010 в 02:09
Обновил(-а) Psycho Tiger 21.12.2010 в 02:34

Сегодня речь пойдёт о ВконтактеАПИ.
Сперва хотелось бы сказать, что программирую я не первый день. И вот за всю свою карьеру мне до сих пор непонятно - КАК можно было сделать так, что возвращалась бы "Неизвестная ошибка"? Как-то ведь можно было понять что произошла ошибка - ну и выплюнь ты результат, может по нему причину ликвидировать можно было бы. А н-нет. Будем плеваться Unknown Error без объяснений - не барское это дело.
На самом деле лабуды у контакта много, вроде всяких там секретов (хотя в 3 версии серверного АПИ должны убрать) и сигнатур - наверное чтобы хоть как-то защищать переменные всякие, что у них на серверах хранятся. Хотя я не представляю для них другой задачи, кроме как хранения запоминалки настроек - типа звук "вкл-выкл", если настройки не найдены в SharedObject. Так что на кой там защита - тоже для меня загадка.

Но мы не такие. Мы будем делать всё правильно, по пацански. Чтобы конкуренты нам завидовали.
Я вам расскажу сегодня как нужно делать взаимодействие клиент-контакт. Более менее сознательно с контактом я работаю после выхода 3 версии их клиентского API, поэтому если что-то нереализуемо со старыми версиями - уж простите. Постараюсь идти по пунктам.

1) Создали VkontakteConnector? Выбросьте на помойку, причем сразу. О чем это я? Дело в том, что никогда нельзя верить заказчикам. Сегодня одно, завтра другое. Поэтому я придерживаюсь MVC насколько могу, а что касается этого момента... Нужно создавать SocialConnector. Уверяю вас, в один прекрасный день начальник скажет - "а теперь в фейсбук!" и ваша седина сменится лысиной.
Как это делать? У SocialConnector мы создаём поле instance с типом ISocial. ISocial - интерфейс, в котором перечислены все-все методы, которые вы используете. Например, getProfiles(...), getUserApps() и всякие такие. VkontakteConnector реализует ISocial и сам отправляет нужные запросы. В итоге, чтобы узнать информацию о юзере нужно будет сделать вот так:
Код AS3:
socialConnector.instance.getProfiles(1);
Но лично мне instance не нравится. Поэтому мой SocialConnector тоже реализует ISocial, где вся реализация методов заключается в
Код AS3:
public function getProfiles(...):void { instance.getProfiles(...); }
Вообще реализация выглядит как то так:
Код AS3:
private var _instance:ISocial;
...
public function SocialConnector(social:String, flashVars:Object){
super();
switch (social){
case SocialConnector.VKONTAKTE: _instance = new VkontakteConnector(flashVars); break;
case SocialConnector.FACEBOOK: _instance=new FacebookConnector(flashVars); break;
default: throw new ArgumentError("Unknown social");
}
}
Неплохо было бы реализовать ещё геттеры вида isGetProfilesAviable - не у всех соцсетей равные возможности, но мы не о том.
О доставке от SocialConnector желающим думаете сами - я просто делаю dispatchEvent, а подписчики уже парсят сообщение.

Далее речь пойдёт сугубо о контакте, однако к другим соцсетям оное тоже применимо.


2) Кэш, кэш, кэш!
Любая картинка извне, что я загружаю - грузится у меня отдельным классом, который по загрузке считывает bytes, а при обращении в следующий раз к этому адресу - эти bytes скармливает Loader#loadBytes. То есть я не гружу загруженные картинки 2 раза.
С контактом всё куда сложнее. Например, getProfiles. Есть много разных полей у этого getProfiles - имя, фамилия, аватарка, день рождения. И всё это надо кешировать. Да-да, я знаю что этим мало кто занимается. Но надо, очень надо.
Реализация: я бы создал класс VkontakteUser, в котором перечислил вообще все возможные поля от getProfiles. Метод getProfiles VkontakteConnector`а принимает массив uid`ов пользователей и fields - поля, что нужно от юзеров знать. Перед отпрвкой мега-супер-кеш-класс бежит по всем uid`ам и смотрит, есть ли такие в кеше, а если и есть - то все ли поля загружены. Если не всё загружено - он грузит это дело с контакта, запоминает в кеше и выплёвывает из кеша. Почему я рекомендую выплёвывать уже из кеша после загрузки: например, у пользователя известно имя, но не известна фамилия. Спросили только фамилию... и теперь нужно склеивать имя с фамилией и выплёвывать клиенту что-то такое, что он ожидает. Когда таких параметров много - это тяжело. Другое дело, сохранив это в кеш и взяв это дело "начистую оттуда". По мне это гораздо проще.
Однако, говоря "взяв из кеша" я имею ввиду что всё это дело происходит прозрачно для клиента. Клиент не подозревает о существовании кеша как такового - если его убрать, то клиент не должен что-нибудь почувствовать. Под клиентом я, конечно, подразумеваю флешку.
По поводу getProfiles и аватарок: можно, конечно, выплевывать сразу bytes для аватарки, но я так не делаю. Я выплевываю адрес, а кэш картинок смотрит, есть ли по такому адресу уже загруженная картинка. Вконтакте кэш и картинко-кэш ничего друг о друге не знают. Это кэши разного уровня.
Со всякими getBalance чтобы узнать у юзера баланс тоже нужно делать кэш - а как же! Однако вот незадача: он может изменится, скажете вы. Да, но изменившись вы получите сообщение, по типу сообщений onWindowFocus, onWindowBlur и подобных. Вот тогда кэш можно сбрасывать.
Пользуясь любыми командами - кешируйте их донельзя. А почему?


3) Да потому что можно сделать всего лишь 3 запроса к вконтакту. Вы создаёте очередь запросов, чтобы не отправлять их слишком много? А то отправятся 4 запроса - и пиши пропало. Ошибка будет, что слишком много запросов. Поэтому каждый запрос нужно отправлять скрипя зубами - мало того, что это юзера беспокоит. Ему ведь надо ждать, деньги за трафик отдавать, да ещё и медленнее это дело будет чем из кэша брать. А там мало ли что-то не то, да всё полетит... ой-йо... Но чтобы прокешировать что-то, сперва нужно это получить. Так что без очереди запросов тут не обойтись.
Однако, проблема есть. Отправляя запросы каждые 334 мс мы рассчитываем на идеальную связь вконтакт-клиент. А её не будет. Какой нибудь запрос возьмет и задержится. А задержавшийся ждать не будет - и уйдет пачка запросов вконтакт сразу, а мы так не играем.
Реализация: будет подстраиваться под реалии сурового мира. Отправляя запрос мы должны дождаться его ответа. Дождавшись смотрим время "полёта" запроса. Если оно больше или равно 334 - значит, запрос прошел. Если меньше - выжидаем это время перед тем как заявить, что "касса свободна". Конкретней реализацию можно представить так: запрос кладётся в ассоциативный массив (в хэш (в Object/Dictionary, ну)), где он является ключом. А значение у этого запроса - текущий getTimer. По возвращению или взводим setTimeout/Timer/да что угодно, или уменьшаем на единичку число "ушедших запросов". Можно запрос в виде класса сделать, с геттером free : Boolean... Да как угодно. Как вам удобней. Кстати, не советую выставлять между запросами время в 334 мс. Погрешность таймера всё таки может сыграть своё место. Поэтому я бы поставил 400.
Однако, мы говорили "положить текущий запрос". Очевидно, что текущий запрос положить сложно, нужно положить какой-то его идентификатор. Идентификатор "подпишет" запрос и по возвращению запроса мы всё таки сможем понять, что же он значил.


4) Только скорее эта подпись является не продолжением пункта 3, а совершенно отдельным. Например, вам нужно узнать у кого установлено приложение и своё имя-фамилию. Это 2 разных запроса. Можно, конечно, ждать ответа от первого, потом отправлять второй... Но это будет куда дольше, чем отправить 2 параллельно.
А при пришествии запроса просто посмотреть на его идентификатор и сказать - "баа! Да это же инфа обо мне!". Ляпота, почти свой сервер и клиент, идентифицирующий пакеты.
Реализация: я человек ленивый достаточно, хоть с ленью и борюсь. Но не в этом случае. Я просто скачал пример того, что даём нам сам контакт - простенькое приложение с кнопочками. Я не зря говорил о лени - ищите этот пример сами.
Но нужно его и прокачать. Глядя в код видим кучу замыканий и некрасивый, нечитабельный код. Но на каждого парня с яйцами найдется каждый парень с ножницами, поэтому прикусив нижнюю губу работаем с тем, что есть. Файл DataProvider.as:
Сигнатура sendRequest:
Код AS3:
private function _sendRequest(method:String, options:Object):void {
Неплохо было бы этот options использовать. Я буду передавать ему поле customParameters, где будет хранится что-то там, идентифицирующее мой запрос. Чаще всего - строка, но чем черт не шутит
Ловким движением руки превращаем кусок их кода в кусок моего:
Код AS3:
      var loader:URLLoader = new URLLoader();
      loader.dataFormat = URLLoaderDataFormat.TEXT;
      if (options.onError) {
        loader.addEventListener(IOErrorEvent.IO_ERROR, function():void {
          options.onError("Connection error occured", options.customParameters);
        });
        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function():void {
          options.onError("Security error occured", options.customParameters);
        });
      }
loader.addEventListener(Event.COMPLETE, function(e:Event):void{
        var loader:URLLoader = URLLoader(e.target);
		//trace(loader.data);
		var data: Object = JSON.decode(loader.data);
        if (data.error) {
          options.onError(data.error, options.customParameters);
        } else if (options.onComplete) {
          options.onComplete(data.response, options.customParameters);
        }
      });
Я ничего такого не сделал, просто в onError теперь будут передаваться customParameters.
В APIConnection есть метод api, который мы и дёргаем. Логично было бы туда передавать сразу customParameters.
Код AS3:
	public function api(method: String, params: Object, onComplete:Function = null, onError:Function = null, customParameters:Object = null):void 
	{
	  var options: Object = new Object();
	  options['params'] = params;
	  options['onComplete'] = onComplete;
	  options['onError'] = onError;
	  options['customParameters'] = customParameters;
	  dp.request(method, options);
	}
Поменяли.
Всё, теперь дело происходит так APIConnection.api -> DataProvider.request -> DataProvider._sendRequest -> onComplete/onError.
И в этом onComplete/onError я имею мой аргументик. Прелестно.
А ещё мне не нравится что onComplete/onError передаётся чистый коллбек, без наворотов вроде нашего любимого event flow (читай - addEventListener/dispatchEvent). Я переделал это дело тоже, только уже внутри VkontakteConnector. Примерно так:
Код AS3:
		private function onError(event:VkontakteEvent):void 
		{
			var e:SocialEvent = new SocialEvent(SocialEvent.ERROR);
			e.customArguments = event.customArguments;
			e.response = event.response;
			_dispatcher.errorHandler(e);
		}
Где _dispatcher у меня - это SocialConnector. А errorHandler просто тупо делает dispatchEvent
Код AS3:
		public function errorHandler(event:SocialEvent):void
		{
			super.dispatchEvent(event);
		}
В итоге я подписываюсь банально на
Код AS3:
_socialAPI.addEventListener(SocialEvent.ERROR, onSocialError);
Последний презерватив сделан ради того, чтобы подписывался я как написано выше, а не вот так:
Код AS3:
_socialAPI.instance.addEventListener(SocialEvent.ERROR, onSocialError);
Однако, какой типа коллбеков использовать - личное дело каждого.

А вот теперь давайте подумаем. Предположим что злой сисадмин провайдер пользователя годами мечтал играть в игры вконтакте, но ему нельзя! Потому что за ним следит великий начальник, который запрещает. И вот он творит всякую злость, черную магию, бьет в бубен... Ну и приключилось так, что произошла ошибка у запроса. Из за зависти черного системного администратора. Ошибка попадёт в onError. А в onSuccess никто не попадёт! А ерунда в том, что именно в onSuccess мы ждали мессию, и сказали пользователю - жди! Сейчас контакт тебе ответит. А он не ответил. Короче, понимаете к чему я клоню? Если происходит такая фигня - нужно запрос тут же отправить заново! Причем прозрачно для всей программы.


5) Редиспатч запроса при ошибке. Однако следует предусмотреть некую границу редиспатчей. Если вдруг запрос 15 раз не прошел, наверное, он не пройдёт и на 16. И стоит записать на сервер что нам отвечает контакт, что мы хотели спросить, значения разных там ключевых переменных... И показать юзеру ошибку. Сказать, что виноват Дуров.
Реализация: банально по идентификаторам храним и сам запрос. При удачном проходе - удаляем. При ошибке - находим его в хранилище отправленных - и пробуем ещё раз. Ну, и ещё одно хранилище для числа текущих неудачных запросов. Запрос, получается, должен иметь:

1) Имя (идентификатор).
2) "Внутренность запроса" - то есть сам запрос, что уходит вконтакт
3) Время, когда он был отправлен
4) Количество запросов, неудачно отправленных.

Неплохо было бы оформить это дело в класс с этими 4 полями. Типизация, всё такое.
Ну всё, теперь нам не страшно, если вдруг запрос "провалится". А значит мы можем слегка ослабить политику к числу запросов. Например, с политикой "враг не пройдёт" запросы будут отсылаться каждые 700 мс. А можно бы отсылать их с интервалом в 500 мс без потерь. Если черный сисадмин позволит. Приходим к мысли, что можно найти


6) Среднее время запроса. Если честно, это уже граничит с турбонадувом в чайнике. Сам никогда не делал, но идея весьма интересная, поэтому поделюсь. Суть в том, что вконтакту достаточно получать запрос каждые 334 мс. Если запрос идёт до контакта 350 мс, и обратно за 350 то в "плотном" режиме запрос отправляется каждые 700 мс. 3.5 секнды будет отправлено 7 запросов, а если отправлять их с интервалом 350 мс - то 10.
Реализация: время выполнения запроса запоминается и корректирует стартовую величину. Например, начальная величина 1000 мс. Запрос прошел за 200 мс (туда-обратно), значит до контакта он доходит за 100. Но раз на раз не приходится, поэтому 1000 и 100 как то взаимодействуют, получая "среднее время запроса".
Да хоть (1000 + 100) / 2 = 550. Следующий запрос в 100 мс сократит время до (550 + 100) / 2 = 325. Ну и так далее. Интервал между запросами - это средний интервал между запросами, но он не может быть меньше 334.
В итоге запросы выполняются с максимальной скоростью, какой только возможно. Конечно, при реализации следует применять этот интервал только в случае если все запросы заняты (можно параллельно отправить 2 запроса сразу, не выжидая паузу). В случае если происходит ошибка по причине "Слишком много запросов" - среднее время резко увеличивается, чтобы потом снова быть подкорректировано. А если такая ошибка повторяется слишком часто - система вообще переходит в состояние, описанное в пункте 3.
Но это просто мысли. Не думаю, что кому то действительно потребуется такой турбонадув.


7) Оформление в единый фреймворк. Всё сделали? Умницы! Теперь оглянитесь назад и поймите, что вы не хотите переживать снова весь этот кошмар. Сделайте фреймворк, задокументируйте и перекреститесь. А на следующий день встаньте, улыбнитесь солнышку и... продолжайте делать адаптер, например, под Мой Мир.


Приведу небольшой овервью сказанного:
1) Сделайте адаптер первым делом. Даже под одну соцсеть.
2) Кэшируйте всё что можно. Если нельзя - закэшируйте и подумайте ещё раз.
3) Делайте очередь запросов: 3 запроса в секунду это предел для контакта.
4) Подписывайте запросы, чтобы в любой момент времени можно было сказать, зачем этот запрос нужен.
5) Случилась ошибка - попробуй ещё раз!
6) Если личной жизнью не богат - турбонадуву будешь рад!
7) Оформи это в фреймворк и забудь как страшный сон.

Спасибо за внимание.
Всего комментариев 50

Комментарии

Старый 21.12.2010 06:14 mayakwd вне форума
mayakwd
 
Аватар для mayakwd
каша в тексте и в голове
Старый 21.12.2010 12:28 GBee вне форума
GBee
 
Аватар для GBee
Цитата:
Уверяю вас, в один прекрасный день начальник скажет - "а теперь в фейсбук!" и ваша седина сменится лысиной.
:о) Золотые слова.
Старый 21.12.2010 15:06 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
mayakwd, покажи где конкретно, я исправлю)
Старый 21.12.2010 15:42 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
покажи где конкретно, я исправлю
Я думаю, стоило начать с паттерна "стратегия" и удобства его применения в данном контексте.
Далее, можно сказать о буфере запросов и кастомных событиях для его правильной работы.
Далее можно было рассказать о кешировании данных в разных его (кеширования) проявлениях

Вот, кстати, самый простой пример кеша картинок:
Код AS3:
package net.cache {
 
	import flash.display.BitmapData;
 
	/**
	 * Кэш для картинок
	 * 
	 * @author gloomyBrain
	 */
	public final class BitmapCache {
 
		private static const _urls:Vector.<String> = new Vector.<String>();
		private static const _bitmaps:Vector.<BitmapData> = new Vector.<BitmapData>();
 
		/**
		 * Записывает дынне о картинке в кеш
		 * 
		 * @param	url		URL-адрес картинки
		 * @param	bitmap	Данные картинки для хранения
		 */
		public static function addPicture(url:String, bitmap:BitmapData):void {
 
			var index:int = _urls.indexOf(url);
			if (index != -1) throw new Error("Повторная запись в кеш невозможна!");
 
			_urls.push(url);
			_bitmaps.push(bitmap);
		}
 
		/**
		 * Получить картинку по URL-адресу
		 * 
		 * @param	url	URL-адрес для поиска картинки в кеше
		 * 
		 * @return	Данные найденной картинки или null
		 */
		public static function getPicture(url:String):BitmapData {
 
			var index:int = _urls.indexOf(url);
			if (index == -1) return null;
 
			return _bitmaps[index];
 
		}
 
		/**
		 * Удаляет данные о картинке из кеша и
		 * чистит занимаемую ими память
		 * 
		 * @param	url	URL-адрес картинки для удаления
		 */
		public static function removePicture(url:String):void {
 
			var index:int = _urls.indexOf(url);
			if (index == -1) return;
 
			_bitmaps[index].dispose();
 
			_urls.splice(index, 1);
			_bitmaps.splice(index, 1);
		}
 
		/**
		 * Очищает все содержимое кеша. При этом все 
		 * данные изображенийудаляются из памяти
		 */
		public static function clear():void {
 
			var i:int = 0;
			var len:int = _bitmaps.length;
 
			for (i = 0; i < len; i++) {
				_bitmaps[i].dispose();
			}
 
			_urls.length = 0;
			_bitmaps.length = 0;
 
		}
 
	}
 
}
ЗЫ
А вот пользоваться теми примерами, которые предоставляет ВКонтакт я бы никому не пожелал. И, тем более, сам не стал бы.
Старый 21.12.2010 17:00 dark256 вне форума
dark256
 
Аватар для dark256
Я как-то слабо разбираюсь в АПИ контакта и еще более в новостях и обновлениях.
VkontakteConnector, SocialConnector - о чем речь? Это методы враппера или что это где?

А в целом - после того как вирусность приложений зарезали, все эти мегавыборки, по сути нафик не нужны. Максимум что там теперь имеет смысл юзать - это имя-фамилию-ник (хотя вконтакте не ники - это дурдом полный ), валидность телефона и ссылку на аватару. И еще - проверить_баланс-снять_Денег.

Все это крайне просто запрашивается и даже можно не кэшировать.
Unknown Error - это вообще песня. Это надо заменить на "ОбщаяОшибкаДурова". К слову - все это так часто стало нынче падать, что в общем случае имеем сервер-500 и работу можно заканчивать.

При всем при этом, все обращения к АПИ и логику работы с социалкой все интеллигентные люди выносят в серверную часть. OpenAPI и привет. По-любому даже одна и та же игра, портируемая в разные социалки может иметь ОДНО ФЛЭШ ЯДРО, но, обязательно РАЗНЫЕ серверные части. Которые выборками и занимаются. Соотв. все не так плохо, это просто полный ДУРдом.
Старый 21.12.2010 17:14 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
ОДНО ФЛЭШ ЯДРО, но, обязательно РАЗНЫЕ серверные части
Интересно, как при таком раскладе пользователи из разных соц сетей могут играть вместе? =)
Старый 21.12.2010 18:19 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Тоже использовал заветные 334мс, пока однажды не получил тут совет не заморачиваться )
Оверфлоу происходит в львиной доле случаев так редко, что достоин лишь повторного запроса, если пришла соотв. ошибка. Это и реализуется проще и в работе дешевле.
Старый 21.12.2010 20:03 dark256 вне форума
dark256
 
Аватар для dark256
Код AS1/AS2:
Интересно, как при таком раскладе пользователи из разных соц сетей могут играть вместе? =)
1. В общем случае у разных соц.сетей до фига всего разного, в том числе способы оплаты и языки, и , самое главное, конечная стоимость шмота. Свести американцев и скажем, каких-нть неимущих эксимосов - у одних ОЧЕНЬ много денег, у других - нет вообще. Какая тут игра получится?

Поэтому первый раз слышу чтобы разные социалки где-то сводились вместе.
Ибо разные не только социалки, но, в общем случае, и социальные СЛОИ

2. Разная серверная часть на уровне гейта с авторизацией, выборки информации по игроку и работе с АПИ соцсети. А далее - в принципе ядро сервера опять-таки единое и ничто не мешает
Старый 21.12.2010 20:06 Rzer вне форума
Rzer
 
Аватар для Rzer
Зачем кешировать кешируемое? Засоряя при этом оперативную память. Я про картинки.
Старый 21.12.2010 20:19 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Вот, кстати, самый простой пример кеша картинок:
Я использую банальный Object, где ключ - это url, значение - ByteArray, который гружу по bytes.

Цитата:
Я думаю, стоило начать с паттерна "стратегия" и удобства его применения в данном контексте.
Далее, можно сказать о буфере запросов и кастомных событиях для его правильной работы.
Далее можно было рассказать о кешировании данных в разных его (кеширования) проявлениях
Думаешь, стоит? Статья ориентирована на людей, которые с вконтактом уже работали, для направления их в правильное русло.

Цитата:
Тоже использовал заветные 334мс, пока однажды не получил тут совет не заморачиваться )
Оверфлоу происходит в львиной доле случаев так редко, что достоин лишь повторного запроса, если пришла соотв. ошибка. Это и реализуется проще и в работе дешевле.
Иногда может возникнуть потребность долбить вконтакт кучами команд )
У меня такого не было и если честно вряд ли будет =)

Цитата:
Зачем кешировать кешируемое? Засоряя при этом оперативную память. Я про картинки.
Не факт, что картинки закешируются. Уж лучше я сам.
Старый 21.12.2010 20:57 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
Засоряя при этом оперативную память
Объем занимаемой оперативной памяти увеличится на несколько байт - для ссылки и для url картинки. Так что можно не заморачиваться. Кеш браузера отработает медленнее чем прямая передача данных в Bitmap. Плюс куча слушателей для загрузки по сети становятся ненужными, если мы берем что-то из кеша. Плюс нам больше вообще не нужен тормозной класс Loader.

Цитата:
Думаешь, стоит? Статья ориентирована на людей, которые с вконтактом уже работали
Я бы назвал это потоком сознания, а не статьей =) А вообще, если ты хотел направить людей по верному пути, тогда тем более стоило начать с теоритичеких основ.

Цитата:
Свести американцев и скажем, каких-нть неимущих эксимосов - у одних ОЧЕНЬ много денег, у других - нет вообще. Какая тут игра получится?
Очевидно, что независимо от серверной части, у эскимосов денег не прибавится.
Старый 21.12.2010 23:48 Gaen вне форума
Gaen
 
Аватар для Gaen
Цитата:
Неплохо было бы реализовать ещё геттеры вида isGetProfilesAviable - не у всех соцсетей равные возможности, но мы не о том.
Ну-ка, а можно всё-таки о том? Возможности у различных социалок действительно отличаются, поэтому грести их все под один интерфейс с кучей isSomethingAvailable имхо как-то неправильно.
Старый 22.12.2010 01:04 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Ну-ка, а можно всё-таки о том? Возможности у различных социалок действительно отличаются, поэтому грести их все под один интерфейс с кучей isSomethingAvailable имхо как-то неправильно.
Почему же? Возможности по большей части равны.
Если например мы не можем попросить социалку прислать нам текущие настройки приложения (isConfigAviable = false) то мы делаем их по умолчанию. Если можем - ставим их, какие пришли.

Там, на самом деле, всё проще, чем кажется на первый взгляд
Старый 22.12.2010 02:39 Azo вне форума
Azo
 
Аватар для Azo
а чем не устраивает вконтактовский DataProvider connector class? в любом случаи запрос (что в коннектором созданным вами, что вконтактовским) будет происходить методом URrlLoader...
единственное да - это то что можно переделат их класс. сделать меньше кода для вызова.+внедрить таймер в этот же класс-коннектор который будет вставлять запросы в очередь и удалять дубликаты запросов,которые были запущены с интервалом менее секунды например.

---

кстати таким образом вы кешируете адреса картинок а не сами картинки?!



Есть еще вариант:

вбить первым запросом ( обрабатываемый до того как флеш загрузится) execute метод который сразу принесёт все данные по getprof...getVideos..photos... и т.д по требованиям.. и занести в объект.

таким образом мы сможем не ссылаясь ниразу на вк использовать кантент взяв из нашей базы (объекта)
Старый 22.12.2010 04:26 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Цитата:
+внедрить таймер в этот же класс-коннектор, который будет вставлять запросы в очередь и удалять дубликаты запросов, которые были запущены с интервалом менее секунды например.
ну вот опять. я однажды остановился и попробовал смоделировать ситуацию, когда мне реально надо так париться о 3-х запросах в секунду... ну короче я так и не придумал нифига )

Цитата:
кстати таким образом вы кешируете адреса картинок а не сами картинки?!
да не. кэширует он картинки — адреса как ключики используются.
Старый 22.12.2010 04:32 andrew911 вне форума
andrew911
Цитата:
gloomyBrain: Объем занимаемой оперативной памяти увеличится на несколько байт - для ссылки и для url картинки. Так что можно не заморачиваться. Кеш браузера отработает медленнее чем прямая передача данных в Bitmap. Плюс куча слушателей для загрузки по сети становятся ненужными, если мы берем что-то из кеша. Плюс нам больше вообще не нужен тормозной класс Loader.
А содержимое картинки разве не в памяти будет храниться?
Старый 22.12.2010 04:39 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Цитата:
А содержимое картинки разве не в памяти будет храниться?
Если зацепим для своих нужд — будет. Отпустим — GC подметет. Просто следует балансировать между удобством кэша и фанатичным поеданием памяти.

P.S.
хотя, как я понял, gloomyBrain имел в виду дополнительные расходы на кэширование картинки, которая и без того сейчас в работе.
Старый 22.12.2010 04:47 andrew911 вне форума
andrew911
Если кэшируются все же ссылки на картинки, тогда непонятно, почему упоминался кэш браузера, да и Loader все равно будет использоваться по мере надобности.

Увидел ПС
С одной картинкой в работе смысла бы не имело заморачиваться с такой системой кэша.
Обновил(-а) andrew911 22.12.2010 в 04:50
Старый 22.12.2010 04:59 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Кэш браузера упоминался как данность — он и так есть. Но доступ к этому кэшу происходит при обычной загрузке. А это значит, что как ни крути, но мелькнет прелоадер, притормозит на долю секунды (но так чтобы заметили) картинка. Не говоря о том, что внутри флэшки все делается как первый раз. Ну короче — "неаккуратненько как-то" ©
Поэтому и используют более экономный режим, при котором нет никаких "проблесков", не создается заново объект, который уже создавали, не заводится снова запрос — просто берем уже готовую картинку в виде того же ByteArray.
Старый 22.12.2010 05:03 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Про ПС — я не имел в виду "одну картинку". Речь идет о том, что картинка уже есть (одна-две-двести). Завести в массиве ссылку на нее под ключом ["URL_картинки"] — вот и все расходы.
Старый 22.12.2010 05:10 andrew911 вне форума
andrew911
Да, логично - если картинка отображается, то память она итак уже занимает.
Старый 22.12.2010 14:20 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Не очень понимаю людей, которые говорят "картинка будет есть память!". Да, будет. Но примерно столько же, сколько эта сама картинка занимает места на жестком диске (если брать bytes, BitmapData, наверно, больше). Сколько юзер скачает по интернету таких картинок? Мегабайт? Два? Десять? Машину меньше чем с гигабайтом оперативы сейчас не встретишь. Да даже если 512 - 10 мегабайт такие копейки. Уверен, что 99.9% остальных приложений потеряют на утечках за 10 минут больше. А "летающее" приложение в плане загрузки картинок будет нравится юзеру.
Старый 22.12.2010 18:13 Котяра вне форума
Котяра
 
Аватар для Котяра
Другое дело чтоб под одну и ту же картинку выделять опять новое место. У меня есть свой кэшер и он быдаёт не Bitmap а BitmapData. Он же отслеживает ситуации дестроя, и если картинка не нужна больше никому - вызываем dispose.
Насчёт хранения в памяти и на жёстком диске - тут ты не прав. на диске хранится jpg/gif/png а в памяти bmp
Разницу сам считай)
Старый 22.12.2010 18:15 Котяра вне форума
Котяра
 
Аватар для Котяра
Всё очень относительно и от приложения к приложению отличается. В одних случаях можно забивать на память и хранить все наборы всех секвенций всех анимаций, например, в других (большие бэки фонов) - нужно убивать битмапдаты и при требовании грузить повторно но уже из кэша.
Старый 22.12.2010 19:45 andrew911 вне форума
andrew911
Цитата:
Всё очень относительно и от приложения к приложению отличается.
Золотые слова
Ато накодят потом тетрисов с требованиями 1Гб памяти и процессор 3ГГц - ну а что, памяти сейчас у всех завались, железо стоит дешевле толкового кодера.
Старый 22.12.2010 19:49 chabapok вне форума
chabapok
Проверку, чтобы запросы не шли чаще 334мс делать надо потому, что ночью и рано утром они могут идти и чаще, и бывает, что идут.

Насчет кэширования полей - мне кажется, что это лишнее. кол-во человеко-часов и машинного времени затраченного на написание этого кэширования велико, а смысла в нем нет - запрашиваем сразу все, что может пригодиться в приложении. Так быстрей, чем по 10 раз запрашивать это частями. А контент-то запрашиваемый все равно нужен! Поэтому, лучше и быстрей его запросить сразу весь, чем по частям.
Старый 22.12.2010 20:03 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Цитата:
Проверку, чтобы запросы не шли чаще 334мс делать надо потому, что ночью и рано утром они могут идти и чаще, и бывает, что идут.
или я ничего не понял, или именно по этой причине не надо ничего проверять — просто шли запросы по мере надобности и тут же повторяй их, если пришло "6".
Старый 22.12.2010 20:21 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
Насчёт хранения в памяти и на жёстком диске - тут ты не прав. на диске хранится jpg/gif/png а в памяти bmp
Разницу сам считай)
Гружу картинку Loader`ом. Размер картинки по версии ОС: 15,9 КБ (16*317 байт)
Код AS3:
		private function onComplete(event:Event):void {
			trace((event.currentTarget as LoaderInfo).bytes.length); //16379
		}
Посчитал. 62 байта.
Старый 24.12.2010 02:33 chabapok вне форума
chabapok
Цитата:
или я ничего не понял, или именно по этой причине не надо ничего проверять — просто шли запросы по мере надобности и тут же повторяй их, если пришло "6".
Вы ничего не поняли.

Если приложение подразумевает отправку 3х и менее запросов подряд, то можно их просто слать, особо не переживая.

Если бывает отправка более 3х запросов, то

- Вы предлагаете проверять есть ли ошибка, и, в случае если есть, повторять запрос. Такая схема - не стабильна! Особенно, если у вас запросы идут не в один поток (вы же не ждете завершения предыдущего перед отправкой следующего?). Может быть ситуация, когда изза слишком быстрой работы сети запросы идут настолько быстро, что получается, что все время идет более 3х в секунду, и поэтому возникают постоянные отлупы. И итоговые тормоза будут нереальные. Это потенциальный *****код, который "вроде работает".

- Я складываю запросы в FIFO буфер, а выбираю их оттуда с такой паузой, чтобы от предыдущего эвента Event.OPEN было не менее 334сек. Тест показал, что 100запросов подряд отрабатывают без единой ошибки.

Отсчитывать 334мс надо именно от Event.OPEN, а не от момента совершения отправки. Приход этого евента говорит о том, что запрос был "скушан" вконтактом. Когда-то пробовал 4 запроса с паузой между посылками в 1 сек. Именно между посылками. Запросы где-то в сети, видимо, складывались в буфер, а потом выдавались на сервер все в течении одной секунды и были отлупы, так что так делать нельзя.

Кстати, с момента, когда на вконтакте ввели execute, лучше вообще им пользоваться и укладываться в 3 запроса. Я вообще не помню когда в последний раз приходилось более 3х запросов делать. Это разве что делать приложение на getVariables-ах, но они настолько глючные, что смысла их использовать нет.


насчет обертки-интерфеса. (IUniversalFoVkontaktFaceBokkMoyMirItd). Идея была бы хорошей, но помоему социалки слишком разные для обьединения их апи в общий интерфейс. Ну разве что везде есть имя-фамилия и id, но ради такой мелочи заводить интерфейс нет смысла.
Старый 24.12.2010 03:52 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Цитата:
Вы ничего не поняли.
Факт.

Цитата:
...у вас запросы идут не в один поток (вы же не ждете завершения предыдущего перед отправкой следующего?)...
Я сейчас и не припомню, когда я последний раз "не ждал".
Пожалуй, будет уместен конкретный пример, если не сложно. Я вот затрудняюсь придумать.
Старый 24.12.2010 12:46 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
насчет обертки-интерфеса. (IUniversalFoVkontaktFaceBokkMoyMirItd). Идея была бы хорошей, но помоему социалки слишком разные для обьединения их апи в общий интерфейс. Ну разве что везде есть имя-фамилия и id, но ради такой мелочи заводить интерфейс нет смысла.
А по мне так нет. Приложению нужно знать что-то. Например, аватарку, имя и друзей. И приложению должно быть глубоко-далеко, откуда к ней поступят эти данные. А эти данные поступают от адаптера, это вполне нормальная практика. Или Вы хотите писать разные приложения вместо одного для разных соцсетей?
Старый 24.12.2010 20:52 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Хм... Только сейчас подумал о том, что можно на ходу грузить модуль для работы с социалкой... Хотя, занятие, наверное, не из самых простых, но с точки зрения веса приложения должно сказаться.
Старый 24.12.2010 21:44 udaaff вне форума
udaaff
Можно компилить с разными конфигами.
Старый 25.12.2010 00:13 Котяра вне форума
Котяра
 
Аватар для Котяра
Вообще да. можно настроить ант, чтоб компилил разные версии по разным конфигам, да ещё и складывал результаты в разные папки svn)
Но можно и просто выделить разные swf для адаптеров и грузить их по мере надобности.
Мы пошли вообще другим путём. У нас наш сервер знает какие запросы запрашивать. В клиент попадает только типизированные данные. Правда это не избавляет от кастомизации всё-равно. Клиенты - всё равно разные. Хотя бы из-за биллинга, размеров и внешних форм приглашения друзей и настроек приложения.
Старый 25.12.2010 02:05 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
У нас один. Просто в местах, где клиенты разные - вьюшка спрашивает "мы где?" и в зависимости от социалки меняет нужные места. Их не так много.
Старый 25.12.2010 15:04 chabapok вне форума
chabapok
Цитата:
Или Вы хотите писать разные приложения вместо одного для разных соцсетей?
не хочу, но к сожалению, в общем случае, приложение из одной СС вот просто так в другую не адаптируется. Например, на вконтакте ширина 800пикс возможна, а на моймире - нет. Значит, приходится делать графический рефакторинг, а вместе с ним, как правило, заказчик хочет и логическй рефакторинг и доделки дополнительного/переделки существующего функционала.

или например, на вконтакте есть запуск со стены для поста, для просмотра, а в др.сс - нет. Значит, если оно использовалось, его приходится чем-то заменять, это влечет за собой незначительные изменение интерфейса и логики. и это еще можно организовать на проверках типа if (adapter is IVkontakte){}, но заказчик воспринимает их как два разных приложения, и идеи на счет их развития - разные. И чем дальше, тем больше отличий. Просто неудобно в рамках одного приложения все делать. Я не вижу способа как тут можно обойтись одним приложением. Ну если поставить такую цель, то можно конечно, но это неудобно. Либо тогда надо сразу договариваться, что все одинаковое, но все равно на вконтакте меняют правила периодически на других сс наверное тоже.
Вобщем, приложения под разные сс хоть и похожи, но получаются разные.
Старый 25.12.2010 15:26 chabapok вне форума
chabapok
Цитата:
Пожалуй, будет уместен конкретный пример, если не сложно. Я вот затрудняюсь придумать.
Мы говорим о сферическом коне в вакууме.
На практике это все ерунда, особенно с момента введения execute.

пример чего нужен? Не правильного кода?
Ну мне когда-то попался код, в котором в переменных вконтакта хранился счетчик. И этому счетчику делалось +1 в некоторых случаях и записывалось через putVariable. И все работало. А потом заказчик захотел, чтобы эти случаи начали следовать с частотой 10-20 раз в сек. Но вызов в цикле putVariable не дал ожидаемого результата. Результирующий инкремент был меньшим, чем нужно. Как потом оказалось - в коде просто проверялось прошествие 334мс с момента отправки и отправлялся запрос. Этого оказалось не достаточно. Запросы отправлялись в одном порядке, а приходили на вконтакт и обрабатывались в другом. Когда я на форуме поделился открытием, мне сказали что я идиот, и что tcp протокол гарантирует правильный порядок отправки, для чего, собственно, он и разрабатывался. Как сейчас понмню - я даже пытался им объяснить, что порядок соблюдается только в рамках сокета. Вобщем в итоге, пришлось добавить складывание запросов в очередь (пока предыдущий запрос не дал Event.OPEN - след.не отсылаем). Тогда оно заработало, но долго и пришлось уйти на вдс, но это уже другая история.
Старый 25.12.2010 15:46 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Я для заказчиков не делал приложения, но для себя рассуждал так:

1. Приложение запускается в своем фрейме в контексте страницы любой СС.
2. Минимальный максимум ширины (0о) — 720px, под него и делаем.

Приложение должно быть полностью функционально в этих условиях.

Дополнительный же функционал — он на то и дополнительный, чтобы быть необязательным. И если он того стоит, то на него тратятся время(ваше) и деньги(заказчика). К этим дополнениям отнесем "резиновую" компоновку, запуск со стены Вконтакте, версия приложения под "Tab" на Facebook, и такое прочее.

Если таким манером выстраивать подход к проекту стороннего заказчика, он будет понимать, что все его изыски должны стоить тех денег, которые он за них заплатит. А если он морочит голову за те же бапки — это или вас нужда заставила с ним работать, или(и) вы как-то оплошали, договариваясь.

Если посмотреть на кросс-социальное (можно так сказать?) приложение под таким углом, то изложенный в публикации подход можно считать удобным и универсальным.
Старый 25.12.2010 15:54 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Цитата:
Мы говорим о сферическом коне в вакууме.
Вот о том и речь. На практике не нужны никакие 334мс... не, ну т.е. вообще! Я и хотел бы написать "в большинстве случаев", но рука не поднимается — не могу придумать нормального примера из "меньшинства". Не лажу какую-то, а жизнеспособный код, который без этих 334 никак нельзя считать стабильным.

P.S.
Я не стою на своем ради спора. Я действительно не могу придумать пример, который дал бы мне основания писать "не нужны эти 334мс в большинстве случаев" )
Старый 25.12.2010 20:14 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
Psycho Tiger, сжатие - оно для того и сжатие, что бы потом расжиматься. в своём коде ты померил размер бинарника, который был загружен. и забыл посчитать размер самой картинки. прибавь к этому width * height * 4 и получишь размер картинки в памяти. и это ты получишь только размер BitmapData ( за вычетом расходов на объёкт ). каждое использование этой битмапки добавляет по столько же. если у тебя на экране отображается 4 раза один битмапка размером 100х100, то весить она будет ( 100 * 100 * 4 ) * 5 + bytes.length + object_size.
Старый 25.12.2010 20:23 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Не забыл. Из "много-много" профилей, загруженных из контакта (под рейтинг, под разные игры, "большие" аватарки для личных данных и прочего) на экране я отображаю всегда не более 9, обычно 3-4.

По мне лучше держать в памяти все загруженные в сжатом виде + дополнительно 3-4, чем все в расжатом виде, за исключением 3-4.

Поясни про:
Цитата:
( 100 * 100 * 4 ) * 5 + bytes.length + object_size.
*4 - RGBA. Почему * 5?
Цитата:
у тебя на экране отображается 4 раза
описался?
Старый 26.12.2010 13:10 chabapok вне форума
chabapok
Цитата:
Я действительно не могу придумать пример, который дал бы мне основания писать "не нужны эти 334мс в большинстве случаев" )
Это вы теперь не можете его придумать. А раньше, когда не было firstApi и когда не было execute - элементарно. Пример - на входе в приложение знать как зовут всех друзей и кто из них поставил приложение, а кто нет (чтобы в приложении по разному отображать), и знать адрес для загрузки картинок и информацию по своим альбомам.
первый запрос - getFriends, второй - getAppFriends, третий -getProfiles, четвертый - photos.getAlbums, пятый - photos.get. И в этой задаче 1,2,3 запросы и 4,5 не взаимосвязаны и могут идти как бы в двух потоках. То есть 4 можно отправлять сразу даже вместе с первым, не дожидаясь 3го и ответа 3го.

Это вполне типичная задача, и заметтье - это еще адрес для загрузки фотографий на стену/в альбом (а как правило, если альбом с требуется, то и адрес для загрузки фотографий). А ведь еще если организовали хранение каких-то данных в переменных вконтакта, то put/getVariable на входе бывало.

И кстати, даже сейчас если приложение запускается со стены, то firstApi у него не срабатывает, и надо все данные запрашивать через API. Пример - приложение для постинга на стену фоток из альбома. Если оно запускается со стены, то firstApi не сработает, следовательно:

первый запрос - узнать как зовут друга, со стены которого запустили приложение
второй - узнать из профиля друга дату рождения и подсветить (выбрать по умолчанию) категорию "дни рождения, если дата стоит сегодняшним числом"
третий - узнать адрес сервера для загрузки фотографий.
четвертый - узнать список своих альбомов, узнать список фотографий в этих альбомах

правда сейчас эти запросы можно все обработать посредством одного excute, поэтому да, сейчас значительно реже 334мс актуально, но все равно бывает что нужно.

...а если организовано кэширование+подгрузка необходимого по мере необходимости, как советует топикстартер, то там и 20 запросов подряд может пойти, в теории.
Старый 26.12.2010 13:33 chabapok вне форума
chabapok
Кстати, я вспомнил.

Простой чат в составе приложения, у которого раз в 3 секунды делался getMessages, при определенных обстоятельствах выкидывал too many requests per second. Они (запросы) где-то у промежуточного провайдера складывались буфер, а только потом в какой-то момент сетку "пробивало" и запросы разом отдавались на вконтакт. Кто бы мог подумать?

помогло запускать таймер на след.вопрос только после получения ответа от предыдущего. (а была просто отсылка запросов по TimerEvent.TIMER)
Старый 26.12.2010 20:40 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
ничего не описался. отображается 4 + 1 эталон, с которого копировалось.
Старый 26.12.2010 21:01 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Цитата:
ничего не описался. отображается 4 + 1 эталон, с которого копировалось.
Эталон в моём случае это bytes, забыл? =)
Старый 26.12.2010 21:16 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
Psycho Tiger, так не бывает. эталон всегда BitmapData. поэтому всегда +1.
Старый 26.12.2010 21:37 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Погоди.
Я загрузил Loader`ом битмапу. У Loader`а сохранил bytes, отобразил картинку. Число BitmapData - 1. Картинку наотображался, сделал dispose, но bytes оставил. Число BitmapData - 0.
По надобности - я делаю loadBytes, по ненадобности - dispose. Почему у меня эталон вдруг остался в памяти?
Имо косяк в моём подходе в том, что отображая картинку дважды я всегда создаю новый BitmapData, хотя можно брать старый. Но эта проблема легко решается CacheManager, который скажет, отображается ли эта битмапа уже и если да - выдаёт старый BitmapData. Однако нецелесообразно, т.к. одна картинка дважды отображается в микрослучаях. Ну и в том, что если картинка всегда отображается (например, рожа игрока) то мы дополнительно храним его bytes. Но в обоих случаях это такие микрорасходы, что и заморачиваться не стоит.
Старый 27.12.2010 01:10 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
Psycho Tiger, когда Loader загрузился картинку он уже сделал BitmapData, что бы ты мог ей пользоваться. если ты сделал dispose ( в чём я лично сомневаюсь, так как это глупо ( даже я так не делаю ) ), то ты её удалил. но при loadBytes ты всё равно получил +1, так что бессмысленно.
но намекну тебе: заморачиваться действительно не стоит. и тем более с dispose.
я просто сказал, что ты неправильно считаешь.
Старый 28.12.2010 15:26 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Ну да, ты всё правильно написал. Только наши слова не расходятся. )
У меня при несуществовании картинки на экране не существует и её BitmapData, то-то и всего. Когда я считал я как раз имел ввиду "чистый" кеш - имеем только в памяти, но не на экране. Если закешированная картинка сидит на экране - то твоя формула.
Старый 28.12.2010 15:34 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
Psycho Tiger, ну пускай по твоему они не расходятся. уговорил. лично мне всё равно.
 

 


Часовой пояс GMT +4, время: 12:44.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.