module Rumpy::Bot
include this module into your bot’s class
Attributes
pid_file[R]
Public Instance Methods
log_file=(logfile)
click to toggle source
if @log_file isn’t set, initialize it
# File lib/rumpy/bot.rb, line 14 def log_file=(logfile) @log_file ||= logfile end
start()
click to toggle source
one and only public function, defined in this module simply initializes bot’s variables, connection, etc. and starts bot
# File lib/rumpy/bot.rb, line 21 def start logger_init init connect set_iq_callback set_subscription_callback set_message_callback start_backend_thread start_output_queue_thread prepare_users @logger.info 'Bot is going ONLINE' @output_queue.enq Jabber::Presence.new(nil, @status, @priority) add_signal_trap Thread.stop rescue => ex general_error ex exit end
Private Instance Methods
add_signal_trap()
click to toggle source
# File lib/rumpy/bot.rb, line 224 def add_signal_trap Signal.trap :TERM do |signo| # soft stop @logger.info 'Bot is unavailable' @output_queue.enq Jabber::Presence.new.set_type :unavailable @queues.each do |user, queue| queue.enq :halt end sleep 1 until @queues.empty? @output_queue.enq :halt sleep 1 until @output_queue.empty? @client.close @logger.info 'terminating' @logger.close exit end end
connect()
click to toggle source
# File lib/rumpy/bot.rb, line 103 def connect @logger.debug 'establishing xmpp connection' @client.connect @client.auth @password @roster = Jabber::Roster::Helper.new @client @roster.wait_for_roster @logger.info 'xmpp connection established' end
connection_timeout_error()
click to toggle source
# File lib/rumpy/bot.rb, line 307 def connection_timeout_error @logger.warn 'ActiveRecord::ConnectionTimeoutError' @logger.info 'sleep and retry again' sleep 3 end
general_error(exception)
click to toggle source
# File lib/rumpy/bot.rb, line 313 def general_error(exception) @logger.error exception.inspect @logger.error exception.backtrace end
init()
click to toggle source
# File lib/rumpy/bot.rb, line 62 def init @config_path ||= 'config' @main_model ||= :user @logger.debug 'initializing some variables' xmppconfig = YAML::load_file @config_path + '/xmpp.yml' @logger.info 'loaded xmpp.yml' @logger.debug "xmpp.yml: #{xmppconfig.inspect}" @lang = YAML::load_file @config_path + '/lang.yml' @logger.info 'loaded lang.yml' @logger.debug "lang.yml: #{@lang.inspect}" @jid = Jabber::JID.new xmppconfig['jid'] @priority = xmppconfig['priority'] @status = xmppconfig['status'] @password = xmppconfig['password'] @client = Jabber::Client.new @jid Jabber::Version::SimpleResponder.new(@client, @bot_name || self.class.to_s, @bot_version || '1.0.0', RUBY_PLATFORM) if @models_files dbconfig = YAML::load_file @config_path + '/database.yml' @logger.info 'loaded database.yml' @logger.debug "database.yml: #{dbconfig.inspect}" ActiveRecord::Base.establish_connection dbconfig @logger.info 'database connection established' @models_files.each do |file| self.class.require file @logger.info "added models file '#{file}'" end end @main_model = Object.const_get @main_model.to_s.capitalize @logger.info "main model set to #{@main_model}" @queues = Hash.new do |h, k| h[k] = Queue.new end @output_queue = Queue.new end
logger_init()
click to toggle source
# File lib/rumpy/bot.rb, line 50 def logger_init unless @logger @log_file ||= STDERR @log_level ||= Logger::INFO @logger = Logger.new @log_file, @log_shift_age, @log_shift_size @logger.level = @log_level @logger.datetime_format = "%Y-%m-%d %H:%M:%S" end @logger.info 'starting bot' end
prepare_users()
click to toggle source
# File lib/rumpy/bot.rb, line 245 def prepare_users @logger.debug 'clear wrong users' @roster.items.each do |jid, item| user = @main_model.find_by_jid jid.strip.to_s if user.nil? || item.subscription != :both @logger.info "deleting from roster user with jid #{jid}" item.remove end end @main_model.find_each do |user| items = @roster.find user.jid if items.empty? @logger.info "deleting from database user with jid #{user.jid}" user.destroy else start_user_thread user end end @main_model.connection_pool.release_connection end
set_iq_callback()
click to toggle source
# File lib/rumpy/bot.rb, line 114 def set_iq_callback @client.add_iq_callback do |iq| @logger.debug "got iq #{iq}" if iq.type == :get # hack for pidgin (STOP USING IT) response = iq.answer true if iq.elements['time'] == "<time xmlns='urn:xmpp:time'/>" @logger.debug 'this is time request, okay' response.set_type :result tm = Time.now response.elements['time'].add REXML::Element.new('tzo') response.elements['time/tzo'].text = tm.xmlschema[-6..-1] response.elements['time'].add REXML::Element.new('utc') response.elements['time/utc'].text = tm.utc.xmlschema else response.set_type :error end # if iq.elements['time'] @output_queue.enq response end end end
set_message_callback()
click to toggle source
# File lib/rumpy/bot.rb, line 172 def set_message_callback @client.add_message_callback do |msg| if msg.type != :error && msg.body && msg.from if @roster[msg.from] && @roster[msg.from].subscription == :both @logger.debug "got normal message #{msg}" @queues[msg.from.strip.to_s].enq msg else @logger.debug "user not in roster: #{msg.from}" @output_queue.enq msg.answer.set_body @lang['stranger'] end end end end
set_subscription_callback()
click to toggle source
# File lib/rumpy/bot.rb, line 135 def set_subscription_callback @roster.add_subscription_request_callback do |item, presence| jid = presence.from @roster.accept_subscription jid @output_queue.enq presence.answer.set_type :subscribe @output_queue.enq Jabber::Message.new(jid, @lang['hello']).set_type :chat @logger.info "#{jid} just subscribed" end @roster.add_subscription_callback do |item, presence| begin case presence.type when :unsubscribed, :unsubscribe @logger.info "#{item.jid} wanna unsubscribe" @queues[item.jid.strip.to_s].enq :unsubscribe item.remove when :subscribed user = @main_model.new user.jid = item.jid.strip.to_s user.save start_user_thread user @logger.info "added new user: #{user.jid}" @output_queue.enq Jabber::Message.new(item.jid, @lang['authorized']).set_type :chat end rescue ActiveRecord::StatementInvalid statement_invalid_error retry rescue ActiveRecord::ConnectionTimeoutError connection_timeout_error retry rescue => ex general_error ex end end end
start_backend_thread()
click to toggle source
# File lib/rumpy/bot.rb, line 188 def start_backend_thread Thread.new do begin loop do backend_func().each do |result| message = Jabber::Message.new(*result).set_type :chat @output_queue.enq message if message.body && message.to end end rescue ActiveRecord::StatementInvalid statement_invalid_error retry rescue ActiveRecord::ConnectionTimeoutError connection_timeout_error retry rescue => ex general_error ex end # begin end if self.respond_to? :backend_func end
start_output_queue_thread()
click to toggle source
# File lib/rumpy/bot.rb, line 209 def start_output_queue_thread Thread.new do @logger.info "Output queue initialized" until (msg = @output_queue.deq) == :halt do if msg.nil? @logger.debug "got nil message. wtf?" else @logger.debug "sending message #{msg}" @client.send msg end end @logger.info "Output queue destroyed" end end
start_user_thread(user)
click to toggle source
# File lib/rumpy/bot.rb, line 268 def start_user_thread(user) Thread.new(user) do |user| @logger.debug "thread for user #{user.jid} started" until (msg = @queues[user.jid].deq).kind_of? Symbol do begin pars_results = parser_func msg.body @logger.debug "parsed message: #{pars_results.inspect}" answer = do_func user, pars_results @output_queue.enq msg.answer.set_body answer unless answer.nil? or answer.empty? rescue ActiveRecord::StatementInvalid statement_invalid_error retry rescue ActiveRecord::ConnectionTimeoutError connection_timeout_error retry rescue => ex general_error ex end # begin @main_model.connection_pool.release_connection end # until (msg = @queues[user.jid].deq).kind_of? Symbol do if msg == :unsubscribe @logger.info "removing user #{user.jid}" user.destroy end @queues.delete user.jid end # Thread.new do end
statement_invalid_error()
click to toggle source
# File lib/rumpy/bot.rb, line 301 def statement_invalid_error @logger.warn 'Statement Invalid catched' @logger.info 'Reconnecting to database' @main_model.connection.reconnect! end