rbus 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/CHANGELOG.txt +9 -0
  2. data/COPYING.txt +341 -0
  3. data/HACKING.txt +104 -0
  4. data/Manifest.txt +58 -0
  5. data/README.txt +17 -0
  6. data/Rakefile +97 -0
  7. data/TUTORIAL.txt +303 -0
  8. data/bin/rbus-send +165 -0
  9. data/examples/async_rb_and_notify.rb +56 -0
  10. data/examples/async_rb_loop.rb +52 -0
  11. data/examples/glib_async_rb_loop.rb +57 -0
  12. data/examples/glib_rhythmbox.rb +54 -0
  13. data/examples/hal_device_info.rb +54 -0
  14. data/examples/listnames.rb +37 -0
  15. data/examples/network_manager_get_properties.rb +50 -0
  16. data/examples/notification_bubble.rb +46 -0
  17. data/examples/rhythmbox_print_playing_uri.rb +41 -0
  18. data/examples/rhythmbox_signal_print_playing.rb +54 -0
  19. data/examples/rhythmbox_start_service.rb +39 -0
  20. data/examples/rhythmbox_toggle_playing.rb +46 -0
  21. data/lib/rbus.rb +25 -0
  22. data/lib/rbus/auth/auth.rb +53 -0
  23. data/lib/rbus/auth/dbus_cookie_sha1.rb +66 -0
  24. data/lib/rbus/auth/dummy.rb +37 -0
  25. data/lib/rbus/auth/external.rb +34 -0
  26. data/lib/rbus/auth/state_machine.rb +168 -0
  27. data/lib/rbus/bus/bus.rb +101 -0
  28. data/lib/rbus/bus/proxy.rb +137 -0
  29. data/lib/rbus/bus/transport.rb +125 -0
  30. data/lib/rbus/default.rb +29 -0
  31. data/lib/rbus/etc/exception.rb +44 -0
  32. data/lib/rbus/etc/log.rb +100 -0
  33. data/lib/rbus/etc/types.rb +56 -0
  34. data/lib/rbus/etc/version.rb +34 -0
  35. data/lib/rbus/glib.rb +29 -0
  36. data/lib/rbus/mainloop/glib.rb +77 -0
  37. data/lib/rbus/mainloop/mainloop.rb +84 -0
  38. data/lib/rbus/mainloop/observers.rb +149 -0
  39. data/lib/rbus/mainloop/thread.rb +78 -0
  40. data/lib/rbus/message/constants.rb +51 -0
  41. data/lib/rbus/message/marshal.rb +139 -0
  42. data/lib/rbus/message/message.rb +110 -0
  43. data/lib/rbus/message/reader.rb +108 -0
  44. data/lib/rbus/message/serial_generator.rb +48 -0
  45. data/lib/rbus/message/unmarshal.rb +171 -0
  46. data/lib/rbus/message/writer.rb +69 -0
  47. data/setup.rb +1608 -0
  48. data/spec/auth_spec.rb +123 -0
  49. data/spec/bus_spec.rb +178 -0
  50. data/spec/helpers/bus_mocks.rb +64 -0
  51. data/spec/helpers/spec_helper.rb +24 -0
  52. data/spec/mainloop_spec.rb +74 -0
  53. data/spec/marshal_spec.rb +91 -0
  54. data/spec/message_spec.rb +61 -0
  55. data/spec/observers_spec.rb +28 -0
  56. data/spec/proxy_spec.rb +120 -0
  57. data/spec/transport_spec.rb +187 -0
  58. data/spec/unmarshal_spec.rb +186 -0
  59. metadata +118 -0
@@ -0,0 +1,149 @@
1
+ #--
2
+ #
3
+ # R-Bus is a native Ruby implementation of the D-Bus protocol.
4
+ # Copyright (C) 2007 Kristoffer Lundén (kristoffer.lunden@gmail.com)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ # MA 02110-1301, USA. A copy of the GNU General Public License is
20
+ # also available at http://www.gnu.org/copyleft/gpl.html.
21
+ #
22
+ #++
23
+ #
24
+ require 'monitor'
25
+ module RBus
26
+ # module Message
27
+
28
+ # Waits for Signals in the message loop.
29
+ class SignalObserver
30
+ include Message::MessageTypes
31
+
32
+ def initialize(observable, rules, callback)
33
+ @observable = observable
34
+ @rules = rules
35
+ @callback = callback
36
+ @observable.add_observer(self)
37
+ end
38
+
39
+ def update(message)
40
+ #Log.debug(message)
41
+ @rules.each do |key,value|
42
+ Log.debug("#{key}: #{value}")
43
+ case key.to_s
44
+ when 'sender'
45
+ return unless value == message.sender
46
+ when 'interface'
47
+ return unless value == message.interface
48
+ when 'member'
49
+ return unless value == message.member
50
+ when 'path'
51
+ return unless value == message.object_path
52
+ when 'destination'
53
+ return unless value == message.destination
54
+ when 'type'
55
+ type = case value
56
+ when 'signal': SIGNAL
57
+ when 'method_call': METHOD_CALL
58
+ when 'method_return': METHOD_RETURN
59
+ when 'error': ERROR
60
+ end
61
+ Log.debug("#{type} == #{message.type}")
62
+ return unless type == message.type
63
+ when /^arg(\d+)/
64
+ return unless value == message.arguments[$1]
65
+ end
66
+ end
67
+ @callback.call(message.arguments)
68
+ end
69
+ end
70
+
71
+ # Waits for asynchronous replies in the message loop.
72
+ class AsyncObserver
73
+ def initialize(observable, serial, callback)
74
+ @observable = observable
75
+ @serial = serial
76
+ @callback = callback
77
+ @observable.add_observer(self)
78
+ end
79
+
80
+ def update(message)
81
+ Log.debug('AsyncObserver got message serial: ' + message.serial.to_s)
82
+ Log.debug('AsyncObserver wanted message serial: ' + @serial.to_s)
83
+ if message.serial == @serial
84
+ @observable.delete_observer(self)
85
+ @callback.call(message.arguments)
86
+ end
87
+ end
88
+ end
89
+
90
+ # Waits for synchronous replies in the message loop.
91
+ # Only used by threaded.
92
+ class SyncObserver
93
+ attr_reader :message
94
+
95
+ def initialize(observable, serial)
96
+ @observable = observable
97
+ @serial = serial
98
+ @observable.add_observer(self)
99
+ @message = nil
100
+ end
101
+
102
+ def update(message)
103
+ Log.debug('SyncObserver got message serial: ' + message.serial.to_s)
104
+ Thread.critical = true
105
+ if message.serial == @serial
106
+ @message = message
107
+ @observable.delete_observer(self)
108
+ end
109
+ Thread.critical = false
110
+ end
111
+ end
112
+
113
+ =begin Old, better(?) implementation?
114
+
115
+ # Waits for synchronous replies in the message loop.
116
+ class SyncObserver
117
+ include MonitorMixin
118
+ def initialize(observable, serial)
119
+ super()
120
+ @observable = observable
121
+ @serial = serial
122
+ @observable.add_observer(self)
123
+ @message = nil
124
+ @lock = new_cond
125
+ end
126
+
127
+ def wait
128
+ synchronize do
129
+ @lock.wait_while {@message.nil?}
130
+ @observable.delete_observer(self)
131
+ return @message.arguments
132
+ end
133
+ end
134
+
135
+ def update(message)
136
+ Log.debug('SyncObserver got message serial: ' + message.serial.to_s)
137
+ synchronize do
138
+ if message.serial == @serial
139
+ @message = message
140
+ @lock.signal
141
+ end
142
+ end
143
+ end
144
+
145
+
146
+
147
+ =end
148
+
149
+ end
@@ -0,0 +1,78 @@
1
+ #--
2
+ #
3
+ # R-Bus is a native Ruby implementation of the D-Bus protocol.
4
+ # Copyright (C) 2007 Kristoffer Lundén (kristoffer.lunden@gmail.com)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ # MA 02110-1301, USA. A copy of the GNU General Public License is
20
+ # also available at http://www.gnu.org/copyleft/gpl.html.
21
+ #
22
+ #++
23
+ #
24
+ require File.dirname(__FILE__) + '/mainloop'
25
+ require File.dirname(__FILE__) + '/observers'
26
+ module RBus
27
+ class Mainloop
28
+
29
+ def setup
30
+ @loop = Thread.new do
31
+ loop do
32
+ #IO.select([@transport.socket], nil, nil, nil)
33
+ message = @reader.read_message
34
+ handle_incoming(message)
35
+ end
36
+ end
37
+ end
38
+
39
+ # Threaded version of observable's method with same name.
40
+ def notify_observers(*arg) # :nodoc:
41
+ if defined? @observer_state and @observer_state
42
+ if defined? @observer_peers
43
+ for i in @observer_peers.dup
44
+ Thread.new{i.update(*arg)}
45
+ end
46
+ end
47
+ @observer_state = false
48
+ end
49
+ end
50
+
51
+ def send_message(message, callback = nil)
52
+ # TODO: if message has no_reply, use dummy observer
53
+ if message.member == 'AddMatch'
54
+ observer = SignalObserver.new(self, message.arguments[0], callback)
55
+ message.arguments = message.arguments[0].map{|key,value|"#{key}='#{value}'"}.join(',')
56
+ elsif callback
57
+ observer = AsyncObserver.new(self, message.serial, callback)
58
+ else
59
+ observer = SyncObserver.new(self, message.serial)
60
+ end
61
+
62
+ handle_outgoing(message)
63
+
64
+ if observer.instance_of?(SyncObserver)
65
+ while observer.message.nil?
66
+ #Thread.pass
67
+ end
68
+ return observer.message.arguments
69
+ end
70
+ end
71
+
72
+
73
+ end
74
+
75
+ def self.mainloop # :nodoc:
76
+ Thread.stop
77
+ end
78
+ end
@@ -0,0 +1,51 @@
1
+ #--
2
+ #
3
+ # R-Bus is a native Ruby implementation of the D-Bus protocol.
4
+ # Copyright (C) 2007 Kristoffer Lundén (kristoffer.lunden@gmail.com)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ # MA 02110-1301, USA. A copy of the GNU General Public License is
20
+ # also available at http://www.gnu.org/copyleft/gpl.html.
21
+ #
22
+ #++
23
+ #
24
+ module RBus
25
+ module Message
26
+ module MessageTypes
27
+ INVALID = 0
28
+ METHOD_CALL = 1
29
+ METHOD_RETURN = 2
30
+ ERROR = 3
31
+ SIGNAL = 4
32
+ end
33
+
34
+ module HeaderFields
35
+ PATH = 1
36
+ INTERFACE = 2
37
+ MEMBER = 3
38
+ ERROR_NAME = 4
39
+ REPLY_SERIAL = 5
40
+ DESTINATION = 6
41
+ SENDER = 7
42
+ SIGNATURE = 8
43
+ end
44
+
45
+ module Flags
46
+ EMPTY = 0
47
+ NO_REPLY_EXPECTED = 1
48
+ NO_AUTO_START = 2
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,139 @@
1
+ #--
2
+ #
3
+ # R-Bus is a native Ruby implementation of the D-Bus protocol.
4
+ # Copyright (C) 2007 Kristoffer Lundén (kristoffer.lunden@gmail.com)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ # MA 02110-1301, USA. A copy of the GNU General Public License is
20
+ # also available at http://www.gnu.org/copyleft/gpl.html.
21
+ #
22
+ #++
23
+ #
24
+ require 'stringio'
25
+ module RBus
26
+
27
+ # Mix in an array of values to gain the +dbus_marshal+ method
28
+ # Generally, this is used on the arguments of a message, and an
29
+ # array of header values. See Message::Writer#send_message.
30
+ module MarshalMixin
31
+ def dbus_marshal(signature)
32
+
33
+ tokens = StringIO.new(signature)
34
+ ms = StringIO.new('')
35
+
36
+ skip = lambda {|alignment| ms.write("\0" * (-ms.pos & alignment - 1))}
37
+
38
+ parser = lambda {|element,sig|
39
+ case sig
40
+ when 'b'
41
+ skip.call(4)
42
+ if element && element != 0 && element != false
43
+ ms.write([1].pack('I'))
44
+ else
45
+ ms.write([0].pack('I'))
46
+ end
47
+ when 'y'
48
+ ms.write([element.to_i].pack('C'))
49
+ when 'n'
50
+ skip.call(2)
51
+ ms.write([element.to_i].pack('s'))
52
+ when 'q'
53
+ skip.call(2)
54
+ ms.write([element.to_i].pack('S'))
55
+ when 'u'
56
+ skip.call(4)
57
+ ms.write([element.to_i].pack('I'))
58
+ when 'i'
59
+ skip.call(4)
60
+ ms.write([element.to_i].pack('i'))
61
+ when 'd'
62
+ skip.call(8)
63
+ ms.write([element.to_f].pack('D'))
64
+ when 's','o'
65
+ skip.call(4)
66
+ str = element.to_s
67
+ ms.write([str.length,str].pack('Ia*x'))
68
+ when 'g'
69
+ str = element.to_s
70
+ ms.write([str.length,str].pack('Ca*x'))
71
+ when 'v'
72
+ parser.call(element.object_signature, 'g')
73
+ parser.call(element.object, element.object_signature)
74
+ when 'a'
75
+ skip.call(4)
76
+ next_token = tokens.read(1)
77
+ t_pos = tokens.pos
78
+
79
+ # Postion of array length int
80
+ a_len_pos = ms.pos
81
+ # ...which is here
82
+ ms.write("\0\0\0\0")
83
+
84
+ # Pad already here, to find correct end of padding...
85
+ case next_token
86
+ when 's','o','b','i','u'
87
+ skip.call(4)
88
+ when '{','(','a','d'
89
+ skip.call(8)
90
+ when 'q','n'
91
+ skip.call(2)
92
+ end
93
+ pad_pos = ms.pos
94
+
95
+ if next_token == '{'
96
+ skip.call(8)
97
+ element.each do |key,value|
98
+ tokens.pos = t_pos
99
+ parser.call(key,tokens.read(1))
100
+ parser.call(value,tokens.read(1))
101
+ end
102
+ while next_token != '}'
103
+ next_token = tokens.read(1)
104
+ end
105
+ else
106
+
107
+ element.each do |value|
108
+ tokens.pos = t_pos
109
+ parser.call(value,next_token)
110
+ end
111
+ end
112
+
113
+ # Fill in array length
114
+ m_new_pos = ms.pos
115
+ a_length = ms.pos - pad_pos
116
+ ms.pos = a_len_pos
117
+ parser.call(a_length, 'u')
118
+ ms.pos = m_new_pos
119
+
120
+ when '('
121
+ skip.call(8)
122
+ ret_val = ''
123
+ element.each {|value|
124
+ next_token = tokens.read(1)
125
+ break if next_token == ')'
126
+ parser.call(value, next_token)
127
+ }
128
+ else
129
+ raise NotImplementedError, "can't marshal #{sig}"
130
+ end
131
+ }
132
+ each do |el|
133
+ parser.call(el,tokens.read(1))
134
+ end
135
+
136
+ ms.string
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,110 @@
1
+ #--
2
+ #
3
+ # R-Bus is a native Ruby implementation of the D-Bus protocol.
4
+ # Copyright (C) 2007 Kristoffer Lundén (kristoffer.lunden@gmail.com)
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ # MA 02110-1301, USA. A copy of the GNU General Public License is
20
+ # also available at http://www.gnu.org/copyleft/gpl.html.
21
+ #
22
+ #++
23
+ #
24
+
25
+ module RBus
26
+ module Message
27
+
28
+ # Base implementation for the different message types.
29
+ class Base
30
+
31
+ include MessageTypes
32
+ include HeaderFields
33
+ include Flags
34
+
35
+ attr_accessor :destination, :interface
36
+ attr_accessor :object_path, :member
37
+ attr_accessor :sender
38
+ attr_accessor :arguments, :signature
39
+
40
+ attr_accessor :flags, :body
41
+
42
+ attr_accessor :type
43
+ attr_accessor :serial
44
+
45
+ def initialize
46
+ @flags ||= EMPTY
47
+ @body = ''
48
+ @serial = SerialGenerator.get_unique
49
+ @type ||= INVALID
50
+ yield self if block_given?
51
+ end
52
+
53
+ def no_reply=(bool)
54
+ if bool
55
+ @flags |= NO_REPLY_EXPECTED
56
+ else
57
+ @flags &= ~ NO_REPLY_EXPECTED
58
+ end
59
+ puts "FLAGS: #{@flags}"
60
+ end
61
+
62
+ def no_auto_start=(bool)
63
+ if bool
64
+ @flags |= NO_AUTO_START
65
+ else
66
+ @flags &= ~ NO_AUTO_START
67
+ end
68
+ end
69
+
70
+ def header_fields
71
+ hf = []
72
+ @object_path and hf << [PATH, Variant.new(@object_path, 'o')]
73
+ @interface and hf << [INTERFACE, Variant.new(@interface, 's')]
74
+ @member and hf << [MEMBER, Variant.new(@member, 's')]
75
+ @destination and hf << [DESTINATION, Variant.new(@destination, 's')]
76
+ @signature and hf << [SIGNATURE, Variant.new(@signature, 'g')]
77
+ hf
78
+ end
79
+ end
80
+ end
81
+
82
+ class MethodCall < Message::Base
83
+ def initialize
84
+ @type = METHOD_CALL
85
+ super
86
+ end
87
+ end
88
+
89
+ class MethodReturn < Message::Base
90
+ def initialize
91
+ @type = METHOD_RETURN
92
+ super
93
+ end
94
+ end
95
+
96
+ class Error < Message::Base
97
+ def initialize
98
+ @type = ERROR
99
+ super
100
+ end
101
+ end
102
+
103
+ class Signal < Message::Base
104
+ def initialize
105
+ @type = SIGNAL
106
+ super
107
+ end
108
+ end
109
+
110
+ end