LE Blog

Инженер с поэтической душой

24.03.2009 firtree_right Jabber бот

Возникла идея написать jabber-бота. Выбор протокола обусловлен тем, что по нему достаточно много документации. И стандарт открытый — это хорошо. Много информации на code.google.com, но я решил пойти более простым путём и нашёл библиотеку на руби xmpp4r. Благодаря тому, что разработка ведется на руби, время разработки простого бота значительно сокращается. Устанавливается как библиотека:

sudo gem i xmpp4r

Регистрация

Это прекрасно, что бот может сам себя зарегистрировать.

require "rubygems"
require "xmpp4r"

include Jabber

client = Client.new(JID.new("login@server"))
client.connect

begin
  client.register "secretpassword"
  puts "Success!"
rescue ServerError => e
  puts "Error: #{e.error.text}"
end

При регистрации можно передавать хэш с параметрами для визитной карточки. После регистрации для последующей авторизации вместо register вызываеься:

client.auth "secretpassword"

Список контактов

Список контактов называется roster. Чтобы с ним работать нужно его запросить:

require "xmpp4r/roster"
roster = Roster::Helper.new(client)

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

roster.add_query_callback do |iq|
  puts "current roster:"
  roster.find_by_group(nil).each do |item|
    puts "#{item.jid}"
  end
end

Простейшее разрешение видеть свой статус и добавление в контакты в ответ на то, что добавляют бота выглядит так:

roster.add_subscription_request_callback do |item, pres|
  puts "Added by #{pres.from}"
  roster.accept_subscription(pres.from) # Разрешить видеть свой статус
  new_pres = Presence.new.set_type(:subscribe).set_to(pres.from)
  client.send(new_pres) # Запросить разрешение видеть статус
end

Теперь наши контакты смогут видеть наш бот онлайн, когда мы сообщаем об этом:

client.send(Presence.new.set_type(:available))

Неплохо бы что-нибудь ещё добавить, типа аватара.

Визитная карточка

Визитная карточка называется vcard:

require "xmpp4r/vcard"
require "base64"

vcard = Vcard::IqVcard.new
vcard["FN"] = "Full Name"
vcard["NICKNAME"] = "bot-nickname"
vcard["PHOTO/TYPE"]= "image/jpeg"
avatar_file = File.new("avatar.jpg", "r")
avatar_b64 = Base64.b64encode(avatar_file.read())
avatar_file.rewind
avatar_sha1 = Digest::SHA1.hexdigest(avatar_file.read())
vcard["PHOTO/BINVAL"] = avatar_b64
avatar_file.close

begin
  Vcard::Helper.new(client).set(vcard)
  puts "Success!"
rescue Exception => e
  puts "VCARD operation failed: #{e.to_s}" 
end

В соответствии со спецификацией xmpp относительно аватаров следует транслировать с какой-то периодичностью sha своего аватара:

Thread.new do
  while true do
    unless avatar_sha1.nil?
      pres = Presence.new
      x = REXML::Element.new("x")
      x.add_namespace("vcard-temp:x:update")
      photo = REXML::Element.new("photo")
      avatar_hash = REXML::Text.new(avatar_sha1)
      photo.add(avatar_hash)
      x.add(photo)
      pres.add_element(x)
      client.send(pres)
    end
    sleep 60
  end
end

Дело за малым.

Ответ на сообщения

cl.add_message_callback do |m|
  if m.type != :error and m.body
    client.send(m.answer.set_body(bot_main_function(m.body)))
  end
end

Внутри bot_main_function находится собственно то, что будет делать ваш бот, как он будет отвечать на то, что написали ему.

Материалы для изучения

Ещё интересные примеры