1# Copyright 2014 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Connections to Google Cloud Datastore API servers.""" 16 17from google.rpc import status_pb2 # type: ignore 18 19from google.cloud import _http as connection_module 20from google.cloud import exceptions # type: ignore 21from google.cloud.datastore_v1.types import datastore as _datastore_pb2 22 23 24DATASTORE_API_HOST = "datastore.googleapis.com" 25"""Datastore API request host.""" 26API_BASE_URL = "https://" + DATASTORE_API_HOST 27"""The base of the API call URL.""" 28API_VERSION = "v1" 29"""The version of the API, used in building the API call's URL.""" 30API_URL_TEMPLATE = "{api_base}/{api_version}/projects" "/{project}:{method}" 31"""A template for the URL of a particular API call.""" 32 33 34def _make_retry_timeout_kwargs(retry, timeout): 35 """Helper for methods taking optional retry / timout args.""" 36 kwargs = {} 37 38 if retry is not None: 39 kwargs["retry"] = retry 40 41 if timeout is not None: 42 kwargs["timeout"] = timeout 43 44 return kwargs 45 46 47def _make_request_pb(request, request_pb_type): 48 """Helper for converting dicts to request messages.""" 49 if not isinstance(request, request_pb_type): 50 request = request_pb_type(**request) 51 52 return request 53 54 55def _request( 56 http, project, method, data, base_url, client_info, retry=None, timeout=None, 57): 58 """Make a request over the Http transport to the Cloud Datastore API. 59 60 :type http: :class:`requests.Session` 61 :param http: HTTP object to make requests. 62 63 :type project: str 64 :param project: The project to make the request for. 65 66 :type method: str 67 :param method: The API call method name (ie, ``runQuery``, 68 ``lookup``, etc) 69 70 :type data: str 71 :param data: The data to send with the API call. 72 Typically this is a serialized Protobuf string. 73 74 :type base_url: str 75 :param base_url: The base URL where the API lives. 76 77 :type client_info: :class:`google.api_core.client_info.ClientInfo` 78 :param client_info: used to generate user agent. 79 80 :type retry: :class:`google.api_core.retry.Retry` 81 :param retry: (Optional) retry policy for the request 82 83 :type timeout: float or tuple(float, float) 84 :param timeout: (Optional) timeout for the request 85 86 :rtype: str 87 :returns: The string response content from the API call. 88 :raises: :class:`google.cloud.exceptions.GoogleCloudError` if the 89 response code is not 200 OK. 90 """ 91 user_agent = client_info.to_user_agent() 92 headers = { 93 "Content-Type": "application/x-protobuf", 94 "User-Agent": user_agent, 95 connection_module.CLIENT_INFO_HEADER: user_agent, 96 } 97 api_url = build_api_url(project, method, base_url) 98 99 requester = http.request 100 101 if retry is not None: 102 requester = retry(requester) 103 104 if timeout is not None: 105 response = requester( 106 url=api_url, method="POST", headers=headers, data=data, timeout=timeout, 107 ) 108 else: 109 response = requester(url=api_url, method="POST", headers=headers, data=data) 110 111 if response.status_code != 200: 112 error_status = status_pb2.Status.FromString(response.content) 113 raise exceptions.from_http_status( 114 response.status_code, error_status.message, errors=[error_status] 115 ) 116 117 return response.content 118 119 120def _rpc( 121 http, 122 project, 123 method, 124 base_url, 125 client_info, 126 request_pb, 127 response_pb_cls, 128 retry=None, 129 timeout=None, 130): 131 """Make a protobuf RPC request. 132 133 :type http: :class:`requests.Session` 134 :param http: HTTP object to make requests. 135 136 :type project: str 137 :param project: The project to connect to. This is 138 usually your project name in the cloud console. 139 140 :type method: str 141 :param method: The name of the method to invoke. 142 143 :type base_url: str 144 :param base_url: The base URL where the API lives. 145 146 :type client_info: :class:`google.api_core.client_info.ClientInfo` 147 :param client_info: used to generate user agent. 148 149 :type request_pb: :class:`google.protobuf.message.Message` instance 150 :param request_pb: the protobuf instance representing the request. 151 152 :type response_pb_cls: A :class:`google.protobuf.message.Message` 153 subclass. 154 :param response_pb_cls: The class used to unmarshall the response 155 protobuf. 156 157 :type retry: :class:`google.api_core.retry.Retry` 158 :param retry: (Optional) retry policy for the request 159 160 :type timeout: float or tuple(float, float) 161 :param timeout: (Optional) timeout for the request 162 163 :rtype: :class:`google.protobuf.message.Message` 164 :returns: The RPC message parsed from the response. 165 """ 166 req_data = request_pb._pb.SerializeToString() 167 kwargs = _make_retry_timeout_kwargs(retry, timeout) 168 response = _request( 169 http, project, method, req_data, base_url, client_info, **kwargs 170 ) 171 return response_pb_cls.deserialize(response) 172 173 174def build_api_url(project, method, base_url): 175 """Construct the URL for a particular API call. 176 177 This method is used internally to come up with the URL to use when 178 making RPCs to the Cloud Datastore API. 179 180 :type project: str 181 :param project: The project to connect to. This is 182 usually your project name in the cloud console. 183 184 :type method: str 185 :param method: The API method to call (e.g. 'runQuery', 'lookup'). 186 187 :type base_url: str 188 :param base_url: The base URL where the API lives. 189 190 :rtype: str 191 :returns: The API URL created. 192 """ 193 return API_URL_TEMPLATE.format( 194 api_base=base_url, api_version=API_VERSION, project=project, method=method 195 ) 196 197 198class HTTPDatastoreAPI(object): 199 """An API object that sends proto-over-HTTP requests. 200 201 Intended to provide the same methods as the GAPIC ``DatastoreClient``. 202 203 :type client: :class:`~google.cloud.datastore.client.Client` 204 :param client: The client that provides configuration. 205 """ 206 207 def __init__(self, client): 208 self.client = client 209 210 def lookup(self, request, retry=None, timeout=None): 211 """Perform a ``lookup`` request. 212 213 :type request: :class:`_datastore_pb2.LookupRequest` or dict 214 :param request: 215 Parameter bundle for API request. 216 217 :type retry: :class:`google.api_core.retry.Retry` 218 :param retry: (Optional) retry policy for the request 219 220 :type timeout: float or tuple(float, float) 221 :param timeout: (Optional) timeout for the request 222 223 :rtype: :class:`.datastore_pb2.LookupResponse` 224 :returns: The returned protobuf response object. 225 """ 226 request_pb = _make_request_pb(request, _datastore_pb2.LookupRequest) 227 project_id = request_pb.project_id 228 229 return _rpc( 230 self.client._http, 231 project_id, 232 "lookup", 233 self.client._base_url, 234 self.client._client_info, 235 request_pb, 236 _datastore_pb2.LookupResponse, 237 retry=retry, 238 timeout=timeout, 239 ) 240 241 def run_query(self, request, retry=None, timeout=None): 242 """Perform a ``runQuery`` request. 243 244 :type request: :class:`_datastore_pb2.BeginTransactionRequest` or dict 245 :param request: 246 Parameter bundle for API request. 247 248 :type retry: :class:`google.api_core.retry.Retry` 249 :param retry: (Optional) retry policy for the request 250 251 :type timeout: float or tuple(float, float) 252 :param timeout: (Optional) timeout for the request 253 254 :rtype: :class:`.datastore_pb2.RunQueryResponse` 255 :returns: The returned protobuf response object. 256 """ 257 request_pb = _make_request_pb(request, _datastore_pb2.RunQueryRequest) 258 project_id = request_pb.project_id 259 260 return _rpc( 261 self.client._http, 262 project_id, 263 "runQuery", 264 self.client._base_url, 265 self.client._client_info, 266 request_pb, 267 _datastore_pb2.RunQueryResponse, 268 retry=retry, 269 timeout=timeout, 270 ) 271 272 def begin_transaction(self, request, retry=None, timeout=None): 273 """Perform a ``beginTransaction`` request. 274 275 :type request: :class:`_datastore_pb2.BeginTransactionRequest` or dict 276 :param request: 277 Parameter bundle for API request. 278 279 :type retry: :class:`google.api_core.retry.Retry` 280 :param retry: (Optional) retry policy for the request 281 282 :type timeout: float or tuple(float, float) 283 :param timeout: (Optional) timeout for the request 284 285 :rtype: :class:`.datastore_pb2.BeginTransactionResponse` 286 :returns: The returned protobuf response object. 287 """ 288 request_pb = _make_request_pb(request, _datastore_pb2.BeginTransactionRequest) 289 project_id = request_pb.project_id 290 291 return _rpc( 292 self.client._http, 293 project_id, 294 "beginTransaction", 295 self.client._base_url, 296 self.client._client_info, 297 request_pb, 298 _datastore_pb2.BeginTransactionResponse, 299 retry=retry, 300 timeout=timeout, 301 ) 302 303 def commit(self, request, retry=None, timeout=None): 304 """Perform a ``commit`` request. 305 306 :type request: :class:`_datastore_pb2.CommitRequest` or dict 307 :param request: 308 Parameter bundle for API request. 309 310 :type retry: :class:`google.api_core.retry.Retry` 311 :param retry: (Optional) retry policy for the request 312 313 :type timeout: float or tuple(float, float) 314 :param timeout: (Optional) timeout for the request 315 316 :rtype: :class:`.datastore_pb2.CommitResponse` 317 :returns: The returned protobuf response object. 318 """ 319 request_pb = _make_request_pb(request, _datastore_pb2.CommitRequest) 320 project_id = request_pb.project_id 321 322 return _rpc( 323 self.client._http, 324 project_id, 325 "commit", 326 self.client._base_url, 327 self.client._client_info, 328 request_pb, 329 _datastore_pb2.CommitResponse, 330 retry=retry, 331 timeout=timeout, 332 ) 333 334 def rollback(self, request, retry=None, timeout=None): 335 """Perform a ``rollback`` request. 336 337 :type request: :class:`_datastore_pb2.RollbackRequest` or dict 338 :param request: 339 Parameter bundle for API request. 340 341 :type retry: :class:`google.api_core.retry.Retry` 342 :param retry: (Optional) retry policy for the request 343 344 :type timeout: float or tuple(float, float) 345 :param timeout: (Optional) timeout for the request 346 347 :rtype: :class:`.datastore_pb2.RollbackResponse` 348 :returns: The returned protobuf response object. 349 """ 350 request_pb = _make_request_pb(request, _datastore_pb2.RollbackRequest) 351 project_id = request_pb.project_id 352 353 return _rpc( 354 self.client._http, 355 project_id, 356 "rollback", 357 self.client._base_url, 358 self.client._client_info, 359 request_pb, 360 _datastore_pb2.RollbackResponse, 361 retry=retry, 362 timeout=timeout, 363 ) 364 365 def allocate_ids(self, request, retry=None, timeout=None): 366 """Perform an ``allocateIds`` request. 367 368 :type request: :class:`_datastore_pb2.AllocateIdsRequest` or dict 369 :param request: 370 Parameter bundle for API request. 371 372 :type retry: :class:`google.api_core.retry.Retry` 373 :param retry: (Optional) retry policy for the request 374 375 :type timeout: float or tuple(float, float) 376 :param timeout: (Optional) timeout for the request 377 378 :rtype: :class:`.datastore_pb2.AllocateIdsResponse` 379 :returns: The returned protobuf response object. 380 """ 381 request_pb = _make_request_pb(request, _datastore_pb2.AllocateIdsRequest) 382 project_id = request_pb.project_id 383 384 return _rpc( 385 self.client._http, 386 project_id, 387 "allocateIds", 388 self.client._base_url, 389 self.client._client_info, 390 request_pb, 391 _datastore_pb2.AllocateIdsResponse, 392 retry=retry, 393 timeout=timeout, 394 ) 395 396 def reserve_ids(self, request, retry=None, timeout=None): 397 """Perform an ``reserveIds`` request. 398 399 :type request: :class:`_datastore_pb2.ReserveIdsRequest` or dict 400 :param request: 401 Parameter bundle for API request. 402 403 :type retry: :class:`google.api_core.retry.Retry` 404 :param retry: (Optional) retry policy for the request 405 406 :type timeout: float or tuple(float, float) 407 :param timeout: (Optional) timeout for the request 408 409 :rtype: :class:`.datastore_pb2.ReserveIdsResponse` 410 :returns: The returned protobuf response object. 411 """ 412 request_pb = _make_request_pb(request, _datastore_pb2.ReserveIdsRequest) 413 project_id = request_pb.project_id 414 415 return _rpc( 416 self.client._http, 417 project_id, 418 "reserveIds", 419 self.client._base_url, 420 self.client._client_info, 421 request_pb, 422 _datastore_pb2.ReserveIdsResponse, 423 retry=retry, 424 timeout=timeout, 425 ) 426