В последнее время perl в около-IT'шной среде принятно ругать(это наверное тема для отдельного разговора), а хвалят в связи с этим чаще всего python, иногда ruby. C python'ом я когда-то игрался, и мне даже нравилось, но сейчас особых чувств к этому языку не испытываю. С ruby как-то особо не сталкивался, хотя судя по отзывам штука достаточно интересная. Во время небольшой передышки на работе нахватался кусков из книг, а вчера в очередной раз посетило желание поиграться с jabber'ом. Погуглив на предмет библиотек для работы с XMPP, для Ruby, нашел XMPP4R, которая оказалась чудовищно простой в обращении, даже с моим минимальным знанием самого ruby.
Вобщем первоначальная задача достаточно банальна - на моем домашнем сервере крутится некий сервис, который сам по себе не очень стабилен, и иногда требует перезапуска - фактически чего-то типа /etc/init.d/servicename restart. Обычно я логинюсь туда по ssh, делаю это черное дело, и до следующего раза(условие рестарта достаточно призрачное - поэтому заскриптовать делать это автоматически не получится). Хочется чтобы я мог сказать jabber боту, который будет запущен с того сервера - restart, а он уже сам запустит нужные команды для переазпуска. С помощью google и ruby у мну получился такой маленький бот, который способен посмотреть что ему ввели, и в зависимости от правильности ввода, или выполнить то что требуется, или послать нафиг :) В качестве примера здесь будет не рестарт сервиса, а выполнение команды dig, в случае если вы напишите что-то похожее на имя домена, или же предложение ввести имя домена, если то что вы ввели слабо походит на домен. Возможно кому-то будет полезно :)
Готовый файл можно стянуть отсюда: http://muaddeep.googlepages.com/jabber-cl.rb, комменты от знатоков приветствуются. На что здесь нужно обратить внимание:
#!/usr/bin/ruby
require 'xmpp4r/client'
include Jabber
def usage
puts "Usage: " $0 " jid password destination-jid"
exit
end
def reconnect(cl,password)
cl.connect
cl.auth(password)
cl.send(Presence.new.set_type(:available))
puts `date`
end
#Jabber::debug = true
jid = ARGV[0]
password = ARGV[1]
to = ARGV[2]
unless jid && password
usage
end
cl = Client::new(jid "/BOT-MODE")
cl.connect
cl.auth(password)
cl.on_exception { sleep 5; reconnect(cl,password) }
cl.send(Presence.new.set_type(:available))
if to
subject = "XMPP4R test"
body = "Give me a domain name and I will do some magic for you"
m_to = Message::new(to, body).set_type(:normal).set_id('1').set_subject(subject)
cl.send m_to
end
mainthread = Thread.current
cl.add_message_callback do |m|
if m.body =~ /^[a-zA-Z0-9.-] \.[a-zA-Z.]{2,5}$/
dig = "\n"
dig = `dig noall answer #{m.body}`
dig = "===========\n"
dig = `dig noall answer NS #{m.body}`
dig = "===========\n"
dig = `dig noall answer MX #{m.body}`
dig = "===========\n"
m_to = Message::new(m.from, dig ).set_type(:normal).set_id('1').set_subject(subject)
cl.send m_to
elsif m.body != nil
body = "Give me a domain name and I will do some magic for you"
m_to = Message::new(m.from, body).set_type(:normal).set_id('1').set_subject(subject)
cl.send m_to
puts "response sended to #{m.from}"
end
puts m.from,m.type, m.body if m.body != nil
end
### keep alive
Thread.new do
while true do
if cl.is_connected?
cl.send(Presence.new)
else
reconnect(cl,password)
end
sleep 30;
end
end
Thread.stop
cl.close
- если вы настраиваете
add_message_callback
так чтобы отвечать всем кто вам что-либо напишет, то нужно обратить внимание что ответы эти будут идти и на всякие presense notifications, и есть риск заспамить всех кто в данный момент в он-лайн. Поэтому нужно проверять что в message body точно что-то есть. - Полезной является практика напоминать серверу о своем присутствии(иначе соединение разрывается, а скрипт сегфолтится), а так же автоматически переконнекчивать бота в случае если соединение все-таки разорвалось(на домашнем jabber-сервере соединение разорвалось где-то через час, на "настоящих" все происходит гораздо быстрее).
- Статьи рекомендованные на http://home.gna.org/xmpp4r/ и примеры которые идут с пакетом, многое объясняют :)
2 комментария:
Я бы не писал «include Jabber», так как тут это лишь сокращает 1 строку:
cl = Client::new(jid "/BOT-MODE") был бы
cl = Jabber::Client::new(jid "/BOT-MODE")
Второй случай как-то более понятен, сразу видно что за клиент :).
Да, точно, можно без этого инклуда, правда строк там чуть больше - еще Jabber::Message, в примерах на которые я смотрел - было с инклудом, я так и списал :)
Отправить комментарий