~ps-jenkins/friends/latestsnapshot-0.2.0daily13.05.07.1-0ubuntu1

« back to all changes in this revision

Viewing changes to friends/service/dispatcher.py

  • Committer: Robert Bruce Park
  • Date: 2013-05-01 17:05:12 UTC
  • mfrom: (160.11.31 trunk-next)
  • Revision ID: robert.park@canonical.com-20130501170512-d3xrvv4vmv24k3ir
Land trunk-next into lp:friends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
from contextlib import ContextDecorator
32
32
 
33
33
from friends.utils.avatar import Avatar
34
 
from friends.utils.account import AccountManager
 
34
from friends.utils.account import find_accounts
35
35
from friends.utils.manager import protocol_manager
36
36
from friends.utils.menus import MenuManager
37
37
from friends.utils.model import Model, persist_model
38
 
from friends.shorteners import lookup
 
38
from friends.utils.shorteners import Short
 
39
from friends.errors import ignored
39
40
 
40
41
 
41
42
log = logging.getLogger(__name__)
52
53
    """Exit the dispatcher 30s after the most recent method call returns."""
53
54
    timers = set()
54
55
    callback = STUB
 
56
    timeout = 30
55
57
 
56
58
    def __enter__(self):
57
59
        self.clear_all_timers()
60
62
        self.set_new_timer()
61
63
 
62
64
    def clear_all_timers(self):
63
 
        log.debug('Clearing {} shutdown timer(s)...'.format(len(self.timers)))
64
65
        while self.timers:
65
 
            GLib.source_remove(self.timers.pop())
 
66
            timer_id = self.timers.pop()
 
67
            log.debug('Clearing timer id: {}'.format(timer_id))
 
68
            GLib.source_remove(timer_id)
66
69
 
67
70
    def set_new_timer(self):
68
71
        # Concurrency will cause two methods to exit near each other,
69
72
        # causing two timers to be set, so we have to clear them again.
70
73
        self.clear_all_timers()
71
74
        log.debug('Starting new shutdown timer...')
72
 
        self.timers.add(GLib.timeout_add_seconds(30, self.terminate))
 
75
        self.timers.add(GLib.timeout_add_seconds(self.timeout, self.terminate))
73
76
 
74
77
    def terminate(self, *ignore):
75
78
        """Exit the dispatcher, but only if there are no active subthreads."""
96
99
        bus_name = dbus.service.BusName(DBUS_INTERFACE, bus=self.bus)
97
100
        super().__init__(bus_name, self.__dbus_object_path__)
98
101
        self.mainloop = mainloop
99
 
        self.account_manager = AccountManager()
 
102
 
 
103
        self.accounts = find_accounts()
100
104
 
101
105
        self._unread_count = 0
102
106
        self.menu_manager = MenuManager(self.Refresh, self.mainloop.quit)
119
123
        # account.protocol() starts a new thread and then returns
120
124
        # immediately, so there is no delay or blocking during the
121
125
        # execution of this method.
122
 
        for account in self.account_manager.get_all():
123
 
            try:
 
126
        for account in self.accounts.values():
 
127
            with ignored(NotImplementedError):
124
128
                account.protocol('receive')
125
 
            except NotImplementedError:
126
 
                # If a protocol doesn't support receive then ignore it.
127
 
                pass
128
129
 
129
130
    @exit_after_idle
130
131
    @dbus.service.method(DBUS_INTERFACE)
163
164
            service.Do('list', '6', 'list_id') # Fetch a single list.
164
165
        """
165
166
        if account_id:
166
 
            accounts = [self.account_manager.get(account_id)]
 
167
            accounts = [self.accounts.get(int(account_id))]
167
168
            if None in accounts:
168
169
                message = 'Could not find account: {}'.format(account_id)
169
170
                failure(message)
170
171
                log.error(message)
171
172
                return
172
173
        else:
173
 
            accounts = list(self.account_manager.get_all())
 
174
            accounts = list(self.accounts.values())
174
175
 
175
176
        called = False
176
177
        for account in accounts:
177
178
            log.debug('{}: {} {}'.format(account.id, action, arg))
178
179
            args = (action, arg) if arg else (action,)
179
 
            try:
 
180
            # Not all accounts are expected to implement every action.
 
181
            with ignored(NotImplementedError):
180
182
                account.protocol(*args, success=success, failure=failure)
181
183
                called = True
182
 
            except NotImplementedError:
183
 
                # Not all accounts are expected to implement every action.
184
 
                pass
185
184
        if not called:
186
185
            failure('No accounts supporting {} found.'.format(action))
187
186
 
205
204
            service.SendMessage('Your message')
206
205
        """
207
206
        sent = False
208
 
        for account in self.account_manager.get_all():
 
207
        for account in self.accounts.values():
209
208
            if account.send_enabled:
210
209
                sent = True
211
210
                log.debug(
240
239
            service.SendReply('6', '34245645347345626', 'Your reply')
241
240
        """
242
241
        log.debug('Replying to {}, {}'.format(account_id, message_id))
243
 
        account = self.account_manager.get(account_id)
 
242
        account = self.accounts.get(int(account_id))
244
243
        if account is not None:
245
244
            account.protocol(
246
245
                'send_thread',
298
297
        free to ignore error conditions at your peril.
299
298
        """
300
299
        log.debug('Uploading {} to {}'.format(uri, account_id))
301
 
        account = self.account_manager.get(account_id)
 
300
        account = self.accounts.get(int(account_id))
302
301
        if account is not None:
303
302
            account.protocol(
304
303
                'upload',
329
328
 
330
329
    @exit_after_idle
331
330
    @dbus.service.method(DBUS_INTERFACE, in_signature='s', out_signature='s')
332
 
    def URLShorten(self, url):
333
 
        """Shorten a URL.
 
331
    def URLShorten(self, message):
 
332
        """Shorten all the URLs in a message.
334
333
 
335
 
        Takes a url as a string and returns a shortened url as a string.
 
334
        Takes a message as a string, and returns the message with all
 
335
        it's URLs shortened.
336
336
 
337
337
        example:
338
338
            import dbus
343
343
            short_url = service.URLShorten(url)
344
344
        """
345
345
        service_name = self.settings.get_string('urlshorter')
346
 
        log.info('Shortening URL {} with {}'.format(url, service_name))
347
 
        if (lookup.is_shortened(url) or
348
 
            not self.settings.get_boolean('shorten-urls')):
349
 
            # It's already shortened, or the preference is not set.
350
 
            return url
351
 
        service = lookup.lookup(service_name)
352
 
        try:
353
 
            return service.shorten(url)
354
 
        except Exception:
355
 
            log.exception('URL shortening class: {}'.format(service))
356
 
            return url
 
346
        log.info('Shortening with {}'.format(service_name))
 
347
        if not self.settings.get_boolean('shorten-urls'):
 
348
            return message
 
349
        return Short(service_name).sub(message)
357
350
 
358
351
    @exit_after_idle
359
352
    @dbus.service.method(DBUS_INTERFACE)