Class: OpenHAB::Core::Events::Source

Inherits:
Delegator
  • Object
show all
Defined in:
lib/openhab/core/events/source.rb

Overview

Represents the source of an event as a chain of delegated Components.

This class behaves like a String representing the event source, but also provides methods to access the individual components in the delegation chain.

Starting from openHAB 5.1, the source can contain multiple components that contain information about the delegation chain of the event.

Each component contains:

  • bundle: The module or app. For example: org.openhab.automation.jrubyscripting when a rule sends a command, or org.openhab.core.io.rest when a command comes from the REST API (UI).
  • actor: Optional. The rule, user or thinguid (e.g., "lighting_rule", "mqtt:topic:livingroom-switch:switch4")

Examples:

Log commands with source information

rule "Log item commands" do
  received_command MyItem
  run do |event|
    logger.info "#{MyItem.name} received command #{event.command} from: #{event.source}"
    logger.info "  Source components:"
    event.source.components.each_with_index do |component, index|
      logger.info "    #{index}: bundle=#{component.bundle}, actor=#{component.actor}"
    end
  end
end

Ignore commands from specific integrations

rule "Ignore UI commands" do
  received_command MyItem
  run do |event|
    next if event.source.sender?("org.openhab.core.io.rest")
    # process the command
  end
end

See Also:

Defined Under Namespace

Classes: Component

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ Source #initialize(components) ⇒ Source

Construct a new OpenHAB::Core::Events::Source object.

Overloads:

  • #initialize(source) ⇒ Source

    Parameters:

    • source (String)

      The event source as a string.

  • #initialize(components) ⇒ Source

    Parameters:

    • components (Array<Component>)

      The components in the event source delegation chain.



63
64
65
66
67
68
69
70
71
# File 'lib/openhab/core/events/source.rb', line 63

def initialize(source_or_components) # rubocop:disable Lint/MissingSuper
  @components = if source_or_components.is_a?(Array)
                  @source = nil
                  source_or_components.dup
                else
                  @source = -source_or_components
                  @source.split("=>").map { |s| Component.parse(s) }
                end.freeze
end

Instance Attribute Details

#actorString? (readonly)

The actor (user, device, etc.) of the initial component that sent the event.

Returns:

  • (String, nil)


173
174
175
# File 'lib/openhab/core/events/source.rb', line 173

def actor
  components.first&.actor
end

#bundleString? (readonly)

The bundle (module, app, etc.) of the initial component that sent the event.

Returns:

  • (String, nil)


163
164
165
# File 'lib/openhab/core/events/source.rb', line 163

def bundle
  components.first&.bundle
end

#componentsArray<Component> (readonly)

The components in the event source delegation chain.

Returns:



52
53
54
# File 'lib/openhab/core/events/source.rb', line 52

def components
  @components
end

#sourceString (readonly) Also known as: to_s, to_str, inspect, __getobj__

The event source as a string.

Returns:

  • (String)


153
154
155
# File 'lib/openhab/core/events/source.rb', line 153

def source
  @source ||= components.join("=>").freeze
end

Instance Method Details

#!=(other) ⇒ true, false

Returns:

  • (true, false)


191
192
193
# File 'lib/openhab/core/events/source.rb', line 191

def !=(other)
  !(self == other) # rubocop:disable Style/InverseMethods
end

#<=>(other) ⇒ Integer?

Returns:



196
197
198
199
200
201
# File 'lib/openhab/core/events/source.rb', line 196

def <=>(other)
  return 0 if self == other
  return nil unless other.respond_to?(:to_str)

  to_s <=> other.to_str
end

#==(other) ⇒ true, false

Returns:

  • (true, false)


183
184
185
186
187
188
# File 'lib/openhab/core/events/source.rb', line 183

def ==(other)
  return components == other.components if other.is_a?(Source)
  return to_s == other.to_str if other.respond_to?(:to_str)

  false
end

#actor_for(bundle) ⇒ String?

Returns the actor (user, device, etc.) for the specified bundle, if any.

Parameters:

  • bundle (#===)

    The bundle (module, app, etc.) to find the actor for.

Returns:

  • (String, nil)

    the actor (user, device, etc.) for the specified bundle, if any.



119
120
121
# File 'lib/openhab/core/events/source.rb', line 119

def actor_for(bundle)
  components.find { |c| bundle === c.bundle }&.actor # rubocop:disable Style/CaseEquality
end

#delegate(bundle, actor = nil) ⇒ Source

Construct a new OpenHAB::Core::Events::Source by adding an additional component to the delegation chain.

Parameters:

  • bundle (String)

    The bundle (module, app, etc.) of the new component to add to the chain.

  • actor (String, nil) (defaults to: nil)

    The actor (user, device, etc.) of the new component to add to the chain.

Returns:



80
81
82
# File 'lib/openhab/core/events/source.rb', line 80

def delegate(bundle, actor = nil)
  Source.new(components + [Component.build(bundle, actor)])
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/openhab/core/events/source.rb', line 203

def eql?(other)
  other.is_a?(Source) && components == other.components
end

#hashInteger

Returns:



208
209
210
# File 'lib/openhab/core/events/source.rb', line 208

def hash
  components.hash
end

#reject(bundle) ⇒ Source #reject({ |component| ... }) {|component| ... } ⇒ Source

Construct a new OpenHAB::Core::Events::Source without any components from the specified bundle.

This is useful if you consider events from a specific bundle as sensitive, and want to filter that component out from an untrusted sender.

Overloads:

  • #reject(bundle) ⇒ Source

    Returns a new Source without any components from the specified bundle.

    Parameters:

    • bundle (#===)

      The bundle (module, app, etc.) to reject.

    Returns:

    • (Source)

      a new Source without any components from the specified bundle.

  • #reject({ |component| ... }) {|component| ... } ⇒ Source

    Returns a new Source without any components for which the block returns true.

    Yield Parameters:

    • component (Component)

      Each component in the delegation chain.

    Returns:

    • (Source)

      a new Source without any components for which the block returns true.

Raises:

  • (ArgumentError)


137
138
139
140
141
142
143
144
145
# File 'lib/openhab/core/events/source.rb', line 137

def reject(bundle = nil, &)
  raise ArgumentError, "Either a bundle or a block must be given" unless bundle || block_given?

  Source.new(if block_given?
               components.reject(&)
             else
               components.reject { |c| bundle === c.bundle } # rubocop:disable Style/CaseEquality
             end)
end

#sender?(bundle_or_actor) ⇒ true, false #sender?(bundle: nil, actor: nil) ⇒ true, false

Check if the event was sent by the specified bundle or actor.

Checks if any component matches the specified bundle or actor.

Overloads:

  • #sender?(bundle_or_actor) ⇒ true, false

    Parameters:

    • bundle_or_actor (#===)

      The bundle (module, app, etc.) or actor (user, device, etc.) to check. If either a bundle or actor in any component in the source matches, this method returns true.

    Returns:

    • (true, false)
  • #sender?(bundle: nil, actor: nil) ⇒ true, false

    Parameters:

    • bundle (#===) (defaults to: nil)
    • actor (#===) (defaults to: nil)

    Returns:

    • (true, false)


100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/openhab/core/events/source.rb', line 100

def sender?(bundle_or_actor = nil, bundle: nil, actor: nil)
  unless bundle_or_actor || bundle || actor
    raise ArgumentError, "Specify one of bundle_or_actor, bundle or actor"
  end

  # rubocop:disable Style/CaseEquality
  components.any? do |sender|
    (bundle && bundle === sender.bundle) ||
      (actor && actor === sender.actor) ||
      (bundle_or_actor && bundle_or_actor === sender.bundle) ||
      (bundle_or_actor && bundle_or_actor === sender.actor)
  end
  # rubocop:enable Style/CaseEquality
end