59 |
59 |
60 |
60 |
61 |
61 |
62 |
62 |
63 |
63 |
|
64 import google |
64 import os |
65 import os |
65 import pickle |
66 import pickle |
|
67 import random |
66 import sha |
68 import sha |
67 import sys |
69 import sys |
68 import thread |
70 import thread |
69 import threading |
71 import threading |
|
72 import yaml |
|
73 |
70 from google.appengine.api import apiproxy_stub_map |
74 from google.appengine.api import apiproxy_stub_map |
71 from google.appengine.datastore import datastore_pb |
75 from google.appengine.datastore import datastore_pb |
72 from google.appengine.ext.remote_api import remote_api_pb |
76 from google.appengine.ext.remote_api import remote_api_pb |
73 from google.appengine.runtime import apiproxy_errors |
77 from google.appengine.runtime import apiproxy_errors |
74 from google.appengine.tools import appengine_rpc |
78 from google.appengine.tools import appengine_rpc |
|
79 |
|
80 |
|
81 class Error(Exception): |
|
82 """Base class for exceptions in this module.""" |
|
83 |
|
84 |
|
85 class ConfigurationError(Error): |
|
86 """Exception for configuration errors.""" |
75 |
87 |
76 |
88 |
77 def GetUserAgent(): |
89 def GetUserAgent(): |
78 """Determines the value of the 'User-agent' header to use for HTTP requests. |
90 """Determines the value of the 'User-agent' header to use for HTTP requests. |
79 |
91 |
376 |
388 |
377 def ConfigureRemoteDatastore(app_id, |
389 def ConfigureRemoteDatastore(app_id, |
378 path, |
390 path, |
379 auth_func, |
391 auth_func, |
380 servername=None, |
392 servername=None, |
381 rpc_server_factory=appengine_rpc.HttpRpcServer): |
393 rpc_server_factory=appengine_rpc.HttpRpcServer, |
|
394 rtok=None, |
|
395 secure=False): |
382 """Does necessary setup to allow easy remote access to an AppEngine datastore. |
396 """Does necessary setup to allow easy remote access to an AppEngine datastore. |
|
397 |
|
398 Either servername must be provided or app_id must not be None. If app_id |
|
399 is None and a servername is provided, this function will send a request |
|
400 to the server to retrieve the app_id. |
383 |
401 |
384 Args: |
402 Args: |
385 app_id: The app_id of your app, as declared in app.yaml. |
403 app_id: The app_id of your app, as declared in app.yaml. |
386 path: The path to the remote_api handler for your app |
404 path: The path to the remote_api handler for your app |
387 (for example, '/remote_api'). |
405 (for example, '/remote_api'). |
390 requires authentication to access the remote_api handler (it should!) |
408 requires authentication to access the remote_api handler (it should!) |
391 and you do not already have a valid auth cookie. |
409 and you do not already have a valid auth cookie. |
392 servername: The hostname your app is deployed on. Defaults to |
410 servername: The hostname your app is deployed on. Defaults to |
393 <app_id>.appspot.com. |
411 <app_id>.appspot.com. |
394 rpc_server_factory: A factory to construct the rpc server for the datastore. |
412 rpc_server_factory: A factory to construct the rpc server for the datastore. |
|
413 rtok: The validation token to sent with app_id lookups. If None, a random |
|
414 token is used. |
|
415 secure: Use SSL when communicating with the server. |
|
416 |
|
417 Raises: |
|
418 urllib2.HTTPError: if app_id is not provided and there is an error while |
|
419 retrieving it. |
|
420 ConfigurationError: if there is a error configuring the DatstoreFileStub. |
395 """ |
421 """ |
|
422 if not servername and not app_id: |
|
423 raise ConfigurationError('app_id or servername required') |
396 if not servername: |
424 if not servername: |
397 servername = '%s.appspot.com' % (app_id,) |
425 servername = '%s.appspot.com' % (app_id,) |
|
426 server = rpc_server_factory(servername, auth_func, GetUserAgent(), |
|
427 GetSourceName(), debug_data=False, secure=secure) |
|
428 if not app_id: |
|
429 if not rtok: |
|
430 random.seed() |
|
431 rtok = str(random.randint) |
|
432 urlargs = {'rtok': rtok} |
|
433 response = server.Send(path, payload=None, **urlargs) |
|
434 if not response.startswith('{'): |
|
435 raise ConfigurationError( |
|
436 'Invalid response recieved from server: %s' % response) |
|
437 app_info = yaml.load(response) |
|
438 if not app_info or 'rtok' not in app_info or 'app_id' not in app_info: |
|
439 raise ConfigurationError('Error parsing app_id lookup response') |
|
440 if app_info['rtok'] != rtok: |
|
441 raise ConfigurationError('Token validation failed during app_id lookup.') |
|
442 app_id = app_info['app_id'] |
|
443 |
398 os.environ['APPLICATION_ID'] = app_id |
444 os.environ['APPLICATION_ID'] = app_id |
399 apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() |
445 apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() |
400 server = rpc_server_factory(servername, auth_func, GetUserAgent(), |
|
401 GetSourceName()) |
|
402 stub = RemoteDatastoreStub(server, path) |
446 stub = RemoteDatastoreStub(server, path) |
403 apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub) |
447 apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub) |