2121if you want to use these Rapid Storage APIs.
2222
2323"""
24- from typing import Optional
25- from . import _utils
24+ from typing import List , Optional , Tuple
2625from google .cloud import _storage_v2
26+ from google .cloud .storage ._experimental .asyncio import _utils
2727from google .cloud .storage ._experimental .asyncio .async_grpc_client import AsyncGrpcClient
2828from google .cloud .storage ._experimental .asyncio .async_abstract_object_stream import (
2929 _AsyncAbstractObjectStream ,
@@ -72,6 +72,7 @@ def __init__(
7272 object_name : str ,
7373 generation_number : Optional [int ] = None , # None means new object
7474 write_handle : Optional [_storage_v2 .BidiWriteHandle ] = None ,
75+ routing_token : Optional [str ] = None ,
7576 ) -> None :
7677 if client is None :
7778 raise ValueError ("client must be provided" )
@@ -87,6 +88,7 @@ def __init__(
8788 )
8889 self .client : AsyncGrpcClient .grpc_client = client
8990 self .write_handle : Optional [_storage_v2 .BidiWriteHandle ] = write_handle
91+ self .routing_token : Optional [str ] = routing_token
9092
9193 self ._full_bucket_name = f"projects/_/buckets/{ self .bucket_name } "
9294
@@ -101,7 +103,7 @@ def __init__(
101103 self .persisted_size = 0
102104 self .object_resource : Optional [_storage_v2 .Object ] = None
103105
104- async def open (self ) -> None :
106+ async def open (self , metadata : Optional [ List [ Tuple [ str , str ]]] = None ) -> None :
105107 """
106108 Opens the bidi-gRPC connection to write to the object.
107109
@@ -110,7 +112,7 @@ async def open(self) -> None:
110112
111113 :rtype: None
112114 :raises ValueError: If the stream is already open.
113- :raises google.api_core.exceptions.FailedPrecondition:
115+ :raises google.api_core.exceptions.FailedPrecondition:
114116 if `generation_number` is 0 and object already exists.
115117 """
116118 if self ._is_stream_open :
@@ -121,9 +123,6 @@ async def open(self) -> None:
121123 # Created object type would be Appendable Object.
122124 # if `generation_number` == 0 new object will be created only if there
123125 # isn't any existing object.
124- is_open_via_write_handle = (
125- self .write_handle is not None and self .generation_number
126- )
127126 if self .generation_number is None or self .generation_number == 0 :
128127 self .first_bidi_write_req = _storage_v2 .BidiWriteObjectRequest (
129128 write_object_spec = _storage_v2 .WriteObjectSpec (
@@ -140,44 +139,46 @@ async def open(self) -> None:
140139 bucket = self ._full_bucket_name ,
141140 object = self .object_name ,
142141 generation = self .generation_number ,
143- write_handle = self .write_handle ,
142+ write_handle = self .write_handle if self .write_handle else None ,
143+ routing_token = self .routing_token if self .routing_token else None ,
144144 ),
145145 )
146+
147+ request_param_values = [f"bucket={ self ._full_bucket_name } " ]
148+ final_metadata = []
149+ if metadata :
150+ for key , value in metadata :
151+ if key == "x-goog-request-params" :
152+ request_param_values .append (value )
153+ else :
154+ final_metadata .append ((key , value ))
155+
156+ final_metadata .append (("x-goog-request-params" , "," .join (request_param_values )))
157+
146158 self .socket_like_rpc = AsyncBidiRpc (
147- self .rpc , initial_request = self .first_bidi_write_req , metadata = self .metadata
159+ self .rpc ,
160+ initial_request = self .first_bidi_write_req ,
161+ metadata = final_metadata ,
148162 )
149163
150164 await self .socket_like_rpc .open () # this is actually 1 send
151165 response = await self .socket_like_rpc .recv ()
152166 self ._is_stream_open = True
153- if is_open_via_write_handle :
154- # Don't use if not response.persisted_size because this will be true
155- # if persisted_size==0 (0 is considered "Falsy" in Python)
156- if response .persisted_size is None :
157- raise ValueError (
158- "Failed to obtain persisted_size after opening the stream via write_handle"
159- )
167+
168+ if response .persisted_size :
160169 self .persisted_size = response .persisted_size
161- else :
162- if not response .resource :
163- raise ValueError (
164- "Failed to obtain object resource after opening the stream"
165- )
166- if not response .resource .generation :
167- raise ValueError (
168- "Failed to obtain object generation after opening the stream"
169- )
170+
171+ if response .resource :
170172 if not response .resource .size :
171173 # Appending to a 0 byte appendable object.
172174 self .persisted_size = 0
173175 else :
174176 self .persisted_size = response .resource .size
175177
176- if not response .write_handle :
177- raise ValueError ("Failed to obtain write_handle after opening the stream" )
178+ self .generation_number = response .resource .generation
178179
179- self . generation_number = response .resource . generation
180- self .write_handle = response .write_handle
180+ if response .write_handle :
181+ self .write_handle = response .write_handle
181182
182183 async def close (self ) -> None :
183184 """Closes the bidi-gRPC connection."""
@@ -220,7 +221,14 @@ async def recv(self) -> _storage_v2.BidiWriteObjectResponse:
220221 if not self ._is_stream_open :
221222 raise ValueError ("Stream is not open" )
222223 response = await self .socket_like_rpc .recv ()
223- _utils .update_write_handle_if_exists (self , response )
224+ # Update write_handle if present in response
225+ if response :
226+ if response .write_handle :
227+ self .write_handle = response .write_handle
228+ if response .persisted_size is not None :
229+ self .persisted_size = response .persisted_size
230+ if response .resource and response .resource .size :
231+ self .persisted_size = response .resource .size
224232 return response
225233
226234 @property
0 commit comments