~ubuntu-branches/ubuntu/precise/ubuntuone-client/precise-201112142106

« back to all changes in this revision

Viewing changes to ubuntuone/platform/windows/tools.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2011-08-09 12:47:56 UTC
  • mfrom: (1.1.53 upstream)
  • Revision ID: james.westby@ubuntu.com-20110809124756-7nzilp3oix0a1yl9
Tags: 1.7.1-0ubuntu1
* New upstream release.
* debian/*:
  - Removed obsolete pycompat file
  - Removed ubuntuone-client-gnome deps and binary packaging, as it was
    moved out to separate project upstream.
  - Updated copyright to remove obsolete file reference
* debian/patches:
  - Removed patches which have been included upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# ubuntuone.syncdaemon.tools - tools for SyncDaemon
2
2
#
3
 
# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
4
 
#         Manuel de la Pena <manuel@canonical.com>
 
3
# Authors: Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
 
4
#          Manuel de la Pena <manuel@canonical.com>
 
5
#          Alejandro J. Cura <alecu@canonical.com>
5
6
#
6
7
# Copyright 2011 Canonical Ltd.
7
8
#
21
22
 
22
23
import logging
23
24
import time
 
25
import subprocess
24
26
import sys
25
27
 
26
 
from win32api import GetUserNameEx
27
 
from win32con import NameSamCompatible
28
 
from win32pipe import CallNamedPipe
29
28
from twisted.internet import defer, reactor
 
29
from _winreg import OpenKey, HKEY_LOCAL_MACHINE, QueryValueEx
30
30
 
31
31
from ubuntuone.syncdaemon.config import get_user_config
32
 
from ubuntuone.platform.windows.ipc import NAMED_PIPE_URL
33
32
from ubuntuone.platform.windows.ipc_client import UbuntuOneClient
34
33
 
 
34
U1_REG_PATH = r'Software\\Ubuntu One'
 
35
SD_INSTALL_PATH = 'SyncDaemonInstallPath'
35
36
 
36
37
def is_running(bus=None):
37
 
    """Check if there is a syncdaemon instance running.
38
 
 
39
 
    Running means the name is registered in the given bus.
40
 
 
41
 
    """
42
 
    pipe = NAMED_PIPE_URL % GetUserNameEx(NameSamCompatible)
43
 
    try:
44
 
        CallNamedPipe(pipe, '', 512, 0)
45
 
        return True
46
 
    except:
47
 
        return False
 
38
    """Check if there is a syncdaemon instance running."""
 
39
    #TODO: Do not start two instances of this process
 
40
    #      https://launchpad.net/bugs/803672
 
41
    #NOTE: Changed to True so SD can be restarted while this bug is fixed
 
42
    return True
48
43
 
49
44
 
50
45
class SyncDaemonTool(object):
51
46
    """Various utility methods to test/play with the SyncDaemon."""
52
47
 
53
 
    def __init__(self, named_pipe=None):
54
 
        self.named_pipe = named_pipe
55
 
        self.client = UbuntuOneClient() 
 
48
    # WARNING: most of the methods of this class are "pre-processed" by
 
49
    # __getattribute__, to call _call_after_connection before the method
 
50
    # is called, so they should either be decorated with inlineCallbacks
 
51
    # or return a deferred.
 
52
    #
 
53
    # All methods and instance variables that should not be handled that way
 
54
    # should be put in the list below (or start with _):
 
55
 
 
56
    _DONT_VERIFY_CONNECTED = [
 
57
        "wait_connected",
 
58
        "client", "last_event", "delayed_call", "log", "connected",
 
59
    ]
 
60
 
 
61
    def _should_wrap(self, attr_name):
 
62
        """Check if this attribute should be wrapped."""
 
63
        return not (attr_name in SyncDaemonTool._DONT_VERIFY_CONNECTED
 
64
                    or attr_name.startswith("_"))
 
65
 
 
66
    def __getattribute__(self, attr_name):
 
67
        """If the attribute is not special, verify the ipc connection."""
 
68
        attr = super(SyncDaemonTool, self).__getattribute__(attr_name)
 
69
        if SyncDaemonTool._should_wrap(self, attr_name):
 
70
            return self._call_after_connection(attr)
 
71
        else:
 
72
            return attr
 
73
 
 
74
    def __init__(self):
 
75
        """Initialize this instance."""
 
76
        self.client = UbuntuOneClient()
56
77
        self.last_event = 0
57
78
        self.delayed_call = None
58
79
        self.log = logging.getLogger('ubuntuone.SyncDaemon.SDTool')
59
 
 
 
80
        self.connected = self.client.connect()
 
81
 
 
82
    def _call_after_connection(self, method):
 
83
        """Make sure Perspective Broker is connected before calling."""
 
84
 
 
85
        @defer.inlineCallbacks
 
86
        def call_after_connection_inner(*args, **kwargs):
 
87
            """Call the given method after the connection to pb is made."""
 
88
            yield self.connected
 
89
            retval = yield method(*args, **kwargs)
 
90
            defer.returnValue(retval)
 
91
 
 
92
        return call_after_connection_inner
60
93
 
61
94
    def _get_dict(self, a_dict):
62
95
        """Converts a dict returned by the IPC to a dict of strings."""
75
108
            # check if the syncdaemon is running
76
109
            # catch all errors, pylint: disable-msg=W0703
77
110
            try:
78
 
                self.client.connect(pipe=self.named_pipe)
 
111
                self.client.connect()
79
112
                d.callback(True)
80
113
            except Exception, e:
81
114
                self.log.debug('Not connected: %s', e)
84
117
        reactor.callLater(.5, check_connection_status)
85
118
        return d
86
119
 
 
120
    @defer.inlineCallbacks
87
121
    def get_current_downloads(self):
88
122
        """Return a deferred that will be fired with the current downloads."""
89
 
        d = defer.Deferred()
90
 
 
91
 
        def reply_handler(downloads, d):
92
 
            """Current downloads callback."""
93
 
            downloads_str = []
94
 
            for download in downloads:
95
 
                downloads_str.append(self._get_dict(download))
96
 
            d.callback(downloads_str)
97
 
 
98
 
        downloads_d = self.client.status.current_downloads()
99
 
        downloads_d.addCallback(lambda downloads: reply_handler(downloads, d))
100
 
        return d
 
123
        downloads = yield self.client.status.current_downloads()
 
124
        downloads_str = []
 
125
        for download in downloads:
 
126
            downloads_str.append(self._get_dict(download))
 
127
        defer.returnValue(downloads_str)
101
128
 
102
129
    def wait_all_downloads(self, verbose=False):
103
130
        """Wait until there is no more pending downloads."""
126
153
        d.addCallback(reply_handler)
127
154
        return d
128
155
 
 
156
    @defer.inlineCallbacks
129
157
    def get_current_uploads(self):
130
158
        """Return a deferred that will be called with the current uploads."""
131
 
        d = defer.Deferred()
132
 
 
133
 
        def reply_handler(uploads, d):
134
 
            """Reply handler."""
135
 
            uploads_str = []
136
 
            for upload in uploads:
137
 
                uploads_str.append(self._get_dict(upload))
138
 
            d.callback(uploads_str)
139
 
 
140
 
        uploads_d = self.client.status.current_uploads()
141
 
        uploads_d.addCallback(lambda uploads: reply_handler(uploads, d))
142
 
        return d
 
159
        uploads = yield self.client.status.current_uploads()
 
160
        uploads_str = []
 
161
        for upload in uploads:
 
162
             uploads_str.append(self._get_dict(upload))
 
163
        defer.returnValue(uploads_str)
143
164
 
144
165
    def wait_all_uploads(self, verbose=False):
145
166
        """Wait until there is no more pending uploads."""
259
280
        self.log.debug('unsubscribe_share: %r', share_id)
260
281
        return self.client.shares.unsubscribe(share_id)
261
282
 
 
283
    @defer.inlineCallbacks
262
284
    def get_shares(self):
263
285
        """Get the list of shares (accepted or not)."""
264
286
        self.log.debug('get_shares')
265
 
        d = defer.Deferred()
266
 
 
267
 
        def reply_handler(results):
268
 
            """Get_shares reply handler."""
269
 
            shares = []
270
 
            for result in results:
271
 
                shares.append(self._get_dict(result))
272
 
            self.log.debug('shares: %r', shares)
273
 
            d.callback(shares)
274
 
 
275
 
        shares_d = self.client.shares.get_shares()
276
 
        shares_d.addCallback(reply_handler)
277
 
        return d
 
287
        shares = yield self.client.shares.get_shares()
 
288
        shares_str = []
 
289
        for share in shares:
 
290
            shares_str.append(self._get_dict(share))
 
291
        defer.returnValue(shares_str)
278
292
 
279
293
    def refresh_shares(self):
280
294
        """Call refresh_shares method via DBus.
292
306
        return self.client.shares.create_share(path, username, name,
293
307
                                               access_level)
294
308
 
 
309
    @defer.inlineCallbacks
295
310
    def list_shared(self):
296
311
        """Get the list of the shares "shared"/created/offered."""
297
312
        self.log.debug('list_shared')
298
 
        d = defer.Deferred()
299
 
 
300
 
        def reply_handler(results):
301
 
            """Get_shares reply handler."""
302
 
            shares = []
303
 
            for result in results:
304
 
                shares.append(self._get_dict(result))
305
 
            self.log.debug('shared: %r', shares)
306
 
            d.callback(shares)
307
 
 
308
 
        shared_d = self.client.shares.get_shared()
309
 
        shared_d.addCallback(reply_handler)
310
 
        return d
 
313
        shared = yield self.client.shares.get_shared()
 
314
        shares_str = []
 
315
        for share in shared:
 
316
            shares_str.append(self._get_dict(share))
 
317
        defer.returnValue(shares_str)
311
318
 
312
319
    def wait_for_signals(self, signal_ok, signal_error,
313
320
                         dbus_iface=None):
339
346
        self.log.debug('unsubscribe_folder')
340
347
        return self.client.folders.unsubscribe(folder_id)
341
348
 
 
349
    @defer.inlineCallbacks
342
350
    def get_folders(self):
343
351
        """Return the list of folders (a list of dicts)."""
344
352
        self.log.debug('get_folders')
345
 
        d = defer.Deferred()
346
 
 
347
 
        def reply_handler(results):
348
 
            """Get_folders reply handler."""
349
 
            folders = []
350
 
            for result in results:
351
 
                folders.append(self._get_dict(result))
352
 
            self.log.debug('folders: %r', folders)
353
 
            d.callback(folders)
354
 
 
355
 
        folders_d = self.client.folders.get_folders()
356
 
        folders_d.addCallback(reply_handler)
357
 
        return d
 
353
        folders = yield self.client.folders.get_folders()
 
354
        folders_str = []
 
355
        for folder in folders:
 
356
            folders_str.append(self._get_dict(folder))
 
357
        defer.returnValue(folders_str)
358
358
 
359
359
    def get_folder_info(self, path):
360
360
        """Call the get_info method for a UDF path."""
412
412
        """Disconnect syncdaemon."""
413
413
        return self.client.sync_daemon.disconnect()
414
414
 
 
415
    @defer.inlineCallbacks
415
416
    def get_status(self):
416
417
        """Get the current_status dict."""
417
 
 
418
 
        d = defer.Deferred()
419
 
        def reply_handler(status):
420
 
            """The reply handler"""
421
 
            state_dict = self._get_dict(status)
422
 
            state_dict['is_connected'] = bool(state_dict['is_connected'])
423
 
            state_dict['is_online'] = bool(state_dict['is_online'])
424
 
            state_dict['is_error'] = bool(state_dict['is_error'])
425
 
            d.callback(state_dict)
426
 
        status_d = self.client.status.current_status()
427
 
        status_d.addCallback(reply_handler)
428
 
        status_d.addErrback(d.errback)
429
 
        return d
 
418
        status = yield self.client.status.current_status()
 
419
        state_dict = self._get_dict(status)
 
420
        state_dict['is_connected'] = bool(state_dict['is_connected'])
 
421
        state_dict['is_online'] = bool(state_dict['is_online'])
 
422
        state_dict['is_error'] = bool(state_dict['is_error'])
 
423
        defer.returnValue(state_dict)
430
424
 
431
425
    def waiting(self):
432
426
        """Return a description of the waiting queue elements."""
442
436
 
443
437
    def start(self):
444
438
        """Start syncdaemon if it's not running."""
445
 
        if not is_running(self.bus):
446
 
            raise Exception('Not implemented yet!')
 
439
        if not is_running():
 
440
            # look in the reg to find the path of the .exe to be executed
 
441
            # to launch the sd on windows
 
442
            key = OpenKey(HKEY_LOCAL_MACHINE, U1_REG_PATH)
 
443
            path = QueryValueEx(key, SD_INSTALL_PATH)[0]
 
444
            p = subprocess.Popen([path,])
 
445
            return defer.succeed(p)
447
446
        else:
448
447
            return defer.succeed(None)
449
448
 
568
567
        """Return the shares link directory."""
569
568
        return self.client.sync_daemon.get_sharesdir_link()
570
569
 
 
570
    def set_status_changed_handler(self, handler):
 
571
        """Set the status changed handler."""
 
572
        self.client.status.on_status_changed_cb = handler
 
573
        return defer.succeed(None)