2012-02-19 13 views
15

Estoy tratando de crear archivos en una carpeta de Dropbox.com desde una aplicación GAE. He realizado todos los pasos para registrar una aplicación de Dropbox e instalé el SDK de Python desde Dropbox localmente en mi máquina de desarrollo. (ver la API de dropbox.com). Todo funciona perfectamente cuando uso el script de prueba cli_client.py en Dropbox SDK en mi máquina local para acceder a Dropbox - puedo 'poner' archivos etc.Escribiendo archivos en la cuenta de Dropbox desde GAE

Ahora quiero empezar a trabajar en el entorno GAE, para que las cosas se pongan un poco complicado Alguna ayuda sería útil.

Para aquellos familiarizados con el código API de Dropbox, que tenían las siguientes cuestiones: hasta el momento

Número 1

El módulo API de Dropbox rest.py utiliza pkg_resources para obtener el CERT instalados en sitio- paquetes de una instalación de máquina local. que sustituyen

TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt') 

con

TRUSTED_CERT_FILE = file('trusted-certs.crt') 

y se coloca el archivo cert en mi directorio de la aplicación GAE. Quizás esto no es del todo correcto; ver mi código de error de autenticación a continuación.

Edición 2

El módulo API Dropbox session.py utiliza oauth módulo, por lo que cambió el incluyen a AppEngine oauth.

Pero se ha presentado una excepción que GAE's oauth no tiene OAuthConsumer método utilizado por el módulo de Dropbox session.py. Así que descargué Oauth 1.0 y lo agregué a mi aplicación y ahora importé esto en lugar de GAE oauth.

Número 3

módulo SSL GAE no parecen tener la propiedad CERT_REQUIRED.

Ésta es una constante, por lo que cambió

self.cert_reqs = ssl.CERT_REQUIRED 

a

self.cert_reqs = 2 

Esto se utiliza cuando se llama a

ssl.wrap_socket(sock, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs) 

falla la autenticación

Pero todavía no puedo conectar a Dropbox:

Status: 401 
Reason: Unauthorized 
Body: {"error": "Authentication failed"} 
Headers: [('date', 'Sun, 19 Feb 2012 15:11:12 GMT'), ('transfer-encoding', 'chunked'), ('connection', 'keep-alive'), ('content-type', 'application/json'), ('server', 'dbws')] 
+0

espero que alguien responde a esta. Mientras tanto, aunque no estoy seguro de qué es pkg_resources.resource_filename(), creo que devuelve un nombre de archivo, no un archivo abierto, mientras que file() abre el archivo nombrado y devuelve un objeto de secuencia (archivo abierto). Es posible que desee probar 'TRUSTED_CERT_FILE = 'trusted-certs.crt'' en su lugar. –

+0

Gracias Guido - intentará que – erickCo

+0

Guido, está en lo cierto, el tipo devuelto por 'pkg_resources.resource_filename()' es 'str'. El valor es la ruta completa al archivo certs. Así que hice el cambio como sugieres. Por desgracia, sigue siendo el mismo error. – erickCo

Respuesta

7

Aquí está mi versión parcheada de Dropbox SDK Python 1.4 que funciona bien para mí con Python 2.7 GAE: dropbox_python_sdk_gae_patched.7z.base64. No se necesitan bibliotecas adicionales de terceros, solo las proporcionadas por el entorno de GAE.

Solo se carga la carga de archivos (put_file). Aquí están los pasos de configuración:

  1. Desempaquete el archivo en la carpeta raíz de la aplicación GAE (si la aplicación principal se encuentra en la carpeta raíz). Puede decodificar BASE64 usando Base64 Encoder/Decoder: base64.exe -d dropbox_python_sdk_gae_patched.7z.base64 dropbox_python_sdk_gae_patched.7z.
  2. Configuración APP_KEY, APP_SECRET, ACCESS_TYPE, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET. Los primeros tres se configuran en el momento de creación de la aplicación dropbox. Los dos últimos se obtienen al otorgar acceso a la aplicación a una cuenta específica de Dropbox, puede obtenerlos a través de cli_client.py (desde DB Python SDK) desde el archivo token_store.txt.
  3. uso en el código como el siguiente:

    import dropbox 
    # ... 
    def DropboxUpload(path, data): 
        sess = dropbox.session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE) 
        sess.set_token(ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET) 
        cli = dropbox.client.DropboxClient(sess) 
        data_file = StringIO.StringIO(data) 
        return cli.put_file(path, data_file) 
    # ... 
    import json 
    class DropboxUploadHandlerExample(webapp2.RequestHandler): 
        def get(self): 
         url = "http://www.google.com/" 
         result = urlfetch.fetch(url) 
         self.response.headers['Content-Type'] = 'application/json' 
         self.response.out.write(json.dumps(DropboxUpload('/fetch_result.dat', result.content))) 
    
+1

¿Se puede actualizar a la nueva Dropbox SDK, la que tiene DropboxOAuth2FlowNoRedirect? –

3

he subido con éxito de Google App Engine a selección con mi propia versión parcheada del SDK de Dropbox: https://github.com/cklein/dropbox-client-python

El uso de urllib2 fue reemplazado por huTools.http: https://github.com/hudora/huTools/

Este es el código que se llama en un controlador de solicitudes:

db_client = dropbox.get_dropbox_client(consumer_key='', consumer_secret='', access_token_key='', access_token_secret='') 
    fileobj = StringIO.StringIO(data) 
    path = '/some/path/filename' 
    resp = db_client.put_file(path, fileobj) 
    fileobj.close() 
1

he parcheado la versión del SDK de Dropbox Python 2.2 para trabajar en Google App Engine. Por favor, encontrar el código relevante aquí:

https://github.com/duncanhawthorne/gae-dropbox-python

El parche para el código correspondiente (copiado de github) para rest.py está aquí:

import io 
import pkg_resources 
-import socket 
+#import socket 
import ssl 
import sys 
import urllib 
+import urllib2 

+def mock_urlopen(method,url,body,headers,preload_content): 
+ request = urllib2.Request(url, body, headers=headers) 
+ r = urllib2.urlopen(request) 
+ return r   
+  
try: 
    import json 
except ImportError: 
@@ -23,7 +29,10 @@ 

SDK_VERSION = "2.2.0" 

-TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt') 
+try: 
+ TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt') 
+except: 
+ TRUSTED_CERT_FILE = file('trusted-certs.crt') 


class RESTResponse(io.IOBase): 
@@ -125,6 +134,7 @@ def flush(self): 
     pass 

def create_connection(address): 
+ return 
    host, port = address 
    err = None 
    for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): 
@@ -152,7 +162,7 @@ def json_loadb(data): 


class RESTClientObject(object): 
- def __init__(self, max_reusable_connections=8, mock_urlopen=None): 
+ def __init__(self, max_reusable_connections=8, mock_urlopen=mock_urlopen): 
     """ 
     Parameters 
      max_reusable_connections 
@@ -206,7 +216,7 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re 
       raise ValueError("headers should not contain newlines (%s: %s)" % 
            (key, value)) 

-  try: 
+  if True: 
      # Grab a connection from the pool to make the request. 
      # We return it to the pool when caller close() the response 
      urlopen = self.mock_urlopen if self.mock_urlopen else self.pool_manager.urlopen 
@@ -217,14 +227,14 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re 
       headers=headers, 
       preload_content=False 
      ) 
-   r = RESTResponse(r) # wrap up the urllib3 response before proceeding 
-  except socket.error as e: 
-   raise RESTSocketError(url, e) 
-  except urllib3.exceptions.SSLError as e: 
-   raise RESTSocketError(url, "SSL certificate error: %s" % e) 
+   #r = RESTResponse(r) # wrap up the urllib3 response before proceeding 
+  #except socket.error as e: 
+  # raise RESTSocketError(url, e) 
+  #except urllib3.exceptions.SSLError as e: 
+  # raise RESTSocketError(url, "SSL certificate error: %s" % e) 

-  if r.status not in (200, 206): 
-   raise ErrorResponse(r, r.read()) 
+  #if r.status not in (200, 206): 
+  # raise ErrorResponse(r, r.read()) 

     return self.process_response(r, raw_response) 

@@ -321,10 +331,11 @@ def PUT(cls, *n, **kw): 
     return cls.IMPL.PUT(*n, **kw) 


-class RESTSocketError(socket.error): 
+class RESTSocketError(): 
    """A light wrapper for ``socket.error`` that adds some more information.""" 

    def __init__(self, host, e): 
+  return 
     msg = "Error connecting to \"%s\": %s" % (host, str(e)) 
     socket.error.__init__(self, msg) 
2

A partir de abril de 2016, ninguna de las otras sugerencias funciona . (API de Dropbox versión 2, Python SDK versión 6.2).

Si sólo necesita algunas de las funciones de SDK, me pareció más fácil sólo tiene que utilizar la API HTTP directamente:

def files_upload(f, path, mode='add', autorename=False, mute=False): 

    args = { 
     'path': path, 
     'mode': mode, 
     'autorename': autorename, 
     'mute': mute, 
    } 

    headers = { 
     'Authorization': 'Bearer {}'.format(ACCESS_TOKEN), 
     'Dropbox-API-Arg': json.dumps(args), 
     'Content-Type': 'application/octet-stream', 
    } 

    request = urllib2.Request('https://content.dropboxapi.com/2/files/upload', f, headers=headers) 
    r = urllib2.urlopen(request) 
Cuestiones relacionadas