File: responder.rb

package info (click to toggle)
ruby-xmpp4r 0.5.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,384 kB
  • sloc: ruby: 17,382; xml: 74; sh: 12; makefile: 4
file content (165 lines) | stat: -rw-r--r-- 4,581 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# =XMPP4R - XMPP Library for Ruby
# License:: Ruby's license (see the LICENSE file) or GNU GPL, at your option.
# Website::http://xmpp4r.github.io

require 'xmpp4r/iq'
require 'xmpp4r/discovery/iq/discoinfo'
require 'xmpp4r/discovery/iq/discoitems'
require 'xmpp4r/caps/helper/generator'

module Jabber
  module Discovery
    ##
    # Responds to Service Discovery queries on a given node
    #
    # Modify returned elements by these attributes:
    # * Responder#identities
    # * Responder#features (Responder#add_features is a short-cut accepting an Array of Strings, too)
    # * Responder#forms
    # * Responder#items
    class Responder
      ##
      # Service Discovery node this Responder is responsible for
      # (will not answer queries for other nodes)
      attr_reader :node

      ##
      # Identities returned on Discovery Info query
      #
      # Array of [Discovery::Identity]
      attr_accessor :identities
      ##
      # Features returned on Discovery Info query,
      #
      # Array of [Discovery::Feature]
      attr_accessor :features
      ##
      # Forms returned on Discovery Info query
      # (such as Software Information)
      #
      # Array of [Dataforms::XData]
      attr_accessor :forms

      ##
      # Children returned on Discovery Item query
      #
      # May contain other Discovery::Responder instances
      # which will generate an item dynamically from their
      # first identity
      #
      # Array of [Discovery::Item] or [Discovery::Responder] (mixed)
      attr_accessor :items

      ##
      # Set the JID this helper feels responsible for
      # (default: nil, responsible for any JID)
      attr_accessor :my_jid

      CALLBACK_PRIORITY = 180

      ##
      # Initialize responder for a specific node
      # stream:: [Jabber::Stream]
      # node:: [nil] or [String]
      def initialize(stream, node=nil, identities=[], features=[], items=[])
        @stream = stream
        @my_jid = nil
        @node = node
        @identities = identities
        @features = []
        add_features(features)
        @forms = []
        @items = items

        @stream.add_iq_callback(CALLBACK_PRIORITY, self) do |iq|
          my_nodes = [@node, "#{@node}##{generate_ver}"]

          if iq.type == :get and
             iq.query.kind_of? IqQueryDiscoInfo and
             my_nodes.include?(iq.query.node)

            answer = iq.answer(false)
            answer.type = :result
            query = answer.add(IqQueryDiscoInfo.new)
            query.node = iq.query.node
            (@identities + @features + @forms).each do |element|
              query.add(element)
            end
            @stream.send(answer)

            true  # handled

          elsif iq.type == :get and
                iq.query.kind_of? IqQueryDiscoItems and
                my_nodes.include?(iq.query.node)

            answer = iq.answer(false)
            answer.type = :result
            query = answer.add(IqQueryDiscoItems.new)
            query.node = iq.query.node
            @items.each do |item|
              if item.kind_of? Responder
                query.add(item.generate_item)
              else
                query.add(item)
              end
            end
            @stream.send(answer)

            true  # handled

          else
            false # not handled
          end
        end
      end

      ##
      # Add a feature
      # feature:: [Jabber::Discovery::Feature] or [String]
      def add_feature(feature)
        if feature.kind_of? Feature
          @features << feature
        else
          @features << Feature.new(feature.to_s)
        end
      end

      ##
      # Add a series of features
      # features:: Array of [Jabber::Discovery::Feature] or [String]
      def add_features(features)
        features.each { |feature|
          add_feature(feature)
        }
      end

      ##
      # Generate a XEP-0115: Entity Capabilities <c/> element
      # for inclusion in Presence stanzas. This enables efficient
      # caching of Service Discovery information.
      def generate_caps
        Caps::C.new(@node, generate_ver)
      end

      ##
      # Generate an item for inclusion in items discovery in other
      # responders
      # return:: [Discovery::Item] or nil
      def generate_item
        i = @identities.first
        if i
          Item.new(@my_jid || @stream.jid, i.iname, @node)
        else
          nil
        end
      end

      private

      def generate_ver
        Caps::generate_ver(@identities, @features, @forms)
      end
    end
  end
end