thirdparty/google_appengine/google/appengine/ext/remote_api/handler.py
changeset 3031 7678f72140e6
parent 2864 2e0b0af889be
equal deleted inserted replaced
3030:09cae668b536 3031:7678f72140e6
    40 import google
    40 import google
    41 import logging
    41 import logging
    42 import os
    42 import os
    43 import pickle
    43 import pickle
    44 import sha
    44 import sha
       
    45 import sys
    45 import wsgiref.handlers
    46 import wsgiref.handlers
    46 import yaml
    47 import yaml
    47 
    48 
    48 from google.appengine.api import api_base_pb
    49 from google.appengine.api import api_base_pb
    49 from google.appengine.api import apiproxy_stub
    50 from google.appengine.api import apiproxy_stub
    50 from google.appengine.api import apiproxy_stub_map
    51 from google.appengine.api import apiproxy_stub_map
    51 from google.appengine.api import datastore_errors
       
    52 from google.appengine.api import mail_service_pb
    52 from google.appengine.api import mail_service_pb
    53 from google.appengine.api import urlfetch_service_pb
    53 from google.appengine.api import urlfetch_service_pb
    54 from google.appengine.api import users
    54 from google.appengine.api import users
    55 from google.appengine.api.capabilities import capability_service_pb
    55 from google.appengine.api.capabilities import capability_service_pb
    56 from google.appengine.api.images import images_service_pb
    56 from google.appengine.api.images import images_service_pb
    57 from google.appengine.api.memcache import memcache_service_pb
    57 from google.appengine.api.memcache import memcache_service_pb
       
    58 try:
       
    59   __import__('google.appengine.api.labs.taskqueue.taskqueue_service_pb')
       
    60   taskqueue_service_pb = sys.modules.get(
       
    61       'google.appengine.api.labs.taskqueue.taskqueue_service_pb')
       
    62 except ImportError:
       
    63   from google.appengine.api.taskqueue import taskqueue_service_pb
       
    64 from google.appengine.api.xmpp import xmpp_service_pb
    58 from google.appengine.datastore import datastore_pb
    65 from google.appengine.datastore import datastore_pb
    59 from google.appengine.ext import webapp
    66 from google.appengine.ext import webapp
    60 from google.appengine.ext.remote_api import remote_api_pb
    67 from google.appengine.ext.remote_api import remote_api_pb
    61 from google.appengine.runtime import apiproxy_errors
    68 from google.appengine.runtime import apiproxy_errors
    62 
    69 
    71 
    78 
    72   To work around this, RemoteDatastoreStub provides its own implementation of
    79   To work around this, RemoteDatastoreStub provides its own implementation of
    73   RunQuery that immediately returns the query results.
    80   RunQuery that immediately returns the query results.
    74   """
    81   """
    75 
    82 
       
    83   def __init__(self, service='datastore_v3', _test_stub_map=None):
       
    84     """Constructor.
       
    85 
       
    86     Args:
       
    87       service: The name of the service
       
    88       _test_stub_map: An APIProxyStubMap to use for testing purposes.
       
    89     """
       
    90     super(RemoteDatastoreStub, self).__init__(service)
       
    91     if _test_stub_map:
       
    92       self.__call = _test_stub_map.MakeSyncCall
       
    93     else:
       
    94       self.__call = apiproxy_stub_map.MakeSyncCall
       
    95 
    76   def _Dynamic_RunQuery(self, request, response):
    96   def _Dynamic_RunQuery(self, request, response):
    77     """Handle a RunQuery request.
    97     """Handle a RunQuery request.
    78 
    98 
    79     We handle RunQuery by executing a Query and a Next and returning the result
    99     We handle RunQuery by executing a Query and a Next and returning the result
    80     of the Next request.
   100     of the Next request.
    81     """
   101     """
    82     runquery_response = datastore_pb.QueryResult()
   102     runquery_response = datastore_pb.QueryResult()
    83     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'RunQuery',
   103     self.__call('datastore_v3', 'RunQuery', request, runquery_response)
    84                                    request, runquery_response)
       
    85     if runquery_response.result_size() > 0:
   104     if runquery_response.result_size() > 0:
    86       response.CopyFrom(runquery_response)
   105       response.CopyFrom(runquery_response)
    87       return
   106       return
    88 
   107 
    89     next_request = datastore_pb.NextRequest()
   108     next_request = datastore_pb.NextRequest()
    90     next_request.mutable_cursor().CopyFrom(runquery_response.cursor())
   109     next_request.mutable_cursor().CopyFrom(runquery_response.cursor())
    91     next_request.set_count(request.limit())
   110     next_request.set_count(request.limit())
    92     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Next',
   111     self.__call('datastore_v3', 'Next', next_request, response)
    93                                    next_request, response)
       
    94 
   112 
    95   def _Dynamic_Transaction(self, request, response):
   113   def _Dynamic_Transaction(self, request, response):
    96     """Handle a Transaction request.
   114     """Handle a Transaction request.
    97 
   115 
    98     We handle transactions by accumulating Put requests on the client end, as
   116     We handle transactions by accumulating Put requests on the client end, as
   100     Transaction is invoked, which verifies that all the entities in the
   118     Transaction is invoked, which verifies that all the entities in the
   101     precondition list still exist and their hashes match, then performs a
   119     precondition list still exist and their hashes match, then performs a
   102     transaction of its own to make the updates.
   120     transaction of its own to make the updates.
   103     """
   121     """
   104     tx = datastore_pb.Transaction()
   122     tx = datastore_pb.Transaction()
   105     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'BeginTransaction',
   123     self.__call('datastore_v3', 'BeginTransaction', api_base_pb.VoidProto(), tx)
   106                                    api_base_pb.VoidProto(), tx)
       
   107 
   124 
   108     preconditions = request.precondition_list()
   125     preconditions = request.precondition_list()
   109     if preconditions:
   126     if preconditions:
   110       get_request = datastore_pb.GetRequest()
   127       get_request = datastore_pb.GetRequest()
   111       get_request.mutable_transaction().CopyFrom(tx)
   128       get_request.mutable_transaction().CopyFrom(tx)
   112       for precondition in preconditions:
   129       for precondition in preconditions:
   113         key = get_request.add_key()
   130         key = get_request.add_key()
   114         key.CopyFrom(precondition.key())
   131         key.CopyFrom(precondition.key())
   115       get_response = datastore_pb.GetResponse()
   132       get_response = datastore_pb.GetResponse()
   116       apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Get', get_request,
   133       self.__call('datastore_v3', 'Get', get_request, get_response)
   117                                      get_response)
       
   118       entities = get_response.entity_list()
   134       entities = get_response.entity_list()
   119       assert len(entities) == request.precondition_size()
   135       assert len(entities) == request.precondition_size()
   120       for precondition, entity in zip(preconditions, entities):
   136       for precondition, entity in zip(preconditions, entities):
   121         if precondition.has_hash() != entity.has_entity():
   137         if precondition.has_hash() != entity.has_entity():
   122           raise apiproxy_errors.ApplicationError(
   138           raise apiproxy_errors.ApplicationError(
   130                 "Transaction precondition failed.")
   146                 "Transaction precondition failed.")
   131 
   147 
   132     if request.has_puts():
   148     if request.has_puts():
   133       put_request = request.puts()
   149       put_request = request.puts()
   134       put_request.mutable_transaction().CopyFrom(tx)
   150       put_request.mutable_transaction().CopyFrom(tx)
   135       apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Put',
   151       self.__call('datastore_v3', 'Put', put_request, response)
   136                                      put_request, response)
       
   137 
   152 
   138     if request.has_deletes():
   153     if request.has_deletes():
   139       delete_request = request.deletes()
   154       delete_request = request.deletes()
   140       delete_request.mutable_transaction().CopyFrom(tx)
   155       delete_request.mutable_transaction().CopyFrom(tx)
   141       apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Delete',
   156       self.__call('datastore_v3', 'Delete', delete_request,
   142                                      delete_request, api_base_pb.VoidProto())
   157                  api_base_pb.VoidProto())
   143 
   158 
   144     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Commit', tx,
   159     self.__call('datastore_v3', 'Commit', tx, api_base_pb.VoidProto())
   145                                    api_base_pb.VoidProto())
       
   146 
   160 
   147   def _Dynamic_GetIDs(self, request, response):
   161   def _Dynamic_GetIDs(self, request, response):
   148     """Fetch unique IDs for a set of paths."""
   162     """Fetch unique IDs for a set of paths."""
   149     for entity in request.entity_list():
   163     for entity in request.entity_list():
   150       assert entity.property_size() == 0
   164       assert entity.property_size() == 0
   152       assert entity.entity_group().element_size() == 0
   166       assert entity.entity_group().element_size() == 0
   153       lastpart = entity.key().path().element_list()[-1]
   167       lastpart = entity.key().path().element_list()[-1]
   154       assert lastpart.id() == 0 and not lastpart.has_name()
   168       assert lastpart.id() == 0 and not lastpart.has_name()
   155 
   169 
   156     tx = datastore_pb.Transaction()
   170     tx = datastore_pb.Transaction()
   157     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'BeginTransaction',
   171     self.__call('datastore_v3', 'BeginTransaction', api_base_pb.VoidProto(), tx)
   158                                    api_base_pb.VoidProto(), tx)
   172 
   159 
   173     self.__call('datastore_v3', 'Put', request, response)
   160     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Put', request, response)
   174 
   161 
   175     self.__call('datastore_v3', 'Rollback', tx, api_base_pb.VoidProto())
   162     apiproxy_stub_map.MakeSyncCall('datastore_v3', 'Rollback', tx,
       
   163                                    api_base_pb.VoidProto())
       
   164 
   176 
   165 
   177 
   166 SERVICE_PB_MAP = {
   178 SERVICE_PB_MAP = {
   167     'capability_service': {
   179     'capability_service': {
   168         'IsEnabled': (capability_service_pb.IsEnabledRequest,
   180         'IsEnabled': (capability_service_pb.IsEnabledRequest,
   172         'Get':        (datastore_pb.GetRequest, datastore_pb.GetResponse),
   184         'Get':        (datastore_pb.GetRequest, datastore_pb.GetResponse),
   173         'Put':        (datastore_pb.PutRequest, datastore_pb.PutResponse),
   185         'Put':        (datastore_pb.PutRequest, datastore_pb.PutResponse),
   174         'Delete':     (datastore_pb.DeleteRequest, datastore_pb.DeleteResponse),
   186         'Delete':     (datastore_pb.DeleteRequest, datastore_pb.DeleteResponse),
   175         'Count':      (datastore_pb.Query, api_base_pb.Integer64Proto),
   187         'Count':      (datastore_pb.Query, api_base_pb.Integer64Proto),
   176         'GetIndices': (api_base_pb.StringProto, datastore_pb.CompositeIndices),
   188         'GetIndices': (api_base_pb.StringProto, datastore_pb.CompositeIndices),
       
   189         'AllocateIds':(datastore_pb.AllocateIdsRequest,
       
   190                        datastore_pb.AllocateIdsResponse),
   177     },
   191     },
   178     'images': {
   192     'images': {
   179         'Transform': (images_service_pb.ImagesTransformRequest,
   193         'Transform': (images_service_pb.ImagesTransformRequest,
   180                       images_service_pb.ImagesTransformResponse),
   194                       images_service_pb.ImagesTransformResponse),
   181         'Composite': (images_service_pb.ImagesCompositeRequest,
   195         'Composite': (images_service_pb.ImagesCompositeRequest,
   199         'FlushAll':  (memcache_service_pb.MemcacheFlushRequest,
   213         'FlushAll':  (memcache_service_pb.MemcacheFlushRequest,
   200                       memcache_service_pb.MemcacheFlushResponse),
   214                       memcache_service_pb.MemcacheFlushResponse),
   201         'Stats':     (memcache_service_pb.MemcacheStatsRequest,
   215         'Stats':     (memcache_service_pb.MemcacheStatsRequest,
   202                       memcache_service_pb.MemcacheStatsResponse),
   216                       memcache_service_pb.MemcacheStatsResponse),
   203     },
   217     },
       
   218     'taskqueue': {
       
   219         'Add':       (taskqueue_service_pb.TaskQueueAddRequest,
       
   220                       taskqueue_service_pb.TaskQueueAddResponse),
       
   221         'UpdateQueue':(taskqueue_service_pb.TaskQueueUpdateQueueRequest,
       
   222                        taskqueue_service_pb.TaskQueueUpdateQueueResponse),
       
   223         'FetchQueues':(taskqueue_service_pb.TaskQueueFetchQueuesRequest,
       
   224                        taskqueue_service_pb.TaskQueueFetchQueuesResponse),
       
   225         'FetchQueueStats':(
       
   226             taskqueue_service_pb.TaskQueueFetchQueueStatsRequest,
       
   227             taskqueue_service_pb.TaskQueueFetchQueueStatsResponse),
       
   228     },
   204     'remote_datastore': {
   229     'remote_datastore': {
   205         'RunQuery':    (datastore_pb.Query, datastore_pb.QueryResult),
   230         'RunQuery':    (datastore_pb.Query, datastore_pb.QueryResult),
   206         'Transaction': (remote_api_pb.TransactionRequest,
   231         'Transaction': (remote_api_pb.TransactionRequest,
   207                         datastore_pb.PutResponse),
   232                         datastore_pb.PutResponse),
   208         'GetIDs':      (remote_api_pb.PutRequest, datastore_pb.PutResponse),
   233         'GetIDs':      (remote_api_pb.PutRequest, datastore_pb.PutResponse),
   209     },
   234     },
   210     'urlfetch': {
   235     'urlfetch': {
   211         'Fetch': (urlfetch_service_pb.URLFetchRequest,
   236         'Fetch': (urlfetch_service_pb.URLFetchRequest,
   212                   urlfetch_service_pb.URLFetchResponse),
   237                   urlfetch_service_pb.URLFetchResponse),
       
   238     },
       
   239     'xmpp': {
       
   240         'GetPresence': (xmpp_service_pb.PresenceRequest,
       
   241                         xmpp_service_pb.PresenceResponse),
       
   242         'SendMessage': (xmpp_service_pb.XmppMessageRequest,
       
   243                         xmpp_service_pb.XmppMessageResponse),
       
   244         'SendInvite':  (xmpp_service_pb.XmppInviteRequest,
       
   245                         xmpp_service_pb.XmppInviteResponse),
   213     },
   246     },
   214 }
   247 }
   215 
   248 
   216 
   249 
   217 class ApiCallHandler(webapp.RequestHandler):
   250 class ApiCallHandler(webapp.RequestHandler):
   265       self.response.set_status(200)
   298       self.response.set_status(200)
   266     except Exception, e:
   299     except Exception, e:
   267       logging.exception('Exception while handling %s', request)
   300       logging.exception('Exception while handling %s', request)
   268       self.response.set_status(200)
   301       self.response.set_status(200)
   269       response.mutable_exception().set_contents(pickle.dumps(e))
   302       response.mutable_exception().set_contents(pickle.dumps(e))
   270       if isinstance(e, datastore_errors.Error):
   303       if isinstance(e, apiproxy_errors.ApplicationError):
   271         application_error = response.mutable_application_error()
   304         application_error = response.mutable_application_error()
   272         application_error.setCode(e.application_error)
   305         application_error.set_code(e.application_error)
   273         application_error.setDetail(e.error_detail)
   306         application_error.set_detail(e.error_detail)
   274     self.response.out.write(response.Encode())
   307     self.response.out.write(response.Encode())
   275 
   308 
   276   def ExecuteRequest(self, request):
   309   def ExecuteRequest(self, request):
   277     """Executes an API invocation and returns the response object."""
   310     """Executes an API invocation and returns the response object."""
   278     service = request.service_name()
   311     service = request.service_name()