qik_logo Qik - это сервис стриминга (вещания) и загрузки видео с мобильных телефонов. Загруженное видео можно посмотреть на [сайте](http://qik.com/) или на его [специальной версии](http://m.qik.com/) с мобильного телефона. Доступна интеграция с другими сервисами, такими как Twitter, Facebook и другие. Клиенты для практически всех современных моделей телефонов: iPhone, Windows Mobile, Symbian, Android, Blackberry и другие. Qik Push Engine - это механизм, который позволяет получать мгновенные оповещения о новых/изменившихся Qik-видео. Например, можно посмотреть постоянно обновляющийся список live-видео, все видео из района Новопеределкино или все видео со словом "кошка". На основе Qik Push Engine API можно построить интересные приложения, интегрированные с Qik, или добавить функциональность в уже существующие. Можно написать собственную систему нотификации, desktop-widget или что-то еще. Сегодня мы открываем API для работы c Qik Push Engine. Это первая ласточка в большом списке API, открывающих доступ к платформе стриминга Qik. Если вам интересно посмотреть Qik Push Engine в действии, заходите на одну из [страниц примеров](http://engine.qik.com/examples/all.videos.html). ## Основы работы с API [Qik Push Engine API](http://qikapi.pbworks.com/) доступно в виде набора удаленных процедур по протоколу JSON-RPC (over HTTP). В ближайшее время будет открыт REST-подобный интерфейс. Точкой входа для JSON-RPC является http://engine.qik.com/api/jsonrpc. Пока проект находится в закрытом бета-тестировании для доступа к API необходимо указать ключ разработчика, добавив параметр apikey: http://engine.qik.com/api/jsonrpc?apikey=xxxxxxx. Ключ разработчика можно получить, отправив письмо с запросом на [api@qik.com](mailto:api@qik.com). Пример HTTP-сессии:

POST /api/jsonrpc

Host : engine.stage.qik.com

Content-Type:  application/json; charset=UTF-8

Content-Length: 46



{"method": "qik.session.create", "params": []}

Ответ:

Content-Type: text/json 



["a56c1603-1fbb-4140-8b35-8c36abbd8b27"]

## Пример подписки на поток событий Здесь и далее я буду использовать простую запись вызова команд, которая похожа на вызов обычных функций, опуская детали JSON-RPC взаимодействия. Итак, пусть мы хотим подписаться на список всех live-стримов, которые есть данный момент. Первым делом создадим сессию:

qik.session.create() -> "a56c1603-1fbb-4140-8b35-8c36abbd8b27"

Подписываемся в рамках сессии на view всех публичных live-стримов, при этом указываем максимальное количество элементов во view (limit). Элементы view будут упорядочены в порядке убывания даты начала стрима (самые новые первыми):

qik.stream.subscribe\_public_live("a56c1603-1fbb-4140-8b35-8c36abbd8b27", 10) -> 
 [ "174/('PublicLiveStreamView', 'Stream', [('stoptime', None)], 'alllive;limit=10')", [ ... ] ]
В ответ на запрос мы получаем массив из двух элементов: первым является ключ подписки (длинная строка, начинающаяся с "174/.."). Не ищите смысла в ключе подписки, его необходимо просто сохранить, он потребуется в дальнейшем. Вторым элементом является начальное состояние view, то есть текущий список live-стримов в нашем случае. Мы получим не больше 10 элементов (так как указали limit 10 при вызове метода `qik.stream.subscribe_public_live`). Состояние view выглядит примерно следующим образом:

[
   {"url": "http://qik.com/video/2158468", 
    "live": true, 
    "user_id": 340699, 
    "small_thumbnail_url": "http://media.qik.com/media.thumbnails.128/c8ad8fe065ad4ad7ac8491874c043eac.jpg", 
    "title": "Untitled", "duration": 0,
    "created_at": "2009-07-11 15:56:03", 
    "views": 0, 
    "id": 2158468}, 

   {"url": "http://qik.com/video/2158466", 
    "live": true, 
    "user_id": 340119, 
    "small_thumbnail_url": "http://media.qik.com/media.thumbnails.128/984c33e1ead441038f315e1fff109fc5.jpg", 
     "title": "Testando!", 
     "duration": 0, "created_at": "2009-07-11 15:55:34", 
     "views": 0, 
     "id": 2158466}
]

Смысл большинства полей очевиден, приведу лишь некоторые комментарии: * все даты приведены в UTC; * поле `duration` хранит длительность видео в секундах. Так как мы подписались на live-стримы, у всех видео `live == true`. Теперь нам необходимо получать новые события для тех view, на которые мы подписались. Для этого используются HTTP long polling-запросы. Клиент отправляет запрос серверу, а сервер отправляет ответ, когда появляются события или когда истечет таймаут, если событий не появилось. Для реализации long polling в цикле вызываем метод `qik.session.get_events`, указывая желаемый таймаут (не рекомендуется использовать таймаут более 90 секунд).

qik.session.get_events("a56c1603-1fbb-4140-8b35-8c36abbd8b27", 60) -> 
  [ {...} ,{...} ]
В ответ мы можем получить пустой массив событий, если истек таймаут, или некоторый набор событий следующего вида:

[
   {
     "action": "update", 
     "old": {"id": 104252, "title": "Untitled", "views": 0, ...}, 
     "obj": {"id": 104252, "title": "driving to key largo", "views": 5, ...}, 
     "key": "175/('PublicRecentStreamView', 'Stream', [], 'allrecent;limit=50')"
    },
] 

В каждом событии обязательно передается следующая инормация: * `key` - ключ подписки, это то же самое значение, которое мы получили при подписке на view, ключ позволяет отличать события для разных view в рамках одной сессии; * `action` - действие (изменение), произошедшее с view: * `ping` - ничего не произошло, просто view сообщает, что все хорошо :) * `update` - элемент view изменился (как в примере выше), передается старое и новое состояние объекта в полях `old` и `obj` * `insert` - во view добавился новый элемент, его состояние будет записано в поле `obj` * `delete` - элемент исчез из view (может быть, видео было удалено, или просто перестало удовлетворять критериям view, или ушло за границу "limit"), последнее состояние объекта будет записано в поле `obj`. В ответ на события мы можем обновить информацию на экране для пользователя, выполнить какие-либо еще действия. Но обязательно надо отправить новый запрос `qik.session.get_events`, чтобы получить новые события. В конце работы не забываем "убраться" за собой, убиваем сессию:

qik.session.destroy("a56c1603-1fbb-4140-8b35-8c36abbd8b27") 

Замечания: * В рамках одной сессии можно подписаться на произвольное количество view. * Если это необходимо, можно авторизовать сессию от имени пользователя с помощью `qik.session.authorize`. * Существует большое количество вспомогательных запросов, которым сессия вообще не требуется, например `qik.user.public_profile`. * Можно отписаться от view при помощи конмады`qik.session.unsubscribe`. ## Reference JS-клиент Для демонстрации возможностей Qik Push Engine и проверки его работы был реализован легкий JavaScript-клиент. Его можно увидеть в работе на примерах, полный список которых приведен ниже. Если вы запустите пример в Firefox с включенным Firebug, в консоли Firebug будет появляться подробная информация о выполняемых запросах к Qik Push Engine API, полученных ответах и т.п. Исходный код клиента доступен в необфусцированном виде, со всеми комментариями. Код предоставляет по принципам public domain, то есть можете делать с ним все, что захотите - использовать в своих приложениях, модифицировать, переписывать на другие языкаи программирования и т.п. Пробежимся быстро по компонентам JS-клиента. ### [prototype.js](http://engine.qik.com/examples/js/prototype.js) Совершенно стандартный [Prototype](http://www.prototypejs.org/), ничего интересного. ### [deferred.js](http://engine.qik.com/examples/js/deferred.js) `Deferred` - это одна из основных концепций Twisted Framework (http://twistedmatrix.com). Deferred не является обязательным для взаимодействия с Qik Push Engine API, но позволяет сильно упростить сложные взаимодействия в асинхронном коде. В качестве дополнительного материала о Deferred можно почитать про [основы работы с Deferred](http://www.smira.ru/2009/02/10/deferred-async-programming/), [более сложные случаи использования Deferred](http://www.smira.ru/2009/02/24/more-about-deferred/), [данную реализацию Deferred для Prototype](http://www.smira.ru/2009/05/29/deferred-in-javascript-for-prototype/), а также взглянуть на Deferred в других JS-фреймворках: [MochiKit](http://mochikit.com/doc/html/MochiKit/Async.html), [Dojo](http://www.dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/miscellaneous/communication-between-threads-do). `DeferredManager` - простая конструкция на основе Deferred, позволяет запускать не более N асинхронных действий в один момент времени. ### [core.js](http://engine.qik.com/examples/js/api.js) Ядро клиента, объявляется namespace `QikEngine`, отладочные функции, определение конфигурации, создания объекта для доступа к API и т.п. ### [api.js](http://engine.qik.com/examples/js/api.js) `QikEngine.API` - простая обертка JSON-RPC API Qik Push Engine, возвращающая `Deferred` в качестве результата любого обращения к API. Через `Deferred` же отправляются ошибки и результаты выполнения методов. `QikEngine.Session` - класс, оборачивающий понятие сессии, создание, уничтожение, авторизация в рамках сессии. ### [events.js](http://engine.qik.com/examples/js/events.js) `QikEngine.Events` - получение новых событий с помощью HTTP long polling, технология, похожая на BOSH/Comet. Распределение событий подписчикам (конкретным view). ### [view.js](http://engine.qik.com/examples/js/view.js) `QikEngine.View` - абстрактный класс, представляющий view на стороне клиента. Обслуживание обновлений, отображение в элементах HTML, обработка событий и т.п. Списки элементов хранятся прямо в DOM-контейнере в виде HTML-узлов. Потомки `QikEngine.View` для реализации конкретных view: `QikEngine.PublicUserStreamView`, `QikEngine.PublicRecentStreamsView` и т.д. ### [updater.js](http://engine.qik.com/examples/js/updater.js) Очень простой интерфейс между данными, полученными из Qik Push Engine (например, информацией о стримах) и HTML-элементами. Адаптация данных, например, перевод дат из UTC в локальный формат, форматирование значений и т.п. ### [usercache.js](http://engine.qik.com/examples/js/usercache.js) `QikEngine.UserCache` - механизм загрузки информации о пользователях (по их ID). Использует `DeferredManager` для ограничения количества параллельных запросов. ## Что делать дальше? * смотрите [описание API](http://qikapi.pbworks.com/); * пишите письмо на api@qik.com, расскажите о своем проекте и получайте ключ для доступа к API. ## Полный список примеров * [все последние видео на Qik/live-видео](http://engine.qik.com/examples/all.videos.html) * [открытые стримы пользователя](http://engine.qik.com/examples/profile.html) * [профайл пользователя с точки зрения другого авторизованного пользователя](http://engine.qik.com/examples/user.videos.html) * [домашняя страница пользователя: собственные стримы, followerы, стримы от following](http://engine.qik.com/examples/user.home.html) Во всех примерах списки видео обновляются автоматически при внесении изменений на сайте или с мобильного телефона, например, если открою доступ Васе к моему приватному видео, он тут же увидит это видео в списке моих стримов и т.п.