Ручной Wave Робот

8 Березня 2010

Моя стаття з січневого випуску Хакера про wave. Хоча зараз ажіотаж трішки з Хвилі зійшов, але гадаю цей сервій ще буде розвиватися.

Ручной Wave Робот

Написание робота на Python'е для Google Wave

"Ладно, я построю свой собственный модуль с блек-джеком и шлюхами. Вообще-то, к черту модуль и блек-джека"... Какие хорошие советы могут давать роботы. Посему в статье построим и себе маленького робота, ну хотя бы лишь для Google Wave.

Google Wave получил хороший пиар, и думаю в сим мире не сыскать того, кто не слышал о нем (не считая, соседа Толика, который в запое;)). Хотя этот пиар может даже немножко повредил Волне, поскольку привозносил сие творение как убийца почты, форумов, и чуть ли не всего интернета. Как для меня же, Волна это достаточно классно сделанная IRC с кульным API. С помощью которого мы можем создавать любые гаджеты и, что более интересно, любых роботов, которые могут расширять возможности Wave под любые нужды. И наличие этого API поднимает планку Волне очень высоко. Так что с нашей стороны было бы огромнейшей ошибкой не рассказать тебе о программировании Волны. А мы же почти идеальны и не допускаем ошибок ;)

Робот API

Робот для Wave представляет e-mail с аваторкой, некоторым описанием, а также закрепленными за ним событиями. Событий где-то около 15 штук, но для большинства случаев хватает двух: WAVELET_SELF_ADDED BLIP_SUBMITTED

Первое событие возникает когда робота добавляем на какую-то волну. А второе событие когда кто-либо добавляет сообщение, причем это сообщение возникает в момент нажатия на кнопку "Done". Гугл при программировании Волны вводит несколько понятий: - wave - полностью весь Wave; - wavelet - обозначает конкретную волну; - blip - одно сообщение.

Помнишь в позапрошлом номере я тебе рассказывал о Google App Engine(GAE), так вот на данный момент роботов можно строить лишь с использованием GAE.

К практике!

Теория в случаях с Гуглом сложнее чем практика, посему не будем на ней задерживаться и перейдем к созданию робота. Все проекты на GAE начинаются с пустой папки и файла app.yaml, в котором установим что все запросы от wave будет обрабатывать скрипт jbot.py: handlers: - url: /_wave/.* script: jbot.py - url: /assets static_dir: assets

Давай теперь определим ТТХ нашего робота... Пусть он должен уведомлять нас по джаберу о новых сообщениях в волну. И соответственно мы должны иметь возможность подписать свой джабер на обновления, и удалиться из рассылки. В тексте сообщения, что будет приходить, будет емайл автора и текст нового сообщения. Нам нужно перехватывать событие WAVELET_SELF_ADDED для вывода справки по командах, и будем перехватывать BLIP_SUBMITTED, чтобы рассылать уведомление.

Начнем прогить файл робота jbot.py и поместим сперва импорт нужных либ: from waveapi import events from waveapi import robot

Создадим обьект робота передав название, адрес аваторки, версию и адрес сайта робота. Заметь, что версию нужно менять обязательно если изменяется список событий, потому что новые события в этом случае не будут работать. myRobot = robot.Robot('w-mailrobot', image_url='http://w-mailrobot.appspot.com/images/avatar.png', version='1', profile_url='http://w-mailrobot.appspot.com/') Теперь добавим перехват нужных событий и сам запуск робота: myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded) myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipSubmitted) myRobot.Run()

В регистрации перехватчиков мы указывали OnRobotAdded, OnBlipSubmitted - это названия функций, которых будут вызываться при событии. Они должны принимать 2 параметра - properties, context.

В properties информация относительно конкретного события. А в context - информация о окружении, о волне, где событие возникло. Именно через работу с context мы можем добавить новое сообщение в волну, вызвав такую длинную цепочку функций: context.GetRootWavelet().CreateBlip().GetDocument().SetText(string) Также с нее можем достать идентификатор волны, который нам немножко позже понадобиться: waveid = context.GetRootWavelet().GetWaveId()

Теперь давай обработаем событие добавления робота на волну. И при получении данного события, мы добавим текстовое сообщение в волну с описанием команд, что бот принимает: def addBlip(context, string): context.GetRootWavelet().CreateBlip().GetDocument().SetText(string) def OnRobotAdded(properties, context): addBlip(context,"I'm alive!\n Command:\n wabber-bot add me: jabber@jabber.ja\n wabber-bot remove me: jabber@jabber.ja")

Как видим мы добавили для будущего удобства функцию по добавлению сообщений - addBlip. А потом уже отправили сообщение.

Джабер

Чтобы продолжить нам уже следует научиться отсылать из GAE сообщения на джабер. Для этого активируем данный функционал - добавив в файл настроек app.yaml несколько строчек: inbound_services: - xmpp_message Теперь можем юзать функции для отправки запроса авторизации и самих сообщений: from google.appengine.api.xmpp import send_message, send_invite #просьба авторизации send_invite("кому") #отослать сообщение status = send_message("кому", "текст сообщения")

При програминге Google Wave иногда не очень понятно почему что-то не работает. Поэтому нам почти обязательно нужно использовать модуль logging. В GAE после его импортирования можем добавлять сообщения с разной степенью важности: logging.info('info') logging.error('error')

Обработчик этих сообщений автоматически добавить информацию о них в базу данных. И мы зайдя в админку можем их просматривать.

Был Blip?

Для завершения робота остался лишь последний шаг - написать OnBlipSubmitted - обработчик события о новом сообщении. В этой функции может быть 3 разные ситуации: - была команда "добавить джабер в лист оповещения"; - была команда "удалить джабер с листа оповещения"; - небыло команды, тогда разослать это сообщения по подписчикам. Если все это выразить на Python'e то получиться такое: def OnBlipSubmitted(properties, context): blip = context.GetBlipById(properties['blipId']) text_blip = blip.GetDocument().GetText() if text_blip.startswith('wabber-bot add me:'): #добавить юзера return if text_blip.startswith('wabber-bot remove me:'): #удалить юзера return #разослать всем сообщение

База данных

Для сохранения привязки джабер-акка к волне нам нужна база с двумя полями, одним для идентификатора волны, и один для джабера: from google.appengine.ext import db class WaveModel(db.Model): wave = db.StringProperty() user = db.StringProperty()

Теперь все готово к непосредственной обработке команд и добавлению пользователей в БД: if text_blip.startswith('wabber-bot add me:'): creator = text_blip[18:].strip() count = WaveModel.all().filter('wave = ', waveid).filter('user =', creator).count() if count: return WaveModel( wave = waveid, user = creator ).put() send_invite(creator) addBlip(context, "%s was added"%creator) return

Как видим, мы не только добавляем юзера в базу данных, а еще и присылаем запрос авторизации, чтобы дальше все сообщения безпрепятственно доходили. Принцип удаление пользователя из рассылки такой же самый, даже немного проще. Там по сути лишь 3 строчки главные: rez = WaveModel.all().filter('wave = ', waveid).filter('user =', creator) for i in rez: i.delete() Если же никакой команды нет, то достаем с базы все кто подписался и отправляем им сообщение: all_u = WaveModel.all().filter('wave = ', waveid) for u in all_u: status = send_message(u.user, "New message from %s:\n%s"%(blip_creator, text_blip)) Вот так долго мы готовились к обработке команд, а кода получилось несколько строчек. Всего же робота в "собранном" виде смотри на диске.

Люди или Бендер?

Я после написания робота, залил его на GAE и уже можешь добавлять wabber-robot@appspot.com к себе в контакты и юзать. Хотя по идее нужно еще добавить подтверждения для джабера, чтобы только пользователь мог себя добавить в список. А то так получается, что любой джабер аккаунт можно заспамить. Но может это совсем и не бага, а фича ;)

Этой статье я не только завершаю цикл о Гугле, но и немного приостанавливаю цикла о Питоне. Мы ведь уже год разбираем многие вещи в нем и думаю ты стал реальным профи... Так что в следующем номере будем пробовать юзать что-то другое... к примеру Erlang.

Ну, Фрай, было приятно познакомиться, пойду, убью себя (с) БЕНДЕР

 
 
 
Роман Хоменко aka PresidentUA
mail/jabber: spirt40@gmail.com