Skip to content

Commit be6461a

Browse files
committed
feat(images): support GCS references and legacy BlobKey fallback for custom gRPC redirection
- Increase gRPC max receive message size to 32MB to handle large processed images. - Bypass blobstore.create_gs_key when USE_CUSTOM_IMAGES_GRPC_SERVICE is active, passing raw GCS paths directly to the service. - Implement local blob content fetching in _set_imagedata for legacy BlobKeys. This allows the custom gRPC service (running on Cloud Run) to receive the image data as bytes since it cannot resolve proprietary BlobKeys. - Update imports to support authenticated gRPC and high-level blob operations.
1 parent e91bef5 commit be6461a

1 file changed

Lines changed: 35 additions & 7 deletions

File tree

src/google/appengine/api/images/__init__.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@
3737
import os
3838
import struct
3939

40-
# import google.auth
41-
# import google.auth.transport.grpc
42-
# import google.auth.transport.requests
40+
import google.auth
41+
import google.auth.transport.grpc
42+
import google.auth.transport.requests
4343
from google.oauth2 import id_token
4444
import grpc
4545
from google.appengine.api import apiproxy_stub_map
4646
from google.appengine.api import blobstore
4747
from google.appengine.api import datastore_types
48+
from google.appengine.ext import blobstore as ext_blobstore
4849
from . import images_service_pb2
4950
from . import images_service_rpc_pb2_grpc
5051
from google.appengine.runtime import apiproxy_errors
@@ -88,7 +89,10 @@ def _make_grpc_call(method_name, request):
8889
call_credentials,
8990
)
9091

91-
authed_channel = grpc.secure_channel(target_host, composite_credentials)
92+
# Increase max receive message size to 32MB to handle large images
93+
options = [('grpc.max_receive_message_length', 32 * 1024 * 1024)]
94+
95+
authed_channel = grpc.secure_channel(target_host, composite_credentials, options=options)
9296
stub = images_service_rpc_pb2_grpc.ImagesServiceStub(authed_channel)
9397

9498
grpc_method = getattr(stub, method_name)
@@ -266,7 +270,10 @@ def __init__(self, image_data=None, blob_key=None, filename=None):
266270

267271
self._image_data = image_data
268272
if filename:
269-
self._blob_key = blobstore.create_gs_key(filename)
273+
if _USE_GRPC:
274+
self._blob_key = filename
275+
else:
276+
self._blob_key = blobstore.create_gs_key(filename)
270277
else:
271278
self._blob_key = _extract_blob_key(blob_key)
272279
self._transforms = []
@@ -814,8 +821,29 @@ def _set_imagedata(self, imagedata):
814821
imagedata: An `ImageData` protocol buffer instance.
815822
"""
816823
if self._blob_key:
817-
imagedata.content = b""
818-
imagedata.blob_key = self._blob_key
824+
if _USE_GRPC and not self._blob_key.startswith('/gs/'):
825+
# If we are using the custom gRPC service and have a legacy BlobKey,
826+
# we must fetch the data locally because the external service cannot read it.
827+
if not self._image_data:
828+
try:
829+
# Use high-level ext.blobstore to fetch content
830+
blob_info = ext_blobstore.BlobInfo.get(self._blob_key)
831+
if not blob_info:
832+
raise ObjectNotFoundError()
833+
834+
with blob_info.open() as reader:
835+
self._image_data = reader.read()
836+
except Exception as e:
837+
if isinstance(e, ObjectNotFoundError):
838+
raise
839+
raise Error("Failed to fetch blob data for gRPC: %s" % e)
840+
841+
imagedata.content = self._image_data
842+
else:
843+
# For GCS paths (starting with /gs/) or standard App Engine calls,
844+
# we maintain the reference-based approach.
845+
imagedata.content = b""
846+
imagedata.blob_key = self._blob_key
819847
else:
820848
imagedata.content = self._image_data
821849

0 commit comments

Comments
 (0)