Class: Uppercut::Agent

Inherits:
Base
  • Object
show all
Defined in:
lib/uppercut/agent.rb

Constant Summary collapse

VALID_CALLBACKS =
[:signon, :signoff, :subscribe, :unsubscribe, :subscription_approval,
:subscription_denial, :status_change, :status_message_change]
DEFAULT_OPTIONS =
{ :connect => true }

Instance Attribute Summary collapse

Attributes inherited from Base

#client

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#connect, #connected?, #disconnect, #reconnect, #stanza

Constructor Details

#initialize(user, pw, options = {}) ⇒ Agent

Create a new instance of an Agent, possibly connecting to the server.

user should be a String in the form: “user@server/Resource”. pw is simply the password for this account. The final, and optional, argument is a boolean which controls whether or not it will attempt to connect to the server immediately. Defaults to true.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/uppercut/agent.rb', line 54

def initialize(user,pw,options={})
  options = DEFAULT_OPTIONS.merge(options)
  
  @user = user
  @pw = pw
  connect if options[:connect]
  listen if options[:listen]
  
  @allowed_roster = options[:roster]
  @redirects = {}
end

Instance Attribute Details

#allowed_rosterObject

Returns the value of attribute allowed_roster.



169
170
171
# File 'lib/uppercut/agent.rb', line 169

def allowed_roster
  @allowed_roster
end

#rosterObject

Returns the value of attribute roster.



169
170
171
# File 'lib/uppercut/agent.rb', line 169

def roster
  @roster
end

Class Method Details

.command(pattern, &block) ⇒ Object

Define a new command for the agent.

The pattern can be a String or a Regexp. If a String is passed, it will dispatch this command only on an exact match. A Regexp simply must match.

There is always at least one argument sent to the block. The first is a always an Uppercut::Message object, which can be used to reply to the sender. The rest of the arguments to the block correspond to any captures in the pattern Regexp. (Does not apply to String patterns).



18
19
20
21
22
23
# File 'lib/uppercut/agent.rb', line 18

def command(pattern,&block)
  @@patterns ||= []
  g = gensym
  @@patterns << [pattern,g]
  define_method(g, &block)
end

.on(type, &block) ⇒ Object

Define a callback for specific presence events.

At the moment this is only confirmed to work with :subscribe and :unsubscribe, but it may work with other types as well. Example:

on :subscribe do |conversation|

conversation.send "Welcome! Send 'help' for instructions."

end



34
35
36
37
# File 'lib/uppercut/agent.rb', line 34

def on(type, &block)
  raise 'Not a valid callback' unless VALID_CALLBACKS.include?(type)
  define_method("__on_#{type.to_s}") { |conversation| block[conversation] }
end

Instance Method Details

#inspectObject

:nodoc:



67
68
69
70
71
# File 'lib/uppercut/agent.rb', line 67

def inspect #:nodoc:
  "<Uppercut::Agent #{@user} " +
  "#{listening? ? 'Listening' : 'Not Listening'}:" +
  "#{connected? ? 'Connected' : 'Disconnected'}>"
end

#listenObject

Makes an Agent instance begin listening for incoming messages and subscription requests.

Current listen simply eats any errors that occur, in the interest of keeping the remote agent alive. These should be logged at some point in the future. Pass debug as true to prevent this behaviour.

Calling listen fires off a new Thread whose sole purpose is to listen for new incoming messages and then fire off a new Thread which dispatches the message to the proper handler.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/uppercut/agent.rb', line 83

def listen
  connect unless connected?

  @listen_thread = Thread.new {
    @client.add_message_callback do |message|
      log_and_continue do
        next if message.body.nil?
        next unless allowed_roster_includes?(message.from)
        dispatch message
      end
    end

    @roster ||= Jabber::Roster::Helper.new(@client)
    @roster.add_presence_callback do |item, old_presence, new_presence|
      # Callbacks:
      # post-subscribe initial stuff (oldp == nil)
      # status change: (oldp.show != newp.show)
      # status message change: (oldp.status != newp.status)

      log_and_continue do
        if old_presence.nil? && new_presence.type == :unavailable
          dispatch_presence :signoff, new_presence
        elsif old_presence.nil?
          # do nothing, we don't care
        elsif old_presence.type == :unavailable && new_presence
          dispatch_presence :signon, new_presence
        elsif old_presence.show != new_presence.show
          dispatch_presence :status_change, new_presence
        elsif old_presence.status != new_presence.status
          dispatch_presence :status_message_change, new_presence
        end
      end
    end
    @roster.add_subscription_request_callback do |item,presence|
      # Callbacks:
      # someone tries to subscribe (presence.type == 'subscribe')

      log_and_continue do
        case presence.type
        when :subscribe
          next unless allowed_roster_includes?(presence.from)
          @roster.accept_subscription(presence.from)
          @roster.add(presence.from, nil, true)
          dispatch_presence :subscribe, presence
        end
      end
    end
    @roster.add_subscription_callback do |item, presence|
      # Callbacks:
      # user allows agent to subscribe to them (presence.type == 'subscribed')
      # user denies agent subscribe request (presence.type == 'unsubscribed')
      # user unsubscribes from agent (presence.type == 'unsubscribe')

      log_and_continue do
        case presence.type
        when :subscribed
          dispatch_presence :subscription_approval, presence
        when :unsubscribed
          # if item.subscription != :from, it's not a denial... it's just an unsub
          dispatch_presence(:subscription_denial, presence) if item.subscription == :from
        when :unsubscribe
          dispatch_presence :unsubscribe, presence
        end
      end
    end
    sleep
  }
end

#listening?Boolean

True if the Agent is currently listening for incoming messages.

Returns:

  • (Boolean)


160
161
162
# File 'lib/uppercut/agent.rb', line 160

def listening?
  @listen_thread && @listen_thread.alive?
end

#redirect_from(contact, &block) ⇒ Object



164
165
166
167
# File 'lib/uppercut/agent.rb', line 164

def redirect_from(contact,&block)
  @redirects[contact] ||= []
  @redirects[contact].push block
end

#stopObject

Stops the Agent from listening to incoming messages.

Simply kills the thread if it is running.



155
156
157
# File 'lib/uppercut/agent.rb', line 155

def stop
  @listen_thread.kill if listening?
end