diff options
-rw-r--r-- | TODO-PJC | 2 | ||||
-rwxr-xr-x | bin/mauvesend | 2 | ||||
-rwxr-xr-x | bin/mauveserver | 7 | ||||
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/mauvealert-server.docs | 6 | ||||
-rw-r--r-- | debian/mauvealert-server.examples | 1 | ||||
-rw-r--r-- | example.conf | 208 | ||||
-rw-r--r-- | lib/mauve/configuration.rb | 56 | ||||
-rw-r--r-- | lib/mauve/heartbeat.rb | 64 | ||||
-rw-r--r-- | lib/mauve/http_server.rb | 7 | ||||
-rw-r--r-- | lib/mauve/mauve_thread.rb | 70 | ||||
-rw-r--r-- | lib/mauve/notifier.rb | 6 | ||||
-rw-r--r-- | lib/mauve/notifiers/templates/email.html.erb | 4 | ||||
-rw-r--r-- | lib/mauve/notifiers/templates/email.txt.erb | 2 | ||||
-rw-r--r-- | lib/mauve/notifiers/templates/xmpp.html.erb | 21 | ||||
-rw-r--r-- | lib/mauve/notifiers/templates/xmpp.txt.erb | 8 | ||||
-rw-r--r-- | lib/mauve/notifiers/xmpp.rb | 75 | ||||
-rw-r--r-- | lib/mauve/server.rb | 25 | ||||
-rw-r--r-- | lib/mauve/timer.rb | 15 | ||||
-rw-r--r-- | lib/mauve/version.rb | 2 | ||||
-rw-r--r-- | lib/mauve/web_interface.rb | 12 |
21 files changed, 469 insertions, 131 deletions
@@ -1,3 +1,3 @@ * Javascript ack_time update if ajax synchronicity a bit shite * Template SMS bit better with the link URL to the actual alert. - * Add "too noisy" reminder to notifcations. + * Add an internal heartbeat to send to another mauve instance. diff --git a/bin/mauvesend b/bin/mauvesend index 7b1375f..42229eb 100755 --- a/bin/mauvesend +++ b/bin/mauvesend @@ -163,7 +163,7 @@ require 'getoptlong' begin require "mauve/#{r}" rescue LoadError => ex - puts ex.to_s + STDERR.puts "*** "+ex.to_s end end diff --git a/bin/mauveserver b/bin/mauveserver index d07aabb..4cb37ed 100755 --- a/bin/mauveserver +++ b/bin/mauveserver @@ -16,6 +16,12 @@ # specified, then mauvealert.conf in the current # directory is used, and failing that # /etc/mauvealert/mauvealert.conf is used. +# +# CONFIGURATION FILE +# +# The configuration file consists of various stanzas, and sub-stanzas which +# give give options for each part of the server. The example configuration +# file gives a definitive explanation of all the options. # # SEE ALSO # mauveclient(1), mauveconsole(1) @@ -88,6 +94,7 @@ require 'mauve/configuration' begin Mauve::Configuration.current = Mauve::ConfigurationBuilder.load(configuration_file) rescue StandardError => ex + STDERR.puts ex.backtrace.join("\n") error ex.message end diff --git a/debian/changelog b/debian/changelog index 2cacc71..be8f647 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +mauvealert (3.1.6) stable; urgency=low + + * Added new heartbeat to remote mauve + * Added alert URL to messages. + + -- Patrick J Cherry <patrick@bytemark.co.uk> Wed, 20 Jul 2011 16:15:07 +0100 + mauvealert (3.1.5) stable; urgency=low * mauvesend can now specify an absolute time diff --git a/debian/mauvealert-server.docs b/debian/mauvealert-server.docs new file mode 100644 index 0000000..20c256d --- /dev/null +++ b/debian/mauvealert-server.docs @@ -0,0 +1,6 @@ +bytemark_example_alerts.sh +bytemark_policy.txt +CHANGELOG +README +TODO +TODO-PJC diff --git a/debian/mauvealert-server.examples b/debian/mauvealert-server.examples new file mode 100644 index 0000000..ae5a993 --- /dev/null +++ b/debian/mauvealert-server.examples @@ -0,0 +1 @@ +example.conf diff --git a/example.conf b/example.conf new file mode 100644 index 0000000..c7e86e4 --- /dev/null +++ b/example.conf @@ -0,0 +1,208 @@ +# +# This is the main configuration clause for the server instance. +# +server { + # + # This is where our database lives. SQLite is the default. + # + database "sqlite3://./alerts.db" + + # + # This is our hostname. It gets used when URLs are generated, and in the heartbeat alert. + # + hostname "mauve.example.com" + + # + # This is the UDP listener. + # + listener { + # + # This is the IP and port for that the UDP packets come in on. The IP can + # be IPv4 or 6. If "::" is specified, then packets will be received over + # both IPv4 and 6. The default port is 32741. + # + ip "::" + port 32741 + + # + # This is how long the UDP server will sleep between looking for packets. + # + sleep_interval 1 + } + + + # + # This is the processing thread, which reveives packets, and updates the + # database as needed. + # + processor { + # + # This is the length of time the processor will sleep between checking for + # new packets from the UDP listener. + # + sleep_interval 1 + + # + # In order to make sure the same transmission isn't received more then + # once, a cache of transmission IDs is kept. This expire time below + # determines the interval over which this cache is expired. + # + transmission_cache_expire_time 300 + } + + # + # The web interface + # + web_interface { + # + # The listening IP and port. Can be IPv4 or IPv6. Bear in mind that for + # ports < 1024, mauveserver will need to be run as root, or have special + # dispensation. + # + ip "::" + port 1288 + + # + # This is where the template files live. + # + document_root "/usr/share/mauvealert/" + + # + # This is used in the cookie, to prevent session-stealing. + # + session_secret "PLEASE CHANGE ME" + } + + # + # The timer checks for alerts set to be raised/cleared in the future, or + # alert reminders, and triggers notifications thereof. + # + timer { + # + # This determines how often the timer thread checks for new reminders/notifications + # + sleep_interval 1 + } + + + # + # This is where the mauve server sends its own heartbeat. Useful for + # watching the watcher. + # + heartbeat { + # + # If no destination is specified, then the contents of + # /etc/mauvealert/mauvesend.destination are used. + # + destination "localhost" + # + # This is how long to wait before the alert is raised + # + raise_at 600 + # + # These two fields have sensible defaults set, but more informative + # messages can be set here. + # + summary "Mauve alert server is down" + detail "The Mauve alert server has failed to send a heartbeat" + } + +} + +# +# The logger uses log4r +# +logger { + + # + # This is the default formatting string. It is a PatternFormatter, which is + # described at + # http://log4r.rubyforge.org/rdoc/Log4r/rdoc/patternformatter.html + # + default_format "%d [ %6.6l ] [ %12.12c ] %m" + + # + # This is the default logging level. It can be one of + # + # Log4r::DEBUG + # Log4r::INFO + # Log4r::NOTICE + # Log4r::WARN + # Log4r::ERROR + # Log4r::FATAL + # + default_level Log4r::INFO + + # + # An outputter can be any one of those listed at + # http://log4r.rubyforge.org/rdoc/Log4r/rdoc/outputter.html. The name must + # correspond to the class name. The options in each outputter correspond to + # the "hash" arguments for that particular outputter class. + # + # Additionally each outputter can have a level, and format assoicated. + # + outputter("stdout") { + level Log4r::WARN + } + + outputter("file") { + filename "/tmp/mauveserver.log" + trunc true + level Log4r::DEBUG + } + + outputter("email") { + server "smtp.example.com" + subject "Mauve logger output" + from "#{ENV['USER']}@#{Socket.gethostname}" + to "awooga@example.com" + level Log4r::WARN + } + +} + +# +# XMPP instant messaging. This are the credentials to log into the XMPP +# account that mauve will use. +# +notification_method ("xmpp") { + jid "mauve@chat.example.com/mauve" + password "mauvespassword" +} + +# +# Email messaging. +# +notification_method ("email") { + server "localhost" + from "mauve@desk1.tur.bytemark.co.uk" + subject_prefix "mauve-test" +} + +person("office_chat") { + xmpp "muc:mauve-test@conference.chat.bytemark.co.uk/MauveAlert" + all { xmpp } +# suppress_notifications_after(310 => 1.minute) +} + +person ("pcherry") { + password '82da4c33e3a5ae9e51def466745e2c8965fa1476' + all { true } +} + +people_list ("arse") { + list [ "office_chat" ] +} + +# +# Default notification - tell root about all alerts every hour +# +alert_group("default") { + level URGENT + + notify("arse") { + every 2.minutes + } +} + + diff --git a/lib/mauve/configuration.rb b/lib/mauve/configuration.rb index 0d3e520..2794c03 100644 --- a/lib/mauve/configuration.rb +++ b/lib/mauve/configuration.rb @@ -7,6 +7,7 @@ require 'mauve/notification' require 'mauve/alert_group' require 'mauve/people_list' require 'mauve/source_list' +require 'mauve/heartbeat' # Seconds, minutes, hours, days, and weeks... More than that, we # really should not need it. @@ -64,8 +65,8 @@ module Mauve attr_reader :alert_groups attr_reader :people_lists attr_reader :source_lists - attr_reader :logger - + attr_reader :logger + def initialize @notification_methods = {} @people = {} @@ -115,6 +116,7 @@ module Mauve is_builder "outputter", LoggerOutputterBuilder + def builder_setup logger = Log4r::Logger.new("Mauve") @default_format = nil @@ -166,14 +168,11 @@ module Mauve class ProcessorBuilder < ObjectBuilder is_attribute "sleep_interval" + is_attribute "transmission_cache_expire_time" def builder_setup @result = Processor.instance end - - def method_missing(name, value) - @args[name] = value - end end class UDPServerBuilder < ObjectBuilder @@ -184,10 +183,6 @@ module Mauve def builder_setup @result = UDPServer.instance end - - def method_missing(name, value) - @args[name] = value - end end class TimerBuilder < ObjectBuilder @@ -196,12 +191,15 @@ module Mauve def builder_setup @result = Timer.instance end + end - def method_missing(name, value) - @args[name] = value + class HeartbeatBuilder < ObjectBuilder + is_attribute "destination" + is_attribute "interval" + + def builder_setup + @result = Heartbeat.instance end - - end class HTTPServerBuilder < ObjectBuilder @@ -210,15 +208,11 @@ module Mauve is_attribute "ip" is_attribute "document_root" is_attribute "session_secret" + is_attribute "base_url" def builder_setup @result = HTTPServer.instance end - - def method_missing(name, value) - @args[name] = value - end - end class NotifierBuilder < ObjectBuilder @@ -227,11 +221,6 @@ module Mauve def builder_setup @result = Notifier.instance end - - def method_missing(name, value) - @args[name] = value - end - end class ServerBuilder < ObjectBuilder @@ -241,22 +230,22 @@ module Mauve is_builder "processor", ProcessorBuilder is_builder "timer", TimerBuilder is_builder "notifier", NotifierBuilder - + is_builder "heartbeat", HeartbeatBuilder + + is_attribute "hostname" + is_attribute "database" + is_attribute "initial_sleep" + def builder_setup + @result = Mauve::Server.instance @args = {} end def result - @result = Mauve::Server.instance @result.configure(@args) - @result.web_interface = @web_interface @result end - def method_missing(name, value) - @args[name] = value - end - def created_web_interface(web_interface) @web_interface = web_interface end @@ -272,6 +261,10 @@ module Mauve def created_notifier(notifier) @notifier = notifier end + + def created_heartbeat(heartbeat) + @heartbeat = heartbeat + end end class NotificationMethodBuilder < ObjectBuilder @@ -282,7 +275,6 @@ module Mauve provider("Default") end - def provider(name) notifiers_base = Mauve::Notifiers notifiers_type = notifiers_base.const_get(@notification_type) diff --git a/lib/mauve/heartbeat.rb b/lib/mauve/heartbeat.rb new file mode 100644 index 0000000..0f51f80 --- /dev/null +++ b/lib/mauve/heartbeat.rb @@ -0,0 +1,64 @@ +require 'mauve/sender' +require 'mauve/proto' +require 'mauve/mauve_thread' +require 'log4r' + +# +# This class is responsible for sending a heartbeat to another mauve instance elsewhere. +# +module Mauve + + class Heartbeat < MauveThread + + include Singleton + + attr_accessor :destination, :summary, :detail + attr_reader :sleep_interval, :raise_at + + def initialize + super + + @destination = nil + @summary = "Mauve alert server down." + @detail = "The Mauve server at #{Server.instance.hostname} has failed to send a heartbeat." + self.raise_at = 600 + end + + def raise_at=(i) + @raise_at = i + @sleep_interval = ((i.to_f)/2.5).round.to_i + end + + def logger + @logger ||= Log4r::Logger.new(self.class.to_s) + end + + def main_loop + # + # Don't send if no destination set. + # + return if @destination.nil? + + update = Mauve::Proto::AlertUpdate.new + update.replace = false + update.alert = [] + update.source = Server.instance.hostname + update.transmission_id = rand(2**63) + + message = Mauve::Proto::Alert.new + message.id = "mauve-heartbeat" + message.summary = self.summary + message.detail = self.detail + message.raise_time = (MauveTime.now.to_f+self.raise_at).to_i + message.clear_time = MauveTime.now.to_i + + update.alert << message + + Mauve::Sender.new(self.destination).send(update) + end + + end + +end + + diff --git a/lib/mauve/http_server.rb b/lib/mauve/http_server.rb index 71261c8..7bd4467 100644 --- a/lib/mauve/http_server.rb +++ b/lib/mauve/http_server.rb @@ -87,7 +87,7 @@ module Mauve include Singleton - attr_accessor :port, :ip, :document_root + attr_accessor :port, :ip, :document_root, :base_url attr_accessor :session_secret def initialize @@ -96,6 +96,7 @@ module Mauve @ip = "127.0.0.1" @document_root = "/usr/share/mauvealert" @session_secret = "%x" % rand(2**100) + @server_name = nil end def main_loop @@ -105,6 +106,10 @@ module Mauve @server = ::Thin::Server.new(@ip, @port, Rack::Session::Cookie.new(WebInterface.new, {:key => "mauvealert", :secret => @session_secret, :expire_after => 691200}), :signals => false) @server.start end + + def base_url + @base_url ||= "http://"+Server.instance.hostname + end def stop @server.stop if @server diff --git a/lib/mauve/mauve_thread.rb b/lib/mauve/mauve_thread.rb index f6c0cbc..6409f98 100644 --- a/lib/mauve/mauve_thread.rb +++ b/lib/mauve/mauve_thread.rb @@ -5,9 +5,11 @@ module Mauve class MauveThread + attr_reader :state + def initialize @thread = nil - @stop = true + @state = :stopped end def logger @@ -18,62 +20,77 @@ module Mauve # # Good to go. # - @frozen = false - @stop = false - - logger.debug("Started") + self.state = :starting @sleep_interval ||= interval - while !@stop do + sleep_loops = (@sleep_interval.to_f / 0.1).round.to_i + sleep_loops = 1 if sleep_loops.nil? or sleep_loops < 1 + + while self.state != :stopping do + + self.state = :started if self.state == :starting + # # Schtop! # - if @frozen - logger.debug("Frozen") + if self.state == :freezing + self.state = :frozen Thread.stop - logger.debug("Thawed") + self.state = :started end yield - next if self.should_stop? + # + # Ah-ha! Sleep with a break clause. + # + sleep_loops.times do + + break if self.should_stop? - Kernel.sleep(@sleep_interval) + # + # This is a rate-limiting step + # + Kernel.sleep 0.1 + end end - logger.debug("Stopped") + self.state = :stopped end def should_stop? - @frozen or @stop + [:freezing, :stopping].include?(self.state) + end + + def state=(s) + raise "Bad state for mauve_thread #{s.inspect}" unless [:stopped, :starting, :started, :freezing, :frozen, :stopping, :killing, :killed].include?(s) + unless @state == s + @state = s + logger.debug(s.to_s.capitalize) + end end def freeze - logger.debug("Freezing") unless @frozen + self.state = :freezing - @frozen = true - 20.times { Kernel.sleep 0.1 ; break if @thread.stop? } logger.debug("Thread has not frozen!") unless @thread.stop? end def frozen? - self.stop? + self.stop? and self.state == :frozen end def run if self.alive? - if self.stop? - logger.debug("Thawing") if @frozen - @frozen = false + if self.stop? @thread.wakeup end else @logger = nil - logger.debug("Starting") if @stop - @stop = false + self.state = :starting @thread = Thread.new{ self.run_thread { self.main_loop } } end end @@ -107,9 +124,7 @@ module Mauve end def stop - logger.debug("Stopping") unless @stop - - @stop = true + self.state = :stopping 10.times do break unless self.alive? @@ -127,10 +142,9 @@ module Mauve alias exit stop def kill - logger.debug("Killing") - @frozen = @stop = true + self.state = :killing @thread.kill - logger.debug("Killed") + self.state = :killed end def thread diff --git a/lib/mauve/notifier.rb b/lib/mauve/notifier.rb index 5bedeb9..6099457 100644 --- a/lib/mauve/notifier.rb +++ b/lib/mauve/notifier.rb @@ -5,17 +5,11 @@ require 'mauve/notifiers/xmpp' module Mauve class Notifier < MauveThread - - DEFAULT_XMPP_MESSAGE = "Mauve server started." include Singleton attr_accessor :sleep_interval - def initialize - super - end - def main_loop # # Cycle through the buffer. diff --git a/lib/mauve/notifiers/templates/email.html.erb b/lib/mauve/notifiers/templates/email.html.erb index f0ce1be..24b5e7b 100644 --- a/lib/mauve/notifiers/templates/email.html.erb +++ b/lib/mauve/notifiers/templates/email.html.erb @@ -1,12 +1,12 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title></title></head><body> -<p><strong><%= alert.update_type.upcase %>:</strong> <% +<p><a href="<%= WebInterface.url_for(alert) %>"><%= alert.update_type.upcase %></a>:<% case alert.update_type when "cleared" %><%= alert.cleared_at.to_s_relative %><% when "acknowledged" -%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by%><% +%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by%> until <%= alert.will_unacknowledge_at.to_s_human %><% else %><%= alert.raised_at.to_s_relative %><% end diff --git a/lib/mauve/notifiers/templates/email.txt.erb b/lib/mauve/notifiers/templates/email.txt.erb index dc5762b..aab44a8 100644 --- a/lib/mauve/notifiers/templates/email.txt.erb +++ b/lib/mauve/notifiers/templates/email.txt.erb @@ -3,7 +3,7 @@ case alert.update_type when "cleared" %><%= alert.cleared_at.to_s_relative %><% when "acknowledged" -%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %><% +%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><% else %><%= alert.raised_at.to_s_relative %><% end diff --git a/lib/mauve/notifiers/templates/xmpp.html.erb b/lib/mauve/notifiers/templates/xmpp.html.erb new file mode 100644 index 0000000..c6bfaed --- /dev/null +++ b/lib/mauve/notifiers/templates/xmpp.html.erb @@ -0,0 +1,21 @@ + <html xmlns="http://jabber.org/protocol/xhtml-im"><body xmlns="OAhttp://www.w3.org/1999/xhtml"> +<a href="<%=WebInterface.url_for(alert)%>"><%= alert.update_type.upcase %></a>: <% +case alert.update_type +when "cleared" +%><%= alert.cleared_at.to_s_relative %><% +when "acknowledged" +%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><% +else +%><%= alert.raised_at.to_s_relative %><% +end +%>: <%= alert.subject %>: <%= alert.summary %><% +if alert.source != alert.subject +%> -- from <%= alert.source %><% +end +%>.<% +if was_suppressed and not is_suppressed +%><em> Normal service has resumed.</em><% +elsif is_suppressed and not was_suppressed +%><em> Further alerts suppressed until things calm down.</em><% +end +%></body></html> diff --git a/lib/mauve/notifiers/templates/xmpp.txt.erb b/lib/mauve/notifiers/templates/xmpp.txt.erb index 837fd67..a73f41f 100644 --- a/lib/mauve/notifiers/templates/xmpp.txt.erb +++ b/lib/mauve/notifiers/templates/xmpp.txt.erb @@ -3,7 +3,7 @@ case alert.update_type when "cleared" %><%= alert.cleared_at.to_s_relative %><% when "acknowledged" -%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %><% +%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><% else %><%= alert.raised_at.to_s_relative %><% end @@ -11,10 +11,10 @@ end if alert.source != alert.subject %> -- from <%= alert.source %><% end -%>.<% +%>. <%=WebInterface.url_for(alert)%><% if was_suppressed and not is_suppressed -%> Normal service has resumed.<% +%> (Normal service has resumed.)<% elsif is_suppressed and not was_suppressed -%> Further alerts suppressed until things calm down.<% +%> (Further alerts suppressed until things calm down.)<% end %> diff --git a/lib/mauve/notifiers/xmpp.rb b/lib/mauve/notifiers/xmpp.rb index 7fe1e39..991194d 100644 --- a/lib/mauve/notifiers/xmpp.rb +++ b/lib/mauve/notifiers/xmpp.rb @@ -34,9 +34,11 @@ module Jabber # mean the other parts of the method fail to execute. # That would be bad. So kill parser_thread last @tbcbmutex.synchronize { @processing = 0 } - @fd.close if @fd and !@fd.closed? + if @fd and !@fd.closed? + @fd.close + stop + end @status = DISCONNECTED - stop end end end @@ -66,15 +68,15 @@ module Mauve include Jabber # Atrtribute. - attr_reader :name, :jid + attr_reader :name # Atrtribute. attr_accessor :password def initialize(name) Jabber::logger = self.logger - #Jabber::debug = true - #Jabber::warnings = true +# Jabber::debug = true +# Jabber::warnings = true @name = name @mucs = {} @@ -138,10 +140,11 @@ module Mauve # unless ex.nil? or @closing logger.warn(["Caught",ex.class,ex.to_s,"during XMPP",where].join(" ")) + @closing = true connect @mucs.each do |jid, muc| @mucs.delete(jid) - join_muc(jid) + join_muc(muc[:jid], muc[:password]) end end end @@ -156,11 +159,13 @@ module Mauve def close @closing = true - if @client and @client.is_connected? - @mucs.each do |jid, muc| - muc.exit("Goodbye!") if muc.active? - end - @client.send(Presence.new(nil, "Goodbye!").set_type(:unavailable)) + if @client + if @client.is_connected? + @mucs.each do |jid, muc| + muc[:client].exit("Goodbye!") if muc[:client].active? + end + @client.send(Presence.new(nil, "Goodbye!").set_type(:unavailable)) + end @client.close! end end @@ -202,7 +207,16 @@ module Mauve alert.to_s end - send_message(destination_jid, txt) + template_file = File.join(File.dirname(__FILE__),"templates","xmpp.html.erb") + + xhtml = if File.exists?(template_file) + ERB.new(File.read(template_file)).result(binding).chomp + else + logger.error("Could not find xmpp.txt.erb template") + alert.to_s + end + + send_message(destination_jid, txt, xhtml) end # Sends a message to the destionation. @@ -210,20 +224,23 @@ module Mauve # @param [String] destination The (full) JID to send to. # @param [String] msg The (formatted) message to send. # @return [NIL] nada. - def send_message(jid, msg) + def send_message(jid, msg, html_msg=nil) jid = JID.new(jid) unless jid.is_a?(JID) message = Message.new(jid) - - #if msg.is_a?(XHTML::HTML) - # message.add_element(msg) - #else message.body = msg - #end + if html_msg + begin + html_msg = REXML::Document.new(html_msg) unless html_msg.is_a?(REXML::Document) + message.add_element(html_msg) + rescue REXML::ParseException + logger.error "Bad XHTML: #{html_msg.inspect}" + end + end if is_muc?(jid) jid = join_muc(jid.strip) - muc = @mucs[jid] + muc = @mucs[jid][:client] if muc message.to = muc.jid @@ -272,28 +289,28 @@ module Mauve logger.debug("Adding new MUC client for #{jid}") - @mucs[jid.strip] = Jabber::MUC::MUCClient.new(@client) + @mucs[jid.strip] = {:jid => jid, :password => password, :client => Jabber::MUC::MUCClient.new(@client)} # Add some callbacks - @mucs[jid.strip].add_message_callback do |m| + @mucs[jid.strip][:client].add_message_callback do |m| receive_message(m) end - @mucs[jid.strip].add_private_message_callback do |m| + @mucs[jid.strip][:client].add_private_message_callback do |m| receive_message(m) end end - if !@mucs[jid.strip].active? + if !@mucs[jid.strip][:client].active? # # Make sure we have a resource. # - @mucs[jid.strip].join(jid, password) + @mucs[jid.strip][:client].join(jid, password) - logger.info("Joined #{jid}") + logger.info("Joined #{jid.strip}") else - logger.debug("Already joined #{jid}.") + logger.debug("Already joined #{jid.strip}.") end # @@ -410,10 +427,10 @@ module Mauve # that we've not sent ourselves, that are not historical, and that # match our resource or node in the body. # - if @mucs[msg.from.strip].is_a?(MUC::MUCClient) and - msg.from != @mucs[msg.from.strip].jid and + if @mucs[msg.from.strip][:client].is_a?(MUC::MUCClient) and + msg.from != @mucs[msg.from.strip][:client].jid and msg.x("jabber:x:delay") == nil and - (msg.body =~ /\b#{Regexp.escape(@mucs[msg.from.strip].jid.resource)}\b/i or + (msg.body =~ /\b#{Regexp.escape(@mucs[msg.from.strip][:client].jid.resource)}\b/i or msg.body =~ /\b#{Regexp.escape(@client.jid.node)}\b/i) receive_normal_message(msg) end diff --git a/lib/mauve/server.rb b/lib/mauve/server.rb index 57ddca8..20f7045 100644 --- a/lib/mauve/server.rb +++ b/lib/mauve/server.rb @@ -11,29 +11,23 @@ require 'mauve/timer' require 'mauve/udp_server' require 'mauve/processor' require 'mauve/http_server' +require 'mauve/heartbeat' require 'log4r' module Mauve class Server - DEFAULT_CONFIGURATION = { - :ip => "127.0.0.1", - :port => 32741, - :database => "sqlite3:///./mauvealert.db", - :log_file => "stdout", - :log_level => 1, - :transmission_cache_expire_time => 600 - } + DEFAULT_CONFIGURATION = { } # # This is the order in which the threads should be started. # - THREAD_CLASSES = [UDPServer, HTTPServer, Processor, Timer, Notifier] + THREAD_CLASSES = [UDPServer, HTTPServer, Processor, Timer, Notifier, Heartbeat] - attr_accessor :web_interface - attr_reader :stopped_at, :started_at, :initial_sleep, :packet_buffer, :notification_buffer + attr_accessor :hostname, :database, :initial_sleep + attr_reader :stopped_at, :started_at, :packet_buffer, :notification_buffer include Singleton @@ -43,8 +37,11 @@ module Mauve # Sleep time between pooling the @buffer buffer. @sleep = 1 - @frozen = false - @stop = false + @frozen = false + @stop = false + @hostname = "localhost" + @database = "sqlite3:///./mauvealert.db" + @stopped_at = MauveTime.now @started_at = MauveTime.now @@ -79,7 +76,7 @@ module Mauve end # - DataMapper.setup(:default, @config[:database]) + DataMapper.setup(:default, @database) # DataObjects::Sqlite3.logger = Log4r::Logger.new("Mauve::DataMapper") # diff --git a/lib/mauve/timer.rb b/lib/mauve/timer.rb index f6ada88..91dea18 100644 --- a/lib/mauve/timer.rb +++ b/lib/mauve/timer.rb @@ -13,12 +13,6 @@ module Mauve attr_accessor :sleep_interval, :last_run_at - def initialize - super - @initial_sleep = 300 - @initial_sleep_threshold = 300 - end - def main_loop # # Get the next alert. @@ -51,22 +45,27 @@ module Mauve # # Sleep indefinitely # - logger.info("Nothing to notify about -- snoozing indefinitely.") + logger.info("Nothing to notify about -- snoozing for a while.") + sleep_loops = 600 else # # La la la nothing to do. # logger.info("Next to notify: #{next_to_notify} -- snoozing until #{next_to_notify.due_at}") + sleep_loops = ((next_to_notify.due_at - MauveTime.now).to_f / 0.1).round.to_i end + sleep_loops = 1 if sleep_loops.nil? or sleep_loops < 1 + # # Ah-ha! Sleep with a break clause. # - while next_to_notify.nil? or MauveTime.now <= next_to_notify.due_at + sleep_loops.times do # # Start again if the situation has changed. # break if self.should_stop? + # # This is a rate-limiting step for alerts. # diff --git a/lib/mauve/version.rb b/lib/mauve/version.rb index 139b8eb..a4be324 100644 --- a/lib/mauve/version.rb +++ b/lib/mauve/version.rb @@ -1,5 +1,5 @@ module Mauve - VERSION="3.1.5" + VERSION="3.1.6" end diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb index 4594e10..4bb9517 100644 --- a/lib/mauve/web_interface.rb +++ b/lib/mauve/web_interface.rb @@ -22,7 +22,14 @@ module Mauve def self._logger Log4r::Logger.new(self.to_s) end - + + # + # Generic URL for + # + def self.url_for(obj) + [Mauve::HTTPServer.instance.base_url, obj.class.to_s.split("::").last.downcase, obj.id.to_s].join("/") + end + use Rack::CommonLogger use Rack::Chunked use Rack::ContentLength @@ -519,7 +526,6 @@ EOF env['rack.errors'] = RackErrorsProxy.new(logger) super(env) end - - end + end end |