@@ -32,6 +32,19 @@ fn build_key(user_token: &str, store_id: &str, key: &str) -> String {
3232 format ! ( "{}#{}#{}" , user_token, store_id, key)
3333}
3434
35+ fn validate_vss_request ( store_id : & str , key : Option < & str > ) -> Result < ( ) , VssError > {
36+ if store_id. is_empty ( ) {
37+ return Err ( VssError :: InvalidRequestError ( "store_id cannot be empty" . to_string ( ) ) ) ;
38+ }
39+ if let Some ( k) = key {
40+ if k. is_empty ( ) {
41+ return Err ( VssError :: InvalidRequestError ( "key cannot be empty" . to_string ( ) ) ) ;
42+ }
43+ }
44+
45+ Ok ( ( ) )
46+ }
47+
3548/// In-memory implementation of the VSS Store.
3649pub struct InMemoryBackendImpl {
3750 store : Arc < Mutex < HashMap < String , VssDbRecord > > > ,
@@ -139,6 +152,9 @@ impl KvStore for InMemoryBackendImpl {
139152 async fn get (
140153 & self , user_token : String , request : GetObjectRequest ,
141154 ) -> Result < GetObjectResponse , VssError > {
155+
156+ validate_vss_request ( & request. store_id , Some ( & request. key ) ) ?;
157+
142158 let key = build_key ( & user_token, & request. store_id , & request. key ) ;
143159 let guard = self . store . lock ( ) . unwrap ( ) ;
144160
@@ -170,6 +186,25 @@ impl KvStore for InMemoryBackendImpl {
170186 async fn put (
171187 & self , user_token : String , request : PutObjectRequest ,
172188 ) -> Result < PutObjectResponse , VssError > {
189+
190+ validate_vss_request ( & request. store_id , None ) ?;
191+
192+ for kv in & request. transaction_items {
193+ if kv. key . is_empty ( ) {
194+ return Err ( VssError :: InvalidRequestError (
195+ "key cannot be empty in transaction_items" . to_string ( ) ,
196+ ) ) ;
197+ }
198+ }
199+
200+ for kv in & request. delete_items {
201+ if kv. key . is_empty ( ) {
202+ return Err ( VssError :: InvalidRequestError (
203+ "key cannot be empty in delete_items" . to_string ( ) ,
204+ ) ) ;
205+ }
206+ }
207+
173208 if request. transaction_items . len ( ) + request. delete_items . len ( ) > MAX_PUT_REQUEST_ITEM_COUNT
174209 {
175210 return Err ( VssError :: InvalidRequestError ( format ! (
@@ -209,6 +244,7 @@ impl KvStore for InMemoryBackendImpl {
209244 }
210245 }
211246 }
247+
212248 for kv in & request. delete_items {
213249 let key = build_key ( & user_token, & store_id, & kv. key ) ;
214250 if kv. version != -1 {
@@ -265,6 +301,9 @@ impl KvStore for InMemoryBackendImpl {
265301 let key_value = request. key_value . ok_or_else ( || {
266302 VssError :: InvalidRequestError ( "key_value missing in DeleteObjectRequest" . to_string ( ) )
267303 } ) ?;
304+
305+ validate_vss_request ( & request. store_id , Some ( & key_value. key ) ) ?;
306+
268307 let store_id = request. store_id . clone ( ) ;
269308 let mut guard = self . store . lock ( ) . unwrap ( ) ;
270309
@@ -287,25 +326,20 @@ impl KvStore for InMemoryBackendImpl {
287326 async fn list_key_versions (
288327 & self , user_token : String , request : ListKeyVersionsRequest ,
289328 ) -> Result < ListKeyVersionsResponse , VssError > {
329+ validate_vss_request ( & request. store_id , None ) ?;
330+
290331 let store_id = request. store_id ;
291332 let key_prefix = request. key_prefix . unwrap_or_default ( ) ;
292333 let page_token = request. page_token . unwrap_or_default ( ) ;
293334 let page_size = request. page_size . unwrap_or ( i32:: MAX ) ;
294335 let limit = std:: cmp:: min ( page_size, LIST_KEY_VERSIONS_MAX_PAGE_SIZE ) as usize ;
336+ let guard = self . store . lock ( ) . unwrap ( ) ;
295337
296- // Global version only on first page
297338 let mut global_version = None ;
298339 if page_token. is_empty ( ) {
299- let get_global = GetObjectRequest {
300- store_id : store_id. clone ( ) ,
301- key : GLOBAL_VERSION_KEY . to_string ( ) ,
302- } ;
303- let resp = self . get ( user_token. clone ( ) , get_global) . await ?;
304- global_version = resp. value . map ( |kv| kv. version ) ;
340+ global_version = Some ( self . get_current_global_version ( & guard, & user_token, & store_id) ) ;
305341 }
306342
307- let guard = self . store . lock ( ) . unwrap ( ) ;
308-
309343 let mut latest_per_key: std:: collections:: HashMap < String , KeyValue > =
310344 std:: collections:: HashMap :: new ( ) ;
311345 for ( k, r) in guard. iter ( ) {
@@ -336,16 +370,7 @@ impl KvStore for InMemoryBackendImpl {
336370 let start_idx = if page_token. is_empty ( ) {
337371 0
338372 } else {
339- match keys. iter ( ) . position ( |k| k == & page_token) {
340- Some ( i) => i + 1 ,
341- None => {
342- return Ok ( ListKeyVersionsResponse {
343- key_versions : vec ! [ ] ,
344- next_page_token : None ,
345- global_version,
346- } ) ;
347- } ,
348- }
373+ keys. iter ( ) . position ( |k| k > & page_token) . unwrap_or ( keys. len ( ) )
349374 } ;
350375
351376 let page_keys: Vec < String > = keys. into_iter ( ) . skip ( start_idx) . take ( limit) . collect ( ) ;
0 commit comments