| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 1 | # Contributors Listed Below - COPYRIGHT 2016 | 
 | 2 | # [+] International Business Machines Corp. | 
 | 3 | # | 
 | 4 | # | 
 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 6 | # you may not use this file except in compliance with the License. | 
 | 7 | # You may obtain a copy of the License at | 
 | 8 | # | 
 | 9 | #     http://www.apache.org/licenses/LICENSE-2.0 | 
 | 10 | # | 
 | 11 | # Unless required by applicable law or agreed to in writing, software | 
 | 12 | # distributed under the License is distributed on an "AS IS" BASIS, | 
 | 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 
 | 14 | # implied. See the License for the specific language governing | 
 | 15 | # permissions and limitations under the License. | 
 | 16 |  | 
 | 17 | import sys | 
 | 18 | import dbus | 
 | 19 | import dbus.mainloop.glib | 
 | 20 | import gobject | 
 | 21 | import obmc.mapper | 
 | 22 |  | 
 | 23 |  | 
 | 24 | class Wait(object): | 
 | 25 |     def __init__(self, bus, waitlist, *a, **kw): | 
 | 26 |         self.bus = bus | 
 | 27 |         self.waitlist = dict(zip(waitlist, [None]*len(waitlist))) | 
 | 28 |         mapper = bus.get_object( | 
 | 29 |             obmc.mapper.MAPPER_NAME, | 
 | 30 |             obmc.mapper.MAPPER_PATH, | 
 | 31 |             introspect=False) | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 32 |         self.iface = dbus.Interface( | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 33 |             mapper, dbus_interface=obmc.mapper.MAPPER_IFACE) | 
 | 34 |         self.done = False | 
 | 35 |         self.callback = kw.pop('callback', None) | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 36 |         self.error_callback = kw.pop('error_callback', self.default_error) | 
 | 37 |         self.busy_retries = kw.pop('busy_retries', 5) | 
 | 38 |         self.busy_retry_delay_milliseconds = kw.pop( | 
 | 39 |             'busy_retry_delay_milliseconds', 1000) | 
 | 40 |         self.waitlist_keyword = kw.pop('waitlist_keyword', None) | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 41 |  | 
 | 42 |         self.bus.add_signal_receiver( | 
 | 43 |             self.name_owner_changed_handler, | 
 | 44 |             dbus_interface=dbus.BUS_DAEMON_IFACE, | 
 | 45 |             signal_name='NameOwnerChanged') | 
 | 46 |         self.bus.add_signal_receiver( | 
 | 47 |             self.interfaces_added_handler, | 
 | 48 |             dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager', | 
 | 49 |             sender_keyword='sender', | 
 | 50 |             signal_name='InterfacesAdded') | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 51 |  | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 52 |         self.name_owner_changed_handler() | 
 | 53 |  | 
 | 54 |     @staticmethod | 
 | 55 |     def default_error(e): | 
 | 56 |         raise e | 
 | 57 |  | 
 | 58 |     def force_done(self): | 
 | 59 |         if self.done: | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 60 |             return | 
 | 61 |  | 
 | 62 |         self.done = True | 
 | 63 |         self.bus.remove_signal_receiver( | 
 | 64 |             self.name_owner_changed_handler, | 
 | 65 |             dbus_interface=dbus.BUS_DAEMON_IFACE, | 
 | 66 |             signal_name='NameOwnerChanged') | 
 | 67 |         self.bus.remove_signal_receiver( | 
 | 68 |             self.interfaces_added_handler, | 
 | 69 |             dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager', | 
 | 70 |             signal_name='InterfacesAdded') | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 71 |  | 
 | 72 |     def check_done(self): | 
 | 73 |         if not all(self.waitlist.values()) or self.done: | 
 | 74 |             return | 
 | 75 |  | 
 | 76 |         self.force_done() | 
 | 77 |  | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 78 |         if self.callback: | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 79 |             kwargs = {} | 
 | 80 |             if self.waitlist_keyword: | 
 | 81 |                 kwargs[waitlist_keyword] = self.waitlist | 
 | 82 |             self.callback(**kwargs) | 
 | 83 |  | 
 | 84 |     def get_object_async(self, path, retry): | 
 | 85 |         method = getattr(self.iface, 'GetObject') | 
 | 86 |         method.call_async( | 
 | 87 |             path, | 
 | 88 |             reply_handler=lambda x: self.get_object_callback( | 
 | 89 |                 path, x), | 
 | 90 |             error_handler=lambda x: self.get_object_error( | 
 | 91 |                 path, retry, x)) | 
 | 92 |         return False | 
 | 93 |  | 
 | 94 |     def get_object_error(self, path, retry, e): | 
 | 95 |         if self.done: | 
 | 96 |             return | 
 | 97 |  | 
 | 98 |         if e.get_dbus_name() == 'org.freedesktop.DBus.Error.FileNotFound': | 
 | 99 |             pass | 
 | 100 |         elif e.get_dbus_name() == 'org.freedesktop.DBus.Error.ObjectPathInUse': | 
 | 101 |             if retry > self.busy_retries: | 
 | 102 |                 self.force_done() | 
 | 103 |                 self.error_callback(e) | 
 | 104 |             else: | 
 | 105 |                 gobject.timeout_add( | 
 | 106 |                     self.busy_retry_delay_milliseconds, | 
 | 107 |                     self.get_object_async, | 
 | 108 |                     path, | 
 | 109 |                     retry + 1) | 
 | 110 |         else: | 
 | 111 |             self.force_done() | 
 | 112 |             self.error_callback(e) | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 113 |  | 
 | 114 |     def get_object_callback(self, path, info): | 
 | 115 |         self.waitlist[path] = list(info)[0] | 
 | 116 |         self.check_done() | 
 | 117 |  | 
 | 118 |     def name_owner_changed_handler(self, *a, **kw): | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 119 |         if self.done: | 
 | 120 |             return | 
 | 121 |  | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 122 |         for path in filter( | 
 | 123 |                 lambda x: not self.waitlist[x], self.waitlist.keys()): | 
 | 124 |             self.get_object_async(path, 0) | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 125 |  | 
 | 126 |     def interfaces_added_handler(self, path, *a, **kw): | 
 | 127 |         if self.done: | 
 | 128 |             return | 
| Brad Bishop | a562704 | 2016-09-20 16:08:51 -0400 | [diff] [blame^] | 129 |  | 
| Brad Bishop | c656a86 | 2016-07-25 09:11:41 -0400 | [diff] [blame] | 130 |         if path in self.waitlist.keys(): | 
 | 131 |             self.waitlist[path] = kw['sender'] | 
 | 132 |         self.check_done() |