28
28
from twisted.internet import defer
29
29
from twisted.python.failure import Failure
30
from ubuntuone.credentials import (DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH,
30
from ubuntuone.platform.linux.credentials import (
31
DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH,
31
32
DBUS_CREDENTIALS_IFACE)
32
33
from ubuntuone.syncdaemon.interfaces import IMarker
33
34
from ubuntuone.syncdaemon import config
95
96
def _get_share_dict(share):
96
97
"""Get a dict with all the attributes of: share."""
97
98
share_dict = share.__dict__.copy()
99
if 'subscribed' not in share_dict:
100
share_dict['subscribed'] = share.subscribed
98
101
for k, v in share_dict.items():
100
103
share_dict[unicode(k)] = ''
101
104
elif k == 'path':
102
105
share_dict[unicode(k)] = v.decode('utf-8')
103
elif k == 'accepted':
106
elif k == 'accepted' or k == 'subscribed':
104
107
share_dict[unicode(k)] = bool_str(v)
106
109
share_dict[unicode(k)] = unicode(v)
137
140
@dbus.service.signal(DBUS_IFACE_SYNC_NAME, signature='sa{ss}')
138
141
def SignalError(self, signal, extra_args):
139
142
""" An error ocurred while trying to emit a signal. """
142
144
def emit_signal_error(self, signal, extra_args):
143
145
""" emit's a Error signal. """
217
219
@dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='aa{ss}')
218
220
def current_downloads(self):
219
""" return list of files with a download in progress. """
221
"""Return a list of files with a download in progress."""
220
222
logger.debug('called current_downloads')
221
223
current_downloads = []
222
for download in self.action_queue.downloading:
224
relpath = self.fs_manager.get_by_node_id(*download).path
226
# the path has gone away! ignore this download
228
path = self.fs_manager.get_abspath(download[0], relpath)
229
info = self.action_queue.downloading[download]
230
entry = {'path':path,
231
'share_id':download[0],
232
'node_id':download[1],
233
'n_bytes_read':str(info.get('n_bytes_read', 0))}
235
entry['deflated_size'] = str(info['deflated_size'])
236
# the idea is to do nothing, pylint: disable-msg=W0704
238
# ignore the deflated_size key
240
current_downloads.append(entry)
224
for cmd in self.action_queue.queue.waiting:
225
if isinstance(cmd, Download) and cmd.running:
228
'share_id': cmd.share_id,
229
'node_id': cmd.node_id,
230
'n_bytes_read': str(cmd.n_bytes_read),
232
if cmd.deflated_size is not None:
233
entry['deflated_size'] = str(cmd.deflated_size)
234
current_downloads.append(entry)
241
235
return current_downloads
243
237
def _get_command_path(self, cmd):
310
304
""" return a list of files with a upload in progress """
311
305
logger.debug('called current_uploads')
312
306
current_uploads = []
313
for upload in self.action_queue.uploading:
314
share_id, node_id = upload
315
if IMarker.providedBy(node_id):
318
relpath = self.fs_manager.get_by_node_id(share_id, node_id).path
320
# the path has gone away! ignore this upload
322
path = self.fs_manager.get_abspath(share_id, relpath)
323
info = self.action_queue.uploading[upload]
324
entry = {'path':path,
325
'share_id':upload[0],
327
'n_bytes_written':str(info.get('n_bytes_written', 0))}
329
entry['deflated_size'] = str(info['deflated_size'])
330
# the idea is to do nothing, pylint: disable-msg=W0704
332
# ignore the deflated_size key
334
current_uploads.append(entry)
307
for cmd in self.action_queue.queue.waiting:
308
if isinstance(cmd, Upload) and cmd.running:
311
'share_id': cmd.share_id,
312
'node_id': cmd.node_id,
313
'n_bytes_written': str(cmd.n_bytes_written),
315
if cmd.deflated_size is not None:
316
entry['deflated_size'] = str(cmd.deflated_size)
317
current_uploads.append(entry)
335
318
return current_uploads
337
320
@dbus.service.signal(DBUS_IFACE_STATUS_NAME)
482
465
def __init__(self, dbus_iface):
483
466
self.dbus_iface = dbus_iface
485
def handle_default(self, event_name, *args, **kwargs):
468
def handle_default(self, event_name, **kwargs):
486
469
"""Handle all events."""
487
from ubuntuone.syncdaemon.event_queue import EVENTS
488
470
event_dict = {'event_name': event_name}
489
event_args = list(EVENTS[event_name])
490
event_dict.update(kwargs)
491
for key in set(event_args).intersection(kwargs.keys()):
492
event_args.pop(event_args.index(key))
493
for i in xrange(0, len(event_args)):
494
event_dict[event_args[i]] = args[i]
495
471
event_dict.update(kwargs)
496
472
self.dbus_iface.events.emit_event(event_dict)
709
685
self.dbus_iface.folders.emit_folder_unsubscribed(udf)
711
687
def handle_VM_UDF_UNSUBSCRIBE_ERROR(self, udf_id, error):
712
"""Handle VM_UDF_UNSUBSCRIBE_ERROR event.
714
Emit FolderUnSubscribeError signal.
688
"""Handle VM_UDF_UNSUBSCRIBE_ERROR, emit FolderUnSubscribeError."""
717
689
self.dbus_iface.folders.emit_folder_unsubscribe_error(udf_id, error)
719
691
def handle_VM_UDF_CREATED(self, udf):
724
696
"""Handle VM_UDF_CREATE_ERROR event, emit FolderCreateError signal."""
725
697
self.dbus_iface.folders.emit_folder_create_error(path, error)
699
def handle_VM_SHARE_SUBSCRIBED(self, share):
700
"""Handle VM_SHARE_SUBSCRIBED event, emit ShareSubscribed signal."""
701
self.dbus_iface.shares.emit_share_subscribed(share)
703
def handle_VM_SHARE_SUBSCRIBE_ERROR(self, share_id, error):
704
"""Handle VM_SHARE_SUBSCRIBE_ERROR, emit ShareSubscribeError signal."""
705
self.dbus_iface.shares.emit_share_subscribe_error(share_id, error)
707
def handle_VM_SHARE_UNSUBSCRIBED(self, share):
708
"""Handle VM_SHARE_UNSUBSCRIBED event, emit ShareUnSubscribed."""
709
self.dbus_iface.shares.emit_share_unsubscribed(share)
711
def handle_VM_SHARE_UNSUBSCRIBE_ERROR(self, share_id, error):
712
"""Handle VM_SHARE_UNSUBSCRIBE_ERROR, emit ShareUnSubscribeError."""
713
self.dbus_iface.shares.emit_share_unsubscribe_error(share_id, error)
727
715
def handle_VM_SHARE_CREATED(self, share_id):
728
716
"""Handle VM_SHARE_CREATED event, emit NewShare event."""
729
717
self.dbus_iface.shares.emit_new_share(share_id)
864
852
return self.dbus_iface.main.get_rootdir()
866
854
@dbus.service.method(DBUS_IFACE_SYNC_NAME,
855
in_signature='', out_signature='s')
856
def get_sharesdir(self):
857
""" Returns the shares dir/mount point. """
858
logger.debug('called get_sharesdir')
859
return self.dbus_iface.main.get_sharesdir()
861
@dbus.service.method(DBUS_IFACE_SYNC_NAME,
862
in_signature='', out_signature='s')
863
def get_sharesdir_link(self):
864
""" Returns the shares dir/mount point. """
865
logger.debug('called get_sharesdir_link')
866
return self.dbus_iface.main.get_sharesdir_link()
868
@dbus.service.method(DBUS_IFACE_SYNC_NAME,
867
869
in_signature='d', out_signature='b',
868
870
async_callbacks=('reply_handler', 'error_handler'))
869
871
def wait_for_nirvana(self, last_event_interval,
899
901
def RootMismatch(self, root_id, new_root_id):
900
902
"""RootMismatch signal, the user connected with a different account."""
903
904
def emit_root_mismatch(self, root_id, new_root_id):
904
905
"""Emit RootMismatch signal."""
1023
1023
class Shares(DBusExposedObject):
1024
""" A dbus interface to interact wiht shares """
1024
"""A dbus interface to interact with shares."""
1026
1026
def __init__(self, bus_name, fs_manager, volume_manager):
1027
""" Creates the instance. """
1027
"""Create the instance."""
1028
1028
self.fs_manager = fs_manager
1029
1029
self.vm = volume_manager
1030
1030
self.path = '/shares'
1034
1034
@dbus.service.method(DBUS_IFACE_SHARES_NAME,
1035
1035
in_signature='', out_signature='aa{ss}')
1036
1036
def get_shares(self):
1037
""" returns a list of dicts, each dict represents a share """
1037
"""Return a list of dicts, each dict represents a share."""
1038
1038
logger.debug('called get_shares')
1040
1040
for share_id, share in self.vm.shares.items():
1048
1048
in_signature='s', out_signature='',
1049
1049
async_callbacks=('reply_handler', 'error_handler'))
1050
1050
def accept_share(self, share_id, reply_handler=None, error_handler=None):
1051
""" Accepts a share, a ShareAnswerOk|Error signal will be fired in the
1052
future as a success/failure indicator.
1053
A ShareAnswerOk|Error signal will be fired in the future as a
1054
success/failure indicator.
1054
1057
logger.debug('accept_share: %r', share_id)
1055
1058
if str(share_id) in self.vm.shares:
1063
1066
in_signature='s', out_signature='',
1064
1067
async_callbacks=('reply_handler', 'error_handler'))
1065
1068
def reject_share(self, share_id, reply_handler=None, error_handler=None):
1066
""" Rejects a share. """
1069
"""Reject a share."""
1067
1070
logger.debug('reject_share: %r', share_id)
1068
1071
if str(share_id) in self.vm.shares:
1069
1072
self.vm.accept_share(str(share_id), False)
1090
1093
# propagate the error
1096
@dbus.service.method(DBUS_IFACE_SHARES_NAME, in_signature='s')
1097
def subscribe(self, share_id):
1098
"""Subscribe to the specified share."""
1099
logger.debug('Shares.subscribe: %r', share_id)
1100
d = self.vm.subscribe_share(str(share_id))
1101
msg = 'subscribe_share for id %r failed with %r'
1102
d.addErrback(lambda f: logger.error(msg, share_id, f))
1104
@dbus.service.method(DBUS_IFACE_SHARES_NAME, in_signature='s')
1105
def unsubscribe(self, share_id):
1106
"""Unsubscribe from the specified share."""
1107
logger.debug('Shares.unsubscribe: %r', share_id)
1108
self.vm.unsubscribe_share(str(share_id))
1093
1110
@dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1094
1111
signature='a{ss}')
1095
1112
def ShareChanged(self, share_dict):
1096
1113
""" A share changed, share_dict contains all the share attributes. """
1099
1115
@dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1100
1116
signature='a{ss}')
1101
1117
def ShareDeleted(self, share_dict):
1102
1118
""" A share was deleted, share_dict contains all available
1103
1119
share attributes. """
1106
1121
@dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1107
1122
signature='a{ss}s')
1108
1123
def ShareDeleteError(self, share_dict, error):
1109
1124
""" A share was deleted, share_dict contains all available
1110
1125
share attributes. """
1113
1127
def emit_share_changed(self, message, share):
1114
1128
""" emits ShareChanged or ShareDeleted signal for the share
1176
1190
signature='a{ss}')
1177
1191
def ShareCreated(self, share_info):
1178
1192
""" The requested share was succesfully created. """
1181
1194
@dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1182
1195
signature='a{ss}s')
1183
1196
def ShareCreateError(self, share_info, error):
1184
1197
""" An error ocurred while creating the share. """
1187
1199
def emit_share_created(self, share_info):
1188
1200
""" emits ShareCreated signal """
1245
1255
logger.debug('emit_new_share: share_id %r.', share_id)
1246
1256
self.NewShare(_get_share_dict(share))
1258
def emit_share_subscribed(self, share):
1259
"""Emit the ShareSubscribed signal"""
1260
share_dict = _get_share_dict(share)
1261
self.ShareSubscribed(share_dict)
1263
@dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}')
1264
def ShareSubscribed(self, share_info):
1265
"""Notify the subscription to a share."""
1266
logger.info('Emitting ShareSubscribed %r.', share_info)
1268
def emit_share_subscribe_error(self, share_id, error):
1269
"""Emit the ShareSubscribeError signal"""
1270
self.ShareSubscribeError({'id': share_id}, str(error))
1272
@dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}s')
1273
def ShareSubscribeError(self, share_info, error):
1274
"""Notify an error while subscribing to a share."""
1275
logger.info('Emitting ShareSubscribeError %r %r.', share_info, error)
1277
def emit_share_unsubscribed(self, share):
1278
"""Emit the ShareUnSubscribed signal"""
1279
share_dict = _get_share_dict(share)
1280
self.ShareUnSubscribed(share_dict)
1282
@dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}')
1283
def ShareUnSubscribed(self, share_info):
1284
"""Notify the unsubscription to a share."""
1285
logger.info('Emitting ShareUnSubscribed %r.', share_info)
1287
def emit_share_unsubscribe_error(self, share_id, error):
1288
"""Emit the ShareUnSubscribeError signal"""
1289
self.ShareUnSubscribeError({'id': share_id}, str(error))
1291
@dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}s')
1292
def ShareUnSubscribeError(self, share_info, error):
1293
"""Notify an error while unsubscribing from a share."""
1294
logger.info('Emitting ShareUnSubscribeError %r %r.', share_info, error)
1249
1297
class Config(DBusExposedObject):
1250
1298
""" The Syncdaemon config/settings dbus interface. """
1403
1451
user_config.save()
1405
1453
@dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1454
in_signature='', out_signature='b')
1455
def share_autosubscribe_enabled(self):
1456
"""Return the share_autosubscribe config value."""
1457
return config.get_user_config().get_share_autosubscribe()
1459
@dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1460
in_signature='', out_signature='')
1461
def enable_share_autosubscribe(self):
1462
"""Enable UDF autosubscribe."""
1463
user_config = config.get_user_config()
1464
user_config.set_share_autosubscribe(True)
1467
@dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1468
in_signature='', out_signature='')
1469
def disable_share_autosubscribe(self):
1470
"""Enable UDF autosubscribe."""
1471
user_config = config.get_user_config()
1472
user_config.set_share_autosubscribe(False)
1475
@dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1406
1476
in_signature='b', out_signature='')
1407
1477
def set_files_sync_enabled(self, enabled):
1408
1478
"""Enable/disable file sync service."""