rbus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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