r6882 - in online-desktop/trunk/pyddm: . ddm
- From: commits mugshot org
- To: online-desktop-list gnome org
- Subject: r6882 - in online-desktop/trunk/pyddm: . ddm
- Date: Thu, 8 Nov 2007 14:50:29 -0600 (CST)
Author: otaylor
Date: 2007-11-08 14:50:28 -0600 (Thu, 08 Nov 2007)
New Revision: 6882
Modified:
online-desktop/trunk/pyddm/ddm/AbstractModel.py
online-desktop/trunk/pyddm/ddm/DataModel.py
online-desktop/trunk/pyddm/ddm/TwistedModel.py
online-desktop/trunk/pyddm/test-session.py
online-desktop/trunk/pyddm/test.py
Log:
AbstractModel.py DataModel.py TwistedModel.py: Replace 'connected'
'initialized' 'server-connected' with a single 'ready'. (Same
semantics as in the C API ... it's emitted at the end of
startup initialization and when you need to restart your data
fetching.)
AbstractModel.py: Allow passing either a resource_id or a resource to
query_resource.
DataModel.py: Map boolean resources to True/False, not 0/1 integers
DataModel.py: Async error on no connection, don't raise an exception.
(pulls in pygobject dependency for main loop.)
TwistedModel.py test.py: Allow separately specifying the web and xmpp
servers. This is most useful for dealing with the (unhandled) XMPP
redirect ... so test.py --server=mugshot.org --xmpp-server=bn.mugshot.org
test.py test-session.py: Adapt to changes
Modified: online-desktop/trunk/pyddm/ddm/AbstractModel.py
===================================================================
--- online-desktop/trunk/pyddm/ddm/AbstractModel.py 2007-11-08 20:39:56 UTC (rev 6881)
+++ online-desktop/trunk/pyddm/ddm/AbstractModel.py 2007-11-08 20:50:28 UTC (rev 6882)
@@ -12,64 +12,39 @@
"""
def __init__(self):
- self.__initialized_handlers = []
- self.__connected_handlers = []
- self.__server_connected_handlers = []
- self.__disconnected_handlers = []
+ self.__ready_handlers = []
self.__added_handlers = []
self.__removed_handlers = []
self.__resources = {}
- self.initialized = False
- # self_id that is not None means that the model is connected
- self.self_id = None
- # connected is True only when we can talk to the server/ the network is present
- self.connected = False
- self.__handled_model_connected = False
- self.__handled_server_connected = False
+ self.ready = False
+ self.global_resource = None
+ self.self_resource = None
- def add_initialized_handler(self, handler):
- """Add a handler that will be called when we initialize the model and find out if we can get connected to the server"""
- self.__initialized_handlers.append(handler)
+ def add_ready_handler(self, handler):
+ """Add a handler that will be called a) when we become ready b) on reconnection"""
+ self.__ready_handlers.append(handler)
- def remove_initialized_handler(self, handler):
- """Remove a handler added with add_initialized_handler"""
- self.__initialized_handlers.remove(handler)
+ def remove_ready_handler(self, handler):
+ """Remove a handler added with add_ready_handler"""
+ self.__ready_handlers.remove(handler)
- def add_connected_handler(self, handler):
- """Add a handler that will be called when we become connected to the model"""
- self.__connected_handlers.append(handler)
-
- def remove_connected_handler(self, handler):
- """Remove a handler added with add_connected_handler"""
- self.__connected_handlers.remove(handler)
-
- def add_server_connected_handler(self, handler):
- """Add a handler that will be called when we become connected to the server"""
- self.__server_connected_handlers.append(handler)
-
- def remove_server_connected_handler(self, handler):
- """Remove a handler added with add_connected_handler"""
- self.__server_connected_handlers.remove(handler)
-
- def add_disconnected_handler(self, handler):
- """Add a handler that will be called when we become disconnected from the server"""
- self.__disconnected_handlers.append(handler)
-
- def remove_disconnected_handler(self, handler):
- """Remove a handler added with add_disconnected_handler"""
- self.__disconnected_handlers.remove(handler)
-
def add_added_handler(self, handler):
- """Add a handler that will be called when a resource is added"""
+ """Add a handler that will be called when a resource is added.
+
+ This should never be used by a normal appplication, it's for ddm-viewer.
+ """
self.__added_handlers.append(handler)
def remove_added_handler(self, handler):
- """Remove a handler added with add_added_handler"""
+ """Remove a handler added with add_added_handler """
self.__added_handlers.remove(handler)
## of course, currently we never remove resources...
def add_removed_handler(self, handler):
- """Add a handler that will be called when a resource is removed"""
+ """Add a handler that will be called when a resource is removed
+
+ This should never be used by a normal appplication, it's for ddm-viewer.
+ """
self.__removed_handlers.append(handler)
def remove_removed_handler(self, handler):
@@ -97,11 +72,11 @@
"""
raise NotImplementedException()
- def query_resource(self, resource_id, fetch):
+ def query_resource(self, resource, fetch):
"""Create a query object for the standard system method 'getResource'.
Arguments:
- method -- the ID of the resource to retrieve
+ resource -- a resource object or resource ID
fetch -- the fetch string to use for retrieving data. (default '+')
The query will return the resource object if found, otherwise
@@ -109,6 +84,11 @@
until you call execute() on it.
"""
+
+ if isinstance(resource, Resource):
+ resource_id = resource.resource_id
+ else:
+ resource_id = resource
return self.query(("http://mugshot.org/p/system", "getResource"),
fetch,
@@ -130,6 +110,12 @@
raise NotImplementedException()
+ def _reset(self):
+ self.__resources = {}
+ self.global_resource = self._ensure_resource("online-desktop:/o/global", "online-desktop:/p/o/global")
+ self.self_resource = None
+ self.global_resource.connect(self.__on_self_changed, "self")
+
def _get_resource(self, resource_id):
return self.__resources[resource_id]
@@ -144,43 +130,10 @@
return resource
- def _on_initialized(self):
- for handler in self.__initialized_handlers:
+ def _on_ready(self):
+ self.ready = True
+ for handler in self.__ready_handlers:
handler()
- self.initialized = True
- def _on_connected(self):
- if not self.__handled_model_connected:
-
- # On reconnection, all previous state is irrelevant
- self.__resources = {}
-
- for handler in self.__connected_handlers:
- handler()
-
- self.__handled_model_connected = True
-
- if self.connected:
- self._on_server_connected()
-
- def _on_server_connected(self):
- if self.__handled_server_connected:
- return
-
- for handler in self.__server_connected_handlers:
- handler()
-
- self.__handled_server_connected = True
-
- def _on_disconnected(self):
- if not self.__handled_model_connected:
- return
-
- for handler in self.__disconnected_handlers:
- handler()
-
- self.__handled_model_connected = False
- self.__handled_server_connected = False
-
- def _set_self_id(self, self_id):
- self.self_id = self_id
+ def __on_self_changed(self, global_resource):
+ self.self_resource = global_resource.self;
Modified: online-desktop/trunk/pyddm/ddm/DataModel.py
===================================================================
--- online-desktop/trunk/pyddm/ddm/DataModel.py 2007-11-08 20:39:56 UTC (rev 6881)
+++ online-desktop/trunk/pyddm/ddm/DataModel.py 2007-11-08 20:50:28 UTC (rev 6882)
@@ -8,6 +8,9 @@
from ddm.NotificationSet import *
from ddm.Resource import *
+# For idle handling
+import gobject
+
_logger = logging.getLogger('mugshot.DataModel')
def _escape_byte(m):
@@ -54,89 +57,89 @@
def __real_init(self, server_name):
AbstractModel.__init__(self)
- self.__web_base_url = None
-
self.server_name = server_name # server_name can be None for "whatever engine is running"
bus = dbus.SessionBus()
bus_proxy = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
bus_proxy.connect_to_signal("NameOwnerChanged",
- self.__update_proxy,
+ self.__on_name_owner_changed,
arg0=_make_bus_name(server_name))
+ self._proxy = None
self.__update_proxy()
self.callback = _DBusCallback(self, bus)
+ def __on_name_owner_changed(self, name, old_owner, new_owner):
+ self._proxy = None
+ if new_owner != '':
+ self.__update_proxy()
+ else:
+ self.__go_offline()
+
def __update_proxy(self, *args):
- self._on_disconnected()
-
bus = dbus.SessionBus()
targetname = _make_bus_name(self.server_name)
try:
_logger.debug("Looking for engine %s", targetname)
self._proxy = bus.get_object(targetname, '/org/freedesktop/od/data_model')
except dbus.DBusException:
+ # Probably means the engine couldn't be activated
_logger.debug("Failed to get proxy for %s", targetname, exc_info=True)
+ self.__go_offline()
return
- _logger.debug("Found model, querying status")
- # Order matters ... we want the self_id to be there before we call on_connect
- self._proxy.Get('org.freedesktop.od.Model', 'SelfId', reply_handler=self.__get_self_id_reply, error_handler=self.__on_dbus_error)
+ _logger.debug("Found new model, querying ready state")
- self._proxy.Get('org.freedesktop.od.Model', 'WebBaseUrl', reply_handler=self.__get_web_base_url_reply, error_handler=self.__on_dbus_error)
-
- self._proxy.connect_to_signal("ConnectedChanged", self.__on_connected_changed, dbus_interface='org.freedesktop.od.Model')
- self._proxy.Get('org.freedesktop.od.Model', 'Connected', reply_handler=self.__get_connected_reply, error_handler=self.__on_dbus_error)
+ self._proxy.connect_to_signal("Ready", self.__on_ready, dbus_interface='org.freedesktop.od.Model')
+ self._proxy.Get('org.freedesktop.od.Model', 'Ready', reply_handler=self.__get_ready_reply, error_handler=self.__get_ready_error)
- def __on_dbus_error(self, err):
- _logger.error("Caught D-BUS error: %s", err)
+ def __get_ready_reply(self, ready):
+ _logger.debug("Got reply for ready state, Ready=%s", ready)
+ if ready:
+ self.__on_ready()
- def __on_connected_changed(self, connected, self_id):
- _logger.debug("Connected status changed: %s", connected)
- self.connected = connected
- if connected:
- self.__on_connected(self_id)
- else:
- self.__on_disconnected()
+ def __get_ready_error(self, err):
+ # Probably means that the engine died
+ _logger.error("Caught D-BUS error asking for Ready: %s", err)
+ self.__go_offline()
- def __on_connected(self, self_id):
- if self_id == '':
- self._set_self_id(None)
- else:
- self._set_self_id(self_id)
- self._on_connected()
+ def __on_ready(self):
+ self._reset()
- def __on_disconnected(self):
- self._on_disconnected()
+ _logger.debug("Doing initial query")
- def __get_web_base_url_reply(self, baseurl):
- _logger.debug("Got base url %s", baseurl)
- if baseurl == '':
- baseurl = None
- self.__web_base_url = baseurl
+ query = self.query_resource("online-desktop:/o/global", "self +;webBaseUrl;online")
+ query.add_handler(self.__on_initial_query_success)
+ query.add_error_handler(self.__on_initial_query_error)
+ query.execute()
+
+ def __on_initial_query_success(self, resource):
+ self._on_ready()
+
+ def __on_initial_query_error(self, code, message):
+ # Probably means that the engine died
+ _logger.error("Got an error response to the initial query: %s", message)
+ self.__go_offline()
- def __get_self_id_reply(self, self_id):
- _logger.debug("Got self id %s", self_id)
- if self_id == '':
- self._set_self_id(None)
- else:
- self._set_self_id(self_id)
+ def __go_offline(self):
+ # Common handling if an error occurs in the initialization path or we lose the
+ # connection to the server; we change the state to be offline and if we were
+ # still in the "not yet ready" state, signal the end of initialization
+ #
+ if self.global_resource == None:
+ self._reset()
+ notifications = NotificationSet(self)
+ self.global_resource._update_property(("online-desktop:/p/o/global", "online"),
+ UPDATE_REPLACE, CARDINALITY_1, False,
+ notifications)
+ notifications.send()
- def __get_connected_reply(self, connected):
- self.connected = connected
+ if not self.ready:
+ self._on_ready()
- self._on_initialized()
- # this is a hack -- we pretend that we are connected so that we can get
- # the information that has been cached by the mugshot client
- if self.self_id != None:
- self._on_connected()
-
def _get_proxy(self):
return self._proxy
- def get_web_base_url(self):
- return self.__web_base_url
-
def query(self, method, fetch=None, single_result=False, **kwargs):
_logger.debug("doing query: %s fetch=%s, single_result=%s", method, fetch, single_result)
return _DBusQuery(self, method, fetch, single_result, kwargs)
@@ -164,6 +167,8 @@
raise Exception("Resource-valued element points to a resource we don't know about: " + str(value))
elif type_byte == ord('s') or type_byte == ord('u'):
value = value.__str__()
+ elif type_byte == ord('b'):
+ value = bool(value)
if cardinality_byte == ord('.'):
cardinality = CARDINALITY_1
@@ -240,11 +245,14 @@
_logger.error('Caught error: %s', err.message)
self._on_error(ERROR_FAILED, err.message)
+ def __async_no_connection_error(self):
+ self._on_error(ERROR_NO_CONNECTION, "No connection to engine to data model engine")
+ return False
+
def execute(self):
- # FIXME: Would it be better to call the __on_error? Doing that sync could cause problems.
- # If we decide to continue raising an exception here, we should use a subclass
- if not self.__model.connected and self.__model.self_id == None:
- raise Exception("Not connected")
+ if self.__model._proxy == None:
+ self._on_error(ERROR_NO_CONNECTION, "No connection to data model engine")
+ return
method_uri = self.__method[0] + "#" + self.__method[1]
#_logger.debug("executing query method: '%s' fetch: '%s' params: '%s'", method_uri, self.__fetch, self._params)
@@ -270,11 +278,14 @@
_logger.error('Caught error: %s', err.message)
self._on_error(ERROR_FAILED, err.message)
+ def __async_no_connection_error(self):
+ self._on_error(ERROR_NO_CONNECTION, "No connection to engine")
+ return False
+
def execute(self):
- # FIXME: Would it be better to call the __on_error? Doing that sync could cause problems.
- # If we decide to continue raising an exception here, we should use a subclass
- if not self.__model.connected and self.__model.self_id == None:
- raise Exception("Not connected")
+ if self.__model._proxy == None:
+ gobject.idle_add(self.__async_no_connection_error)
+ return
method_uri = self.__method[0] + "#" + self.__method[1]
_logger.debug("executing update method: '%s' params: '%s'", method_uri, self._params)
Modified: online-desktop/trunk/pyddm/ddm/TwistedModel.py
===================================================================
--- online-desktop/trunk/pyddm/ddm/TwistedModel.py 2007-11-08 20:39:56 UTC (rev 6881)
+++ online-desktop/trunk/pyddm/ddm/TwistedModel.py 2007-11-08 20:50:28 UTC (rev 6882)
@@ -23,37 +23,66 @@
"""
- def __init__(self, server="mugshot.org:5222", username=None, password=None):
+ def __init__(self, web_server="mugshot.org", xmpp_server=None, username=None, password=None):
"""Create a new TwistedModel instance that connects to the specified server.
Arguments:
- server: Server to connect to. The port may be specified by appending it after
- a colon. If the port is not specified, a default value will be used (default='mugshot.org')
+ web_server: Web server to connect to. The port may be specified by appending it after
+ a colon. If the port is not specified, a default value will be used. (default='mugshot.org')
+ xmpp_server: XMPP server to connect to. The port may be specified by appending it after
+ a colon. If the port is not specified, a default value will be used.
+ If no xmpp server is specified, the web server hostname will be used.
username: GUID of the user to connect as (if not specified, found from cookies.txt)
password: Password of the user (if not specified, found from cookies.txt)
"""
AbstractModel.__init__(self)
- colon = server.find(":")
+ colon = web_server.find(":")
if (colon >= 0):
- self.server = server[:colon]
- self.port = int(server[colon + 1:])
+ self.web_server = web_server[:colon]
+ self.web_port = int(web_server[colon + 1:])
else:
- self.server = server
- if server == "mugshot.org":
- self.port = 5222
+ self.web_server = web_server
+ if web_server == "mugshot.org":
+ self.web_port = 80
+ elif web_server == "dogfood.mugshot.org":
+ self.web_port = 9080
else:
- self.port = 21020
+ self.web_port = 8080
+ if self.web_port == 80:
+ web_port = ""
+ else:
+ web_port = ":" + `self.web_port`
+
+ self.web_base_url = "http://%s%s" % (self.web_server, web_port)
+
+ self.xmpp_port = None
+ if xmpp_server != None:
+ colon = xmpp_server.find(":")
+ if (colon >= 0):
+ self.xmpp_server = xmpp_server[:colon]
+ self.xmpp_port = int(xmpp_server[colon + 1:])
+ else:
+ self.xmpp_server =xmpp_server
+ else:
+ self.xmpp_server = self.web_server
+
+ if self.xmpp_port == None:
+ if self.web_port == 80:
+ self.xmpp_port = 5122
+ else:
+ self.xmpp_port = 21020
+
if username == None and password == None:
- username, password = _parse_cookies(self.server)
+ username, password = _parse_cookies(self.web_server)
elif username != None or password != None:
raise MustLoginException("Either both user and password must be specified or neither")
# FIXME: Use a legal resource
self.username = username
- user_jid = jid.JID("%s %s/mugshot-python" % (_guid_to_jabber_id(username), self.server))
+ user_jid = jid.JID("%s %s/mugshot-python" % (_guid_to_jabber_id(username), self.web_server))
self.__factory = client.basicClientFactory(user_jid, password)
self._xmlstream = None
@@ -65,12 +94,12 @@
presumbaly want to start the main loop itself.
"""
-
+
global reactor
self.__factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.__on_auth_succeeded)
self.__factory.addBootstrap(client.BasicAuthenticator.AUTH_FAILED_EVENT, self.__on_auth_failed)
- reactor.connectTCP(self.server, self.port, self.__factory)
+ reactor.connectTCP(self.xmpp_server, self.xmpp_port, self.__factory)
reactor.run()
@@ -88,16 +117,34 @@
xmlstream.addObserver('/message', self.__on_message)
self._xmlstream = xmlstream
-
- self.connected = True
- self._on_initialized()
- self._on_connected()
+ self._reset()
+
+ notifications = NotificationSet(self)
+ self.global_resource._update_property(("online-desktop:/p/o/global", "online"),
+ UPDATE_REPLACE, CARDINALITY_1, True,
+ notifications)
+
+ self.global_resource._update_property(("online-desktop:/p/o/global", "webBaseUrl"),
+ UPDATE_REPLACE, CARDINALITY_1, self.web_base_url,
+ notifications)
+
+ self_resource_id = self.web_base_url + "/o/user/" + self.username
+ self_resource = self._ensure_resource(self_resource_id,
+ "http://mugshot.org/p/o/user")
+
+ self.global_resource._update_property(("online-desktop:/p/o/global", "self"),
+ UPDATE_REPLACE, CARDINALITY_01, self_resource,
+ notifications)
+
+ notifications.send()
+
+ self._on_ready()
+
def __on_auth_failed(self, xmlstream):
global reactor
print 'Auth failed!'
- self.connected = False
- self._on_initialized()
+
reactor.stop()
def __get_resource_id(self, resource_element):
Modified: online-desktop/trunk/pyddm/test-session.py
===================================================================
--- online-desktop/trunk/pyddm/test-session.py 2007-11-08 20:39:56 UTC (rev 6881)
+++ online-desktop/trunk/pyddm/test-session.py 2007-11-08 20:50:28 UTC (rev 6882)
@@ -45,22 +45,26 @@
def on_global_query_failure(code, message):
print message
-def on_connect():
- print "Connected"
+def online_changed(resource):
+ print "Online: ", resource.online
+
+def on_ready():
+ print "Ready"
- query = model.query_resource(model.self_id, "+;contacts +;contacters +;lovedAccounts +;email;aim")
- query.add_handler(on_self_query_success)
- query.add_error_handler(on_self_query_failure)
- query.execute()
+ if model.self_resource != None:
+ query = model.query_resource(model.self_resource, "+;contacts +;contacters +;lovedAccounts +;email;aim")
+ query.add_handler(on_self_query_success)
+ query.add_error_handler(on_self_query_failure)
+ query.execute()
- query = model.query_resource("online-desktop:/o/global", "onlineBuddies +")
+ query = model.query_resource(model.global_resource, "onlineBuddies +")
query.add_handler(on_global_query_success)
query.add_error_handler(on_global_query_failure)
query.execute()
+
+ model.global_resource.connect(online_changed, "online")
+ online_changed(model.global_resource)
-def on_disconnect():
- print "Disconnected"
-
parser = OptionParser()
parser.add_option("-s", "--server", default="localinstance.mugshot.org:8080", help="Mugshot server to connect to (default localinstance.mugshot.org:8080)")
(options, args) = parser.parse_args()
@@ -69,10 +73,9 @@
sys.exit(1)
model = DataModel(options.server)
-model.add_connected_handler(on_connect)
-model.add_disconnected_handler(on_disconnect)
-if model.connected:
- on_connect()
+model.add_ready_handler(on_ready)
+if model.ready:
+ on_ready()
loop = gobject.MainLoop()
loop.run()
Modified: online-desktop/trunk/pyddm/test.py
===================================================================
--- online-desktop/trunk/pyddm/test.py 2007-11-08 20:39:56 UTC (rev 6881)
+++ online-desktop/trunk/pyddm/test.py 2007-11-08 20:50:28 UTC (rev 6882)
@@ -22,18 +22,25 @@
def on_query_failure(code, message):
print message
-def on_connect():
- print "Connected"
+def online_changed(resource):
+ print "Online: ", resource.online
+
+def on_ready():
+ print "Ready"
# FIXME: having to include the port means won't work on non-debug servers
- query = model.query_resource("http://%s:8080/o/user/%s" % (model.server, model.username),
+ query = model.query_resource(model.self_resource,
"+;contacts +;contacters +;lovedAccounts +")
query.add_handler(on_query_success)
query.add_error_handler(on_query_failure)
query.execute()
+ model.global_resource.connect(online_changed, "online")
+ online_changed(model.global_resource)
+
parser = OptionParser()
-parser.add_option("-s", "--server", default="localinstance.mugshot.org:21020", help="Mugshot server to connect to (default localinstance.mugshot.org:21020)")
+parser.add_option("-s", "--server", default="localinstance.mugshot.org:21020", help="Mugshot web server to connect to (default localinstance.mugshot.org)")
+parser.add_option("-x", "--xmpp-server", help="XMPP server to connect to (if not specified, derived from --server)")
parser.add_option("-u", "--user", help="User to connect to the server as (default from Firefox cookies)")
parser.add_option("-p", "--password", help="Password to use to connect to the server (default from Firefox cookies)")
(options, args) = parser.parse_args()
@@ -41,7 +48,7 @@
parser.print_usage()
sys.exit(1)
-model = TwistedModel(options.server, options.user, options.password)
+model = TwistedModel(web_server=options.server, xmpp_server=options.xmpp_server, username=options.user, password=options.password)
-model.add_connected_handler(on_connect)
+model.add_ready_handler(on_ready)
model.run()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]