/
export.rb
133 lines (116 loc) · 4.28 KB
/
export.rb
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
# dbus/introspection.rb - module containing a low-level D-Bus introspection implementation
#
# This file is part of the ruby-dbus project
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.
require 'thread'
module DBus
# Exception raised when an interface cannot be found in an object.
class InterfaceNotInObject < Exception
end
# Exception raised when a method cannot be found in an inferface.
class MethodNotInInterface < Exception
end
# Method raised when a method returns an invalid return type.
class InvalidReturnType < Exception
end
# Exported object type
# = Exportable D-Bus object class
#
# Objects that are going to be exported by a D-Bus service
# should inherit from this class.
class Object
# The path of the object.
attr_reader :path
# The interfaces that the object supports.
class_attribute :intfs
# The service that the object is exported by.
attr_writer :service
@@cur_intf = nil
@@intfs_mutex = Mutex.new
# Create a new object with a given _path_.
def initialize(path)
@path = path
@service = nil
end
# State that the object implements the given _intf_.
def implements(intf)
# use a setter
self.intfs = (self.intfs || {}).merge({intf.name => intf})
end
# Dispatch a message _msg_.
def dispatch(msg)
case msg.message_type
when Message::METHOD_CALL
if not self.intfs[msg.interface]
raise InterfaceNotInObject, msg.interface
end
meth = self.intfs[msg.interface].methods[msg.member.to_sym]
raise MethodNotInInterface if not meth
methname = Object.make_method_name(msg.interface, msg.member)
reply = nil
begin
retdata = method(methname).call(*msg.params)
retdata = [*retdata]
reply = Message.new.reply_to(msg)
meth.rets.zip(retdata).each do |rsig, rdata|
reply.add_param(rsig.type, rdata)
end
rescue => ex
puts("DBus call Error: #{ex.to_s}")
reply = Message.error(msg, "org.freedesktop.DBus.Error.Failed", "#{ex.class}: #{ex}\n==== Backtrace ====\n#{ex.backtrace.join("\n")}")
end
@service.bus.send(reply.marshall)
end
end
# Select (and create) the interface that the following defined methods
# belong to.
def self.dbus_interface(s)
@@intfs_mutex.synchronize do
@@cur_intf = Interface.new(s)
self.intfs = (self.intfs || {}).merge({s => @@cur_intf})
yield
@@cur_intf = nil
end
end
# Dummy undefined interface class.
class UndefinedInterface < ScriptError
def initialize(sym)
super "No interface specified for #{sym}"
end
end
# Defines an exportable method on the object with the given name _sym_,
# _prototype_ and the code in a block.
def self.dbus_method(sym, protoype = "", &block)
raise UndefinedInterface, sym if @@cur_intf.nil?
@@cur_intf.define(Method.new(sym.to_s).from_prototype(protoype))
define_method(Object.make_method_name(@@cur_intf.name, sym.to_s), &block)
end
# Emits a signal from the object with the given _interface_, signal
# _sig_ and arguments _args_.
def emit(intf, sig, *args)
@service.bus.emit(@service, self, intf, sig, *args)
end
# Defines a signal for the object with a given name _sym_ and _prototype_.
def self.dbus_signal(sym, protoype = "")
raise UndefinedInterface, sym if @@cur_intf.nil?
cur_intf = @@cur_intf
signal = Signal.new(sym.to_s).from_prototype(protoype)
cur_intf.define(Signal.new(sym.to_s).from_prototype(protoype))
define_method(sym.to_s) do |*args|
emit(cur_intf, signal, *args)
end
end
####################################################################
private
# Helper method that returns a method name generated from the interface
# name _intfname_ and method name _methname_.
def self.make_method_name(intfname, methname)
"#{intfname}%%#{methname}"
end
end # class Object
end # module DBus