From c869ea9e4b0f0d2a35174e727b563bfc9160b81b Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Mon, 23 Jul 2012 09:46:37 +0000 Subject: Switch to DBus SN interface --- diff --git a/plugin/__init__.py b/plugin/__init__.py index 5fe5cf7..61ede76 100644 --- a/plugin/__init__.py +++ b/plugin/__init__.py @@ -13,14 +13,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import os +import json +import logging import subprocess from gettext import gettext as _ +import dbus import gobject from sugar.graphics.alert import NotifyAlert, ErrorAlert -from sugar_network import sugar, GlibClient, api_url, server_mode +from sugar_network import sugar, api_url, server_mode from active_toolkit.options import Option @@ -42,6 +44,7 @@ _ALERT_SEVERITIES = { None: (NotifyAlert, _('Sugar Network')), } +_logger = logging.getLogger('plugins.sn') _bundleregistry = None _launcher = None _client = None @@ -62,10 +65,6 @@ def init(): api_url.value = SN_MASER_URL Option.save() - if not os.fork(): - args = ['sugar-network-service', '--webui', '--delayed-start', 'start'] - os.execvp(args[0], args) - import jarabe.model.bundleregistry from .bundleregistry import BundleRegistry @@ -81,15 +80,11 @@ def init(): def enable(): - global _launcher, _client + global _launcher if not sugar_network.value: return - _client = GlibClient() - _client.connect('alert', - lambda sender, severity, message: add_alert(severity, msg=message)) - _bundleregistry.populate() from jarabe.journal import misc @@ -102,7 +97,7 @@ def enable(): shell = get_model() def delayed_start(): - _client.publish('delayed-start') + get_client().Publish({'event': 'delayed-start'}) get_browser() def activity_added_cb(model, activity): @@ -122,6 +117,11 @@ def get_registry(): def get_client(): + global _client + + if _client is None: + _client = _Client() + return _client @@ -171,3 +171,40 @@ def _get_bundle_path(self): for env in f.read().split('\0'): if env.startswith('SUGAR_BUNDLE_PATH='): return env.split('=', 1)[-1] + + +class _Client(object): + + def __init__(self): + self._event_callbacks = [] + self._client = dbus.Interface( + dbus.SessionBus().get_object( + 'org.sugarlabs.Network', + '/org/sugarlabs/Network'), + 'org.sugarlabs.Network') + self._client.connect_to_signal('Event', self.__Event_cb) + + def connect_to_signal(self, signal, callback): + if signal == 'Event': + self._event_callbacks.append(callback) + else: + return self._client.connect_to_signal(signal, callback) + + def __getattr__(self, name): + return getattr(self._client, name) + + def __Event_cb(self, event): + event = json.loads(event) + + for callback in self._event_callbacks: + try: + callback(event) + except Exception: + _logger.exception('%r callback failed on %r SN event', + callback, event) + + event_type = event.get('event') + if event.get('event') == 'alert': + add_alert(event['severity'], msg=event['message']) + elif event_type == 'sync_complete': + add_alert('info', msg=_('Synchronization completed')) diff --git a/plugin/browser.py b/plugin/browser.py index 68a406c..58a987d 100644 --- a/plugin/browser.py +++ b/plugin/browser.py @@ -65,7 +65,7 @@ class Browser(Window): self.show_all() self._webkit.connect('notify::load-status', self.__load_status_cb) - get_client().connect('connect', self.__connection_cb) + get_client().connect_to_signal('Event', self.__Event_cb) gobject.timeout_add_seconds(_RETRY_TIMEOUT, self._open) @@ -105,7 +105,7 @@ class Browser(Window): wm.set_activity_id(window.window, create_activity_id()) self.disconnect_by_func(self.__realize_cb) - def __connection_cb(self, sender, mountpoint, connected): + def __Event_cb(self, event): self._open() diff --git a/plugin/bundleregistry.py b/plugin/bundleregistry.py index d4ca5f8..3f9bb36 100644 --- a/plugin/bundleregistry.py +++ b/plugin/bundleregistry.py @@ -15,14 +15,13 @@ import os import logging -from os.path import lexists, basename +from os.path import lexists from gettext import gettext as _ import gtk import gobject -import sugar_network -from sugar.util import LRU +from sugar_network import checkins, sugar from sugar.bundle.activitybundle import ActivityBundle from jarabe.plugins.sn import SN_BROWSER_NAME, get_client @@ -30,7 +29,6 @@ from jarabe.plugins.sn import SN_BROWSER_NAME, get_client _logger = logging.getLogger('plugins.sn.bundleregistry') _stub_icon_path = None -_online_cache = LRU(100) class BundleRegistry(gobject.GObject): @@ -51,15 +49,21 @@ class BundleRegistry(gobject.GObject): def populate(self): client = get_client() + client.connect_to_signal('Event', self.__Event_cb) - for props in client.find('~', 'context', 0, 50, - reply=['guid', 'keep', 'keep_impl', 'position']): - if props['keep_impl']: + def reply_handler(entries, total): + for props in entries: bundle = self._add_bundle(props['guid'], props) - self.emit('bundle-added', bundle) + if bundle is not None: + self.emit('bundle-added', bundle) + + def error_handler(error): + _logger.warning('Cannot call Find(): %s', error) - client.connect('keep', self.__keep_cb) - client.connect('keep_impl', self.__keep_impl_cb) + client.Find('~', 'context', + ['guid', 'keep', 'keep_impl', 'position'], + {'keep_impl': 2, 'limit': 1024}, + reply_handler=reply_handler, error_handler=error_handler) def __iter__(self): return self._bundles.itervalues() @@ -76,22 +80,17 @@ class BundleRegistry(gobject.GObject): if context_guid in self._bundles: return self._bundles[context_guid] - if context_guid in _online_cache: - return _online_cache[context_guid] - if mountpoint == '~': return None - try: - props = get_client().get(mountpoint, 'context', context_guid, - reply=['guid', 'keep', 'keep_impl', 'title']) + props = get_client().Get(mountpoint, 'context', context_guid, + ['guid', 'keep', 'keep_impl', 'title']) result = _ContextInfo(mountpoint, props) except Exception: - _logger.warning(_('Cannot fetch activity metadata')) + _logger.warning('Cannot fetch activity metadata for %r on %r', + context_guid, mountpoint) result = None - _online_cache[context_guid] = result - return result def get_activities_for_type(self, mime_type): @@ -112,7 +111,7 @@ class BundleRegistry(gobject.GObject): bundle = self._bundles.get(bundle_id) if bundle is None: return - get_client().update('~', 'context', bundle_id, keep=keep) + get_client().Update('~', 'context', bundle_id, {'keep': keep}) bundle.props['keep'] = keep self.emit('bundle-changed', bundle) @@ -127,7 +126,7 @@ class BundleRegistry(gobject.GObject): if bundle is None: return position = bundle.props['position'] = [int(x), int(y)] - get_client().update('~', 'context', bundle_id, position=position) + get_client().Update('~', 'context', bundle_id, {'position': position}) self.emit('bundle-changed', bundle) def get_default_for_type(self, mime_type): @@ -148,7 +147,7 @@ class BundleRegistry(gobject.GObject): raise NotImplementedError('Not yet supported') def _add_bundle(self, bundle_id, props): - for path in sugar_network.checkins(bundle_id): + for path in checkins(bundle_id): try: bundle = self._bundles[bundle_id] = \ _BundleInfo(ActivityBundle(path), props) @@ -160,28 +159,43 @@ class BundleRegistry(gobject.GObject): else: _logger.info('No bundles for %r', bundle_id) - def __keep_cb(self, sender, bundle_id, keep): + def _set_keep(self, bundle_id, keep): bundle = self._bundles.get(bundle_id) if bundle is None: return bundle.props['keep'] = keep self.emit('bundle-changed', bundle) - def __keep_impl_cb(self, sender, bundle_id, keep_impl): + def _set_keep_impl(self, bundle_id, keep_impl): if keep_impl: - props = get_client().get('~', 'context', bundle_id, - reply=['guid', 'keep', 'keep_impl', 'position']) bundle = self._bundles.get(bundle_id) if bundle is None: + props = get_client().Get('~', 'context', bundle_id, + ['guid', 'keep', 'keep_impl', 'position']) bundle = self._add_bundle(bundle_id, props) - else: - bundle.props.update(props) - self.emit('bundle-added', bundle) + if bundle is not None: + self.emit('bundle-added', bundle) else: if bundle_id in self._bundles: bundle = self._bundles.pop(bundle_id) self.emit('bundle-removed', bundle) + def __Event_cb(self, event): + if 'mountpoint' in event and event['mountpoint'] != '~' or \ + event.get('document') != 'context': + return + event_type = event.get('event') + if event_type in ('create', 'update'): + bundle_id = event['guid'] + props = event['props'] + if props.get('keep_impl') in (0, 2): + self._set_keep_impl(bundle_id, props['keep_impl']) + if 'keep' in props: + self._set_keep(bundle_id, props['keep']) + elif event_type == 'delete': + bundle_id = event['guid'] + self._set_keep_impl(bundle_id, 0) + class _ContextInfo(object): @@ -196,21 +210,22 @@ class _ContextInfo(object): return self.props['guid'] def get_icon(self): - path = None + blob = None try: - path, __ = get_client().get_blob_path('/', 'context', + blob = get_client().GetBlob(self.mountpoint, 'context', self.get_bundle_id(), 'artifact_icon') except Exception, error: _logger.debug('Fail to get icon for %r: %s', self.get_bundle_id(), error) - if not path or os.stat(path).st_size == 0: + if not blob or os.stat(blob['path']).st_size == 0: return _stub_icon() else: - svg_path = path + '.svg' - if not lexists(svg_path): - os.symlink(basename(path), svg_path) - return svg_path + path = sugar.profile_path('data', self.get_bundle_id() + '.svg') + if lexists(path): + os.unlink(path) + os.symlink(blob['path'], path) + return path def get_tags(self): # Doesn't matter with Sweets' features enabled diff --git a/plugin/launcher.py b/plugin/launcher.py index 08bb2f5..ea1ed76 100644 --- a/plugin/launcher.py +++ b/plugin/launcher.py @@ -42,7 +42,7 @@ class Launcher(object): self._launches = {} self._screen = wnck.screen_get_default() self._screen.connect('window-opened', self.__window_opened_cb) - get_client().connect('launch', self.__launch_cb) + get_client().connect_to_signal('Event', self.__Event_cb) def launch(self, bundle, activity_id=None, object_id=None, uri=None, color=None, invited=None, args=None): @@ -141,14 +141,17 @@ class Launcher(object): gtk.gdk.PROP_MODE_REPLACE, 'launcher') wm.set_bundle_id(widget.window, str(bundle_id)) - def __launch_cb(self, sender, mountpoint, bundle_id, command, object_id, - uri, args): - bundle = get_registry().get_bundle(bundle_id, mountpoint) + def __Event_cb(self, event): + if event.get('event') != 'launch': + return + bundle = get_registry().get_bundle( + event['context'], event['mountpoint']) if bundle is None: - add_alert('error', - msg=_('Cannot find %r activity to launch') % bundle_id) + add_alert('error', msg=_('Cannot find %s activity to launch') % \ + event['context']) else: - self.launch(bundle, object_id=object_id, uri=uri, args=args) + self.launch(bundle, object_id=event['object_id'], uri=event['uri'], + args=event['args']) def __progress_cb(self, source, cb_condition, pipe, activity_id): event = pipe.read() -- cgit v0.9.1