Pull to refresh

Разговариваем с Rails-приложением через XMPP (Jabber)

Ruby on Rails *

Статья расскажет о том, как получать сообщения от вашего Rails-приложения по протоколу XMPP (Jabber) и наоборот, управлять приложением, отправляя ему команды через XMPP.



Немного теории


XMPP (Extensible Messaging and Presence Protocol), ранее известный как Jabber — основанный на XML, открытый, свободный для использования протокол для мгновенного обмена сообщениями в режиме, близком к режиму реального времени. Изначально спроектированный легко расширяемым, протокол, помимо передачи текстовых сообщений, поддерживает передачу голоса, видео и файлов по сети.

В отличие от коммерческих систем мгновенного обмена сообщениями, таких, как AIM, ICQ, WLM и Yahoo, XMPP является децентрализованной, расширяемой и открытой системой. Любой желающий может открыть свой сервер мгновенного обмена сообщениями, регистрировать на нем пользователей и взаимодействовать с другими серверами XMPP. На основе протокола XMPP уже открыто множество частных и корпоративных серверов XMPP. Среди них есть достаточно крупные проекты, такие как Facebook, Google Talk, Яндекс, ВКонтакте и LiveJournal.

Если у вас еще нет джаббер-аккаунта (буду называть XMPP джаббером, по-старинке), его можно быстро завести на Jabber.ru или воспользоваться Google Talk. С клиентом для джаббера проблем не будет, подойдет практически любой «асечный», например, Miranda или QIP.

Для чего это нужно?


Я использую отправку сообщений:
— Для поиска битых ссылок. Когда пользователь на моем сайте попадает на 404-страницу, мне приходит сообщение с адресом этой страницы и адресом страницы, с которой был этот переход.
— Для мгновенного получения информации о заказе товара, оплате и т.д.
— Для получения сообщений от пользователей, которые не требуют ответа. Например, при заполнении «формы пожеланий».

Я отдаю команды Rails-приложению:
— На перезагрузку приложения. Это гораздо быстрее, чем лезть на сервер по ssh и перезагружать рельсы длиннющей командой.
— На добавление/удаление строки в базе данных. Мне было лень писать полноценный интерфейс, для работы с БД, которая очень редко нуждается в добавлении/удалении нескольких записей.

Ну а вы можете использовать связку Rails+XMPP для этих и любых более смелых задач. Например, заливки файлов и другого контента на сервер, чаты с пользователями и т.д.

Что нам потребуется?


Потребуется нам гем XMPP4R. Устанавливаем:
gem install xmpp4r

Сразу замечу, что гем очень нестабильно ведет себя под windows, поэтому лучше работать с ним на линуксе.

Далее, нам нужен джаббер-аккаунт для нашего Rails-приложения, т.е. адрес, с которого оно будет отправлять вам сообщения и принимать от вас команды. Регистрируем аккаунт.

Отправка сообщений


Подключение и аутентификация робота (буду так называть часть нашего Rails-приложения, ответственную за общение).
require "xmpp4r"

robot = Jabber::Client::new(Jabber::JID::new("robot@xmpp.ru"))
robot.connect
robot.auth("password")

Думаю, тут все понятно, robot@xmpp.ru — адрес джаббер-аккаунта, который вы зарегистрировали для приложения, password — пароль к нему. Теперь отправляем сообщение.

message = Jabber::Message::new("you@xmpp.ru", "Хелло, ворлд!")
message.set_type(:chat)
    
robot.send message

Где you@xmpp.ru — ваш джаббер-адрес. Вот и все. Сообщение уже всплыло из вашего трея.

Обратная связь


Теперь самое интересное — мы будем отправлять роботу команды (через джаббер-клиент). Для этого сперва подключим робота и заставим его заявить о своем присутствии и готовности общаться. Т.е. робот «будет онлайн», зеленая ламочка в джаббер-клиенте будет гореть.
robot = Jabber::Client::new(Jabber::JID::new("robot@xmpp.ru"))
robot.connect
robot.auth("password")
robot.send(Jabber::Presence.new.set_show(nil))

Теперь, включим цикл ожидания входящих сообщений. При этом будем проверять, что сообщения приходят с правильного адреса, т.е. роботом не пытается командовать некий злоумышленник.
robot.add_message_callback do |message| #ожидание сообщения
  if message.from.to_s.scan("you@xmpp.ru").count > 0 #сообщение с правильного адреса
  case message.body #перебираем варианты команд для робота
  when "hello"
    message = Jabber::Message::new("you@xmpp.ru", "И тебе привет!")
    message.set_type(:chat)
    robot.send message
  when "restart"
    File.open(Rails.root.to_s + "/tmp/restart.txt", "a+")
  end
  else #сообщение с чужого адреса
    message = Jabber::Message::new("you@xmpp.ru", "Ко мне ломится незнакомец!")
    message.set_type(:chat)
    robot.send message
  end
end

Получив сообщение «hello», робот ответит нам приветом, а получив «restart» — перезагрузит Rails-приложение (если оно работает через Passenger).

Финальный класс


В предыдущем примере, робот получил от нас команду перезагрузить приложение и… умер. Его нужно снова оживлять, запуская соответствующий скрипт. Делать это каждый раз после перезагрузки приложения конечно же не хочется. Поэтому, предлагаю запускать робота вместе с приложением. Я написал демон, включающий класс, который упростит работу с XMPP, а также, позволит роботу жить, невзирая на перезагрузки.

Этот класс мы оформим в отдельный руби-файл, например «xmpp_daemon.rb», и положим в папку «config/initializers», что позволит ему запускаться вместе с рельсами.
#coding: utf-8

require "xmpp4r"

class Xmpp
  
  #параметры подключения
  @@my_xmpp_address =      "you@xmpp.ru"     #ваш джаббер-адрес
  @@robot_xmpp_address =   "robot@xmpp.ru"   #джаббер-адрес робота
  @@robot_xmpp_password =  "password"        #пароль от джаббер-аккаунта робота
  @@site_name =            "sitename.ru"     #имя сайта, для идентификации источника сообщений
  
  #подключение и аутентификация на xmpp-сервере
  def self.connect
    @@robot = Jabber::Client::new(Jabber::JID::new(@@robot_xmpp_address))
    @@robot.connect
    @@robot.auth(@@robot_xmpp_password)
  end
  
  #отправка сообщения
  def self.message(text)
    self.connect
    message = Jabber::Message::new(@@my_xmpp_address, "[#{@@site_name}]\n#{text}")
    message.set_type(:chat)
    @@robot.send message
  end
  
  #прием сообщений
  def self.listen
    self.connect
    @@robot.send(Jabber::Presence.new.set_show(nil))
    @@robot.add_message_callback do |message| #ожидание сообщения
      if message.from.to_s.scan(@@my_xmpp_address).count > 0 #сообщение с правильного адреса
        case message.body #перебираем варианты команд для робота
        when "hello"
          Xmpp.message "И тебе привет!"
        when "restart"
          Xmpp.message "Перезагрузка..."
          File.open(Rails.root.to_s + "/tmp/restart.txt", "a+")
        end
      else #сообщение с чужого адреса
        Xmpp.message "Ко мне ломится незнакомец!"
      end
    end
  end
end

Xmpp.listen

Теперь, из любого контроллера Rails-приложения мы легко можем отправить сообщение.
Xmpp.message "Хелло, ворлд!"

Спасибо за внимание, надеюсь, это кому-то пригодится.

МанагеруЗакгоЭнспе
Tags:
Hubs:
Total votes 47: ↑43 and ↓4 +39
Views 6.2K
Comments Comments 26