diff -r f176f9ad5e58 server/python/check-raindrop.py --- a/server/python/check-raindrop.py Thu Oct 22 16:35:34 2009 -0700 +++ b/server/python/check-raindrop.py Fri Oct 23 03:23:16 2009 +0100 @@ -76,7 +76,7 @@ deps = [ ('twisted', '>=8.2', True), ('pyOpenSSL', '', True), - ('paisley', '', True), + #('paisley', '', True), ('feedparser', '>=4.1', False), ('Skype4Py', '', False), # ack - no 0.6 actually exists and 0.5 is missing a key feature we need. @@ -204,7 +204,11 @@ try: info = json.load(urllib2.urlopen(url)) except IOError, why: - fail("Can't connect to couchdb: %s", why) + # if desktopcouch is available, use that + if "desktopcouch" in config.couches: + info = {"couchdb": "desktopcouch", "version": "0.10"} + else: + fail("Can't connect to couchdb: %s", why) note("couchdb says '%s'.", info['couchdb']) ver = info['version'] diff -r f176f9ad5e58 server/python/raindrop/config.py --- a/server/python/raindrop/config.py Thu Oct 22 16:35:34 2009 -0700 +++ b/server/python/raindrop/config.py Fri Oct 23 03:23:16 2009 +0100 @@ -21,7 +21,7 @@ # Contributor(s): # -import ConfigParser, logging, os, os.path +import ConfigParser, logging, os, os.path, wetpaisley __all__ = ['get_config'] @@ -29,10 +29,24 @@ COUCH_DEFAULTS = {'host': '127.0.0.1', 'port': 5984, 'name': 'raindrop'} def __init__(self, filename=None): self.parser = ConfigParser.SafeConfigParser() + self.couches = {'local': self.COUCH_DEFAULTS.copy()} self.accounts = {} + try: + import desktopcouch, wetpaisley_desktopcouch + except ImportError: + # No desktopcouch, oh well, never mind + pass + else: + port = desktopcouch.find_port() + # haha! you have desktopcouch, so we take a unilateral decision that + # you want to use it. + self.couches["local"] = {"host": "localhost", "port": port, + "name": "raindrop", + "couchdb_server_class": wetpaisley_desktopcouch.CouchDB} + # XXX - this seems wrong: most of the time the 'config' - particularly the # list of accounts etc - will come from the DB. The config file should only # be used during bootstrapping. diff -r f176f9ad5e58 server/python/raindrop/model.py --- a/server/python/raindrop/model.py Thu Oct 22 16:35:34 2009 -0700 +++ b/server/python/raindrop/model.py Fri Oct 23 03:23:16 2009 +0100 @@ -90,7 +90,8 @@ except KeyError: pass logger.info("Connecting to couchdb at %s", dbinfo) - db = CouchDB(dbinfo['host'], dbinfo['port'], dbname, + couchdb_server_class = dbinfo.get("couchdb_server_class", CouchDB) + db = couchdb_server_class(dbinfo['host'], dbinfo['port'], dbname, dbinfo.get('username'), dbinfo.get('password')) DBs[key] = db return db diff -r f176f9ad5e58 server/python/raindrop/wetpaisley_desktopcouch.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/python/raindrop/wetpaisley_desktopcouch.py Fri Oct 23 03:23:16 2009 +0100 @@ -0,0 +1,75 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Raindrop. +# +# The Initial Developer of the Original Code is +# Mozilla Messaging, Inc.. +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): Stuart Langridge +# + +# paisley with raindrops on it and desktopcouch frosting + +import wetpaisley, desktopcouch, urlparse, cgi, logging, httplib2 +from oauth import oauth +from twisted.internet import reactor +from twisted.web.client import HTTPClientFactory + +logger = logging.getLogger('model') + +class CouchDB(wetpaisley.CouchDB): + _has_adbs = None # does this couch support the old _all_docs_by_seq api? + def __init__(self, host, port=5984, dbName=None, username=None, password=None): + port = desktopcouch.find_port() + wetpaisley.CouchDB.__init__(self, host, port, dbName) + + def _getPage(self, uri, **kwargs): + """ + C{getPage}-like with OAuth. + """ + url = self.url_template % (uri,) + kwargs["headers"] = headers = {"Accept": "application/json"} + # Need to use OAuth to talk to desktopcouch + # Look up our oauth token + oauth_tokens = desktopcouch.local_files.get_oauth_tokens() + (consumer_key, consumer_secret, token, token_secret) = ( + oauth_tokens["consumer_key"], oauth_tokens["consumer_secret"], + oauth_tokens["token"], oauth_tokens["token_secret"]) + # sign this request with them + consumer = oauth.OAuthConsumer(consumer_key, consumer_secret) + access_token = oauth.OAuthToken(token, token_secret) + # We know desktopcouch is http, not https + full_http_url = "http://%s:%s%s" % (self.host, self.port, uri) + schema, netloc, path, params, query, fragment = urlparse.urlparse(full_http_url) + querystr_as_dict = dict(cgi.parse_qsl(query)) + req = oauth.OAuthRequest.from_consumer_and_token( + consumer, + access_token, + http_method = kwargs["method"], + http_url = full_http_url, + parameters = querystr_as_dict + ) + req.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), + consumer, access_token) + # and add the signature to the headers + headers.update(httplib2._normalize_headers(req.to_header())) + # Host header seems to require port number for Couch to accept auth + headers["Host"] = "%s:%s" % (self.host, self.port) + + factory = HTTPClientFactory(url, **kwargs) + reactor.connectTCP(self.host, self.port, factory) + return factory.deferred +