In Files

Parent

DBus::Connection

D-Bus main connection class

Main class that maintains a connection to a bus and can handle incoming and outgoing messages.

Attributes

message_queue[R]

pop and push messages here

unique_name[R]

The unique name (by specification) of the message.

Public Class Methods

new(path) click to toggle source

Create a new connection to the bus for a given connect path. path format is described in the D-Bus specification: dbus.freedesktop.org/doc/dbus-specification.html#addresses and is something like: "transport1:key1=value1,key2=value2;transport2:key1=value1,key2=value2" e.g. "unix:path=/tmp/dbus-test" or "tcp:host=localhost,port=2687"

# File lib/dbus/bus.rb, line 198
def initialize(path)
  @message_queue = MessageQueue.new(path)
  @unique_name = nil
  @method_call_replies = Hash.new
  @method_call_msgs = Hash.new
  @signal_matchrules = Hash.new
  @proxy = nil
  @object_root = Node.new("/")
end

Public Instance Methods

[](name) click to toggle source
Alias for: service
add_match(mr, &slot) click to toggle source

Asks bus to send us messages matching mr, and execute slot when received

# File lib/dbus/bus.rb, line 470
def add_match(mr, &slot)
  # check this is a signal.
  mrs = mr.to_s
  DBus.logger.debug "#{@signal_matchrules.size} rules, adding #{mrs.inspect}"
  # don't ask for the same match if we override it
  unless @signal_matchrules.key?(mrs)
    DBus.logger.debug "Asked for a new match"
    proxy.AddMatch(mrs)
  end
  @signal_matchrules[mrs] = slot
end
dispatch_message_queue() click to toggle source

Dispatch all messages that are available in the queue, but do not block on the queue. Called by a main loop when something is available in the queue

# File lib/dbus/bus.rb, line 211
def dispatch_message_queue
  while (msg = @message_queue.pop(:non_block)) # FIXME EOFError
    process(msg)
  end
end
emit(service, obj, intf, sig, *args) click to toggle source

@api private Emit a signal event for the given service, object obj, interface intf and signal sig with arguments args.

# File lib/dbus/bus.rb, line 558
def emit(service, obj, intf, sig, *args)
  m = Message.new(DBus::Message::SIGNAL)
  m.path = obj.path
  m.interface = intf.name
  m.member = sig.name
  m.sender = service.name
  i = 0
  sig.params.each do |par|
    m.add_param(par.type, args[i])
    i += 1
  end
  @message_queue.push(m)
end
glibize() click to toggle source

Tell a bus to register itself on the glib main loop

# File lib/dbus/bus.rb, line 218
def glibize
  require 'glib2'
  # Circumvent a ruby-glib bug
  @channels ||= Array.new

  gio = GLib::IOChannel.new(@message_queue.socket.fileno)
  @channels << gio
  gio.add_watch(GLib::IOChannel::IN) do |c, ch|
    dispatch_message_queue
    true
  end
end
introspect(dest, path) click to toggle source

@api private Issues a call to the org.freedesktop.DBus.Introspectable.Introspect method dest is the service and path the object path you want to introspect If a code block is given, the introspect call in asynchronous. If not data is returned

FIXME: link to ProxyObject data definition The returned object is a ProxyObject that has methods you can call to issue somme METHOD_CALL messages, and to setup to receive METHOD_RETURN

# File lib/dbus/bus.rb, line 381
def introspect(dest, path)
  if not block_given?
    # introspect in synchronous !
    data = introspect_data(dest, path)
    pof = DBus::ProxyObjectFactory.new(data, self, dest, path)
    return pof.build
  else
    introspect_data(dest, path) do |async_data|
      yield(DBus::ProxyObjectFactory.new(async_data, self, dest, path).build)
    end
  end
end
introspect_data(dest, path, &reply_handler) click to toggle source

@api private

# File lib/dbus/bus.rb, line 353
def introspect_data(dest, path, &reply_handler)
  m = DBus::Message.new(DBus::Message::METHOD_CALL)
  m.path = path
  m.interface = "org.freedesktop.DBus.Introspectable"
  m.destination = dest
  m.member = "Introspect"
  m.sender = unique_name
  if reply_handler.nil?
    send_sync_or_async(m).first
  else
    send_sync_or_async(m) do |*args|
      # TODO test async introspection, is it used at all?
      args.shift            # forget the message, pass only the text
      reply_handler.call(*args)
      nil
    end
  end
end
on_return(m, &retc) click to toggle source

@api private Specify a code block that has to be executed when a reply for message m is received.

# File lib/dbus/bus.rb, line 459
def on_return(m, &retc)
  # Have a better exception here
  if m.message_type != Message::METHOD_CALL
    raise "on_return should only get method_calls"
  end
  @method_call_msgs[m.serial] = m
  @method_call_replies[m.serial] = retc
end
process(m) click to toggle source

@api private Process a message m based on its type.

# File lib/dbus/bus.rb, line 494
def process(m)
  return if m.nil? #check if somethings wrong
  case m.message_type
  when Message::ERROR, Message::METHOD_RETURN
    raise InvalidPacketException if m.reply_serial == nil
    mcs = @method_call_replies[m.reply_serial]
    if not mcs
      DBus.logger.debug "no return code for mcs: #{mcs.inspect} m: #{m.inspect}"
    else
      if m.message_type == Message::ERROR
        mcs.call(Error.new(m))
      else
        mcs.call(m)
      end
      @method_call_replies.delete(m.reply_serial)
      @method_call_msgs.delete(m.reply_serial)
    end
  when DBus::Message::METHOD_CALL
    if m.path == "/org/freedesktop/DBus"
      DBus.logger.debug "Got method call on /org/freedesktop/DBus"
    end
    node = @service.get_node(m.path)
    if not node
      reply = Message.error(m, "org.freedesktop.DBus.Error.UnknownObject",
                            "Object #{m.path} doesn't exist")
      @message_queue.push(reply)
    # handle introspectable as an exception:
    elsif m.interface == "org.freedesktop.DBus.Introspectable" and
        m.member == "Introspect"
      reply = Message.new(Message::METHOD_RETURN).reply_to(m)
      reply.sender = @unique_name
      reply.add_param(Type::STRING, node.to_xml)
      @message_queue.push(reply)
    else
      obj = node.object
      return if obj.nil?    # FIXME, pushes no reply
      obj.dispatch(m) if obj
    end
  when DBus::Message::SIGNAL
    # the signal can match multiple different rules
    @signal_matchrules.each do |mrs, slot|
      if DBus::MatchRule.new.from_s(mrs).match(m)
        slot.call(m)
      end
    end
  else
    DBus.logger.debug "Unknown message type: #{m.message_type}"
  end
rescue Exception => ex
  raise m.annotate_exception(ex)
end
proxy() click to toggle source

Set up a ProxyObject for the bus itself, since the bus is introspectable. Returns the object.

# File lib/dbus/bus.rb, line 421
def proxy
  if @proxy == nil
    path = "/org/freedesktop/DBus"
    dest = "org.freedesktop.DBus"
    pof = DBus::ProxyObjectFactory.new(DBUSXMLINTRO, self, dest, path)
    @proxy = pof.build["org.freedesktop.DBus"]
  end
  @proxy
end
remove_match(mr) click to toggle source
# File lib/dbus/bus.rb, line 482
def remove_match(mr)
  mrs = mr.to_s
  unless @signal_matchrules.delete(mrs).nil?
    # don't remove nonexisting matches.
    # FIXME if we do try, the Error.MatchRuleNotFound is *not* raised
    # and instead is reported as "no return code for nil"
    proxy.RemoveMatch(mrs)
  end
end
request_service(name) click to toggle source

Attempt to request a service name.

FIXME, NameRequestError cannot really be rescued as it will be raised when dispatching a later call. Rework the API to better match the spec. @return [Service]

# File lib/dbus/bus.rb, line 403
def request_service(name)
  # Use RequestName, but asynchronously!
  # A synchronous call would not work with service activation, where
  # method calls to be serviced arrive before the reply for RequestName
  # (Ticket#29).
  proxy.RequestName(name, NAME_FLAG_REPLACE_EXISTING) do |rmsg, r|
    if rmsg.is_a?(Error)  # check and report errors first
      raise rmsg
    elsif r != REQUEST_NAME_REPLY_PRIMARY_OWNER
      raise NameRequestError
    end
  end
  @service = Service.new(name, self)
  @service
end
send_sync(m) click to toggle source

@api private Send a message m on to the bus. This is done synchronously, thus the call will block until a reply message arrives.

# File lib/dbus/bus.rb, line 440
def send_sync(m, &retc) # :yields: reply/return message
  return if m.nil? #check if somethings wrong
  @message_queue.push(m)
  @method_call_msgs[m.serial] = m
  @method_call_replies[m.serial] = retc

  retm = wait_for_message
  return if retm.nil? #check if somethings wrong
  
  process(retm)
  while @method_call_replies.has_key? m.serial
    retm = wait_for_message
    process(retm)
  end
end
send_sync_or_async(message, &reply_handler) click to toggle source

@api private Send a message. If reply_handler is not given, wait for the reply and return the reply, or raise the error. If reply_handler is given, it will be called when the reply eventually arrives, with the reply message as the 1st param and its params following

# File lib/dbus/bus.rb, line 329
def send_sync_or_async(message, &reply_handler)
  ret = nil
  if reply_handler.nil?
    send_sync(message) do |rmsg|
      if rmsg.is_a?(Error)
        raise rmsg
      else
        ret = rmsg.params
      end
    end
  else
    on_return(message) do |rmsg|
      if rmsg.is_a?(Error)
        reply_handler.call(rmsg)
      else
        reply_handler.call(rmsg, * rmsg.params)
      end
    end
    @message_queue.push(message)
  end
  ret
end
service(name) click to toggle source

Retrieves the Service with the given name. @return [Service]

# File lib/dbus/bus.rb, line 548
def service(name)
  # The service might not exist at this time so we cannot really check
  # anything
  Service.new(name, self)
end
Also aliased as: []
wait_for_message() click to toggle source

@api private Wait for a message to arrive. Return it once it is available.

# File lib/dbus/bus.rb, line 433
def wait_for_message
  @message_queue.pop                 # FIXME EOFError
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.