class Flapjack::Gateways::Jabber::Bot
Attributes
siblings[RW]
Public Class Methods
new(opts = {})
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 520 def initialize(opts = {}) @lock = opts[:lock] @stop_cond = opts[:stop_condition] @config = opts[:config] @boot_time = opts[:boot_time] @say_buffer = [] @announce_buffer = [] @hostname = Socket.gethostname @alias = @config['alias'] || 'flapjack' @identifiers = ((@config['identifiers'] || []) + [@alias]).uniq @state_buffer = [] @should_quit = false end
Public Instance Methods
_announce(muc_clients)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 809 def _announce(muc_clients) @announce_buffer.each do |announce| if (muc_client = muc_clients[announce[:room]]) && muc_client.active? muc_client.say(announce[:msg]) announce[:sent] = true end end @announce_buffer.delete_if {|announce| announce[:sent] } end
_deactivate(muc_clients)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 803 def _deactivate(muc_clients) # send method has been overridden in MUCClient class # without this MUC clients will still think they are active muc_clients.values.each {|muc_client| muc_client.__send__(:deactivate) } end
_join(client, muc_clients, opts = {})
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 751 def _join(client, muc_clients, opts = {}) client.connect client.auth(@config['password']) client.send(::Jabber::Presence.new) muc_clients.each_pair do |room, muc_client| attempts_allowed = 3 attempts_remaining = attempts_allowed joined = nil while !joined && (attempts_remaining > 0) @lock.synchronize do unless @should_quit || (attempts_remaining == attempts_allowed) # The only thing that should be interrupting this wait is # a pikelet.stop, which would set @should_quit to true; # thus we shouldn't see multiple connection attempts happening # too quickly. @stop_cond.wait(3) end end # may have changed during previous wait sq = nil @lock.synchronize do sq = @should_quit end unless sq attempts_remaining -= 1 begin muc_client.join(room + '/' + @alias, nil, :history => false) t = Time.now msg = opts[:rejoin] ? "flapjack jabber gateway rejoining at #{t}, hello again!" : "flapjack jabber gateway started at #{t}, hello! Try typing 'help'." muc_client.say(msg) if @config['chatbot_announce'] joined = true rescue Errno::ECONNREFUSED, ::Jabber::JabberError => muc_je report_error("Couldn't join MUC room #{room}, #{attempts_remaining} attempts remaining", muc_je) raise if attempts_remaining <= 0 joined = false end end end end end
_leave(client, muc_clients)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 795 def _leave(client, muc_clients) if @joined muc_clients.values.each {|muc_client| muc_client.exit if muc_client.active? } client.close end @joined = false end
_say(client)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 819 def _say(client) while speak = @say_buffer.pop msg = ::Jabber::Message::new(speak[:nick], speak[:msg]) msg.type = :chat client.send( msg ) end end
alias()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 537 def alias ret = nil @lock.synchronize do ret = @alias end ret end
announce(room, msg)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 701 def announce(room, msg) @lock.synchronize do @announce_buffer += [{:room => room, :msg => msg}] @state_buffer << 'announce' @stop_cond.signal end end
handle_state_change(client, muc_clients)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 717 def handle_state_change(client, muc_clients) connected = client.is_connected? Flapjack.logger.debug "connected? #{connected}" while state = @state_buffer.pop Flapjack.logger.debug "state change #{state}" case state when 'announce' _announce(muc_clients) if connected when 'say' _say(client) if connected when 'leave' connected ? _leave(client, muc_clients) : _deactivate(muc_clients) when 'rejoin' _join(client, muc_clients, :rejoin => true) unless connected else Flapjack.logger.warn "unknown state change #{state}" end end end
identifiers()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 545 def identifiers ret = nil @lock.synchronize do ret = @identifiers end ret end
report_error(error_msg, je)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 742 def report_error(error_msg, je) Flapjack.logger.error error_msg message = je.respond_to?(:message) ? je.message : '-' Flapjack.logger.error "#{je.class.name} #{message}" # if je.respond_to?(:backtrace) && trace = je.backtrace # Flapjack.logger.error trace.join("\n") # end end
say(nick, msg)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 709 def say(nick, msg) @lock.synchronize do @say_buffer += [{:nick => nick, :msg => msg}] @state_buffer << 'say' @stop_cond.signal end end
start()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 553 def start Flapjack.logger.debug("I will respond to the following identifiers: #{@identifiers.join(', ')}") @lock.synchronize do interpreter = self.siblings ? self.siblings.detect {|sib| sib.respond_to?(:interpret)} : nil Flapjack.logger.info("starting") Flapjack.logger.debug("new jabber pikelet with the following options: #{@config.inspect}") # ::Jabber::debug = true jabber_id = @config['jabberid'] || 'flapjack' jabber_id += '/' + @hostname unless jabber_id.include?('/') flapjack_jid = ::Jabber::JID.new(jabber_id) client = ::Jabber::Client.new(flapjack_jid) client.on_exception do |exc, stream, loc| leave_and_rejoin = nil @lock.synchronize do # called with a nil exception on disconnect for some reason if exc Flapjack.logger.error exc.class.name Flapjack.logger.error ":#{loc.to_s}" Flapjack.logger.error exc.message Flapjack.logger.error exc.backtrace.join("\n") end leave_and_rejoin = @joined && !@should_quit if leave_and_rejoin @state_buffer << 'leave' @stop_cond.signal end end if leave_and_rejoin sleep 3 @lock.synchronize do unless @should_quit @state_buffer << 'rejoin' @stop_cond.signal end end end end check_xml = Proc.new do |data| if data.nil? nil else Flapjack.logger.debug "xml_data: #{data}" text = '' begin enc_name = Encoding.default_external.name REXML::Document.new("<?xml version=\"1.0\" encoding=\"#{enc_name}\"?>" + data). each_element_with_text do |elem| text += elem.texts.join(" ") end text = data if text.empty? && !data.empty? rescue REXML::ParseException # invalid XML, so we'll just clear everything inside angled brackets text = data.gsub(/<[^>]+>/, '').strip end text end end client.add_message_callback do |m| unless (m.type != :chat) || m.body.nil? || m.body.strip.empty? Flapjack.logger.debug "received message #{m.inspect}" nick = m.from time = nil m.each_element('x') { |x| if x.kind_of?(::Jabber::Delay::XDelay) time = x.stamp end } unless interpreter.nil? interpreter.receive_message(nil, nick, time, check_xml.call(m.body)) end end end muc_clients = @config['rooms'].inject({}) do |memo, room| muc_client = ::Jabber::MUC::SimpleMUCClient.new(client) muc_client.on_message do |time, nick, text| Flapjack.logger.debug("message #{text} -- #{time} -- #{nick}") next if nick == jabber_id identifier = identifiers.detect {|id| /^(?:@#{id}|#{id}:)\s*(.*)/m === check_xml.call(text) } unless identifier.nil? the_command = Regexp.last_match(1) Flapjack.logger.debug("matched identifier: #{identifier}, command: #{the_command.inspect}") if interpreter interpreter.receive_message(room, nick, time, the_command) end end end memo[room] = muc_client memo end attempts_allowed = 3 attempts_remaining = attempts_allowed @joined = false loop do if @joined # block this thread until signalled to quit / leave / rejoin @stop_cond.wait_until { @should_quit || !@state_buffer.empty? } elsif attempts_remaining > 0 unless @should_quit || (attempts_remaining == attempts_allowed) # The only thing that should be interrupting this wait is # a pikelet.stop, which would set @should_quit to true; # thus we shouldn't see multiple connection attempts happening # too quickly. @stop_cond.wait(3) end unless @should_quit # may have changed during previous wait begin attempts_remaining -= 1 _join(client, muc_clients) @joined = true rescue Errno::ECONNREFUSED, ::Jabber::JabberError => je report_error("Couldn't join Jabber server #{@hostname}", je) end end else # TODO should we quit Flapjack entirely? Flapjack.logger.error "stopping jabber bot, couldn't connect in #{attempts_allowed} attempts" @should_quit = true end break if @should_quit handle_state_change(client, muc_clients) unless @state_buffer.empty? end # main loop has finished, stop() must have been called -- disconnect _leave(client, muc_clients) if client.is_connected? end end
stop_type()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 738 def stop_type :signal end