lib/rackamole/alert/growl.rb
require 'ruby-growl'

module Rackamole::Alert
  # Leverages growl as a notification client.
  class Growl

    # Twitt an alert        
    def self.deliver_alert( logger, options, attrs )
      @growl ||= Growl.new( logger, options[:growl][:to] )
      @growl.send_alert( attrs )
    end
            
    # Send a growl notification for particular moled feature. A growl will
    # be sent based on the configuration :growl defined on Rack::Mole component
    # This option must specify the to ip addresses and the conditions
    # that will trigger a growl defined by alert_on for the type of
    # moled features to track via email. The notification will be sent via UDP,
    # so you will need to make sure it is properly configured for your domain.
    #
    # NOTE: This is just a notification mechanism. All moled event will be either logged 
    # or persisted in the db regardless.
    #
    # === Parameters:
    # options    :: Mole options. The :growl key must contains :to addresses.
    # args       :: The gathered information from the mole.
    def initialize( logger, recipients )
      raise "You must specify your growl :to addresses" unless recipients
      @recipients = recipients
      @logger   = logger
      @growls   = {}
    end
       
    # Send out a growl notification based of the watched features. A short message will be blasted to your growl
    # client based on information reported by the mole.
    # === Params:
    # args :: The moled info for a given feature. 
    def send_alert( args )
      recipients.each do |recipient|
        buff  = "#{args[:user_name]}:#{display_feature(args)}"
        title = "#{args[:app_name]}(#{args[:environment]})"
        case args[:type]
          when Rackamole.feature
            type     = "Feature"
            title    = "[Feat] #{title}"
            msg      = buff
            priority = -2
            sticky   = false
          when Rackamole.perf
            type     = "Perf" 
            title    = "[Perf] #{title}"
            msg      = "#{buff} #{format_time(args[:request_time])} secs"
            priority = 2
            sticky   = true
          when Rackamole.fault
            type     = "Fault"
            title    = "[Fault] #{title}"
            msg      = "#{buff}\n#{args[:fault]}"
            priority = 2
            sticky   = true            
        end
        growl( recipient ).notify( type, title, msg, priority, sticky )
      end
    rescue => boom
       logger.error "Rackamole growl alert failed with error `#{boom}"
    end
        
    # =========================================================================
    private
    
       attr_reader :logger, :recipients #:nodoc:
       
       # Fetch or create growl application...
       def growl( recipient )
         return @growls[recipient[:ip]] if @growls[recipient[:ip]]
         growl = ::Growl.new( recipient[:ip], 'rackamole', %w(Feature Perf Fault), nil, recipient[:password] )
         @growls[recipient[:ip]] = growl
         growl
       end
       
       # Display controller/action or path depending on frmk used...
       def display_feature( args )
         return args[:path] unless args[:route_info]
         "#{args[:route_info][:controller]}##{args[:route_info][:action]}"
       end

      # Format host ie fred@blee.com => fred
      def format_host( host )
        return host.gsub( /@.+/, '' ) if host =~ /@/
        host
      end
      
      # Format precision on request time
      def format_time( time )
        ("%4.2f" % time).to_f
      end
      
      # Truncate for twitt max size      
      # BOZO !! This will be hosed if not 1.9 for multibyte chars 
      def truncate(text, length = 140, truncate_string = "...")
        return "" if text.nil?
        l = length - truncate_string.size
        text.size > length ? (text[0...l] + truncate_string).to_s : text
      end       
  end
end