11use crate :: { get_blob, Message , PackageId , Request } ;
2+ use alloy:: rpc:: types:: error;
23use serde:: { de:: DeserializeOwned , Deserialize , Serialize } ;
34use std:: marker:: PhantomData ;
45use thiserror:: Error ;
@@ -13,40 +14,98 @@ pub struct KvRequest {
1314 pub action : KvAction ,
1415}
1516
17+ /// IPC Action format, representing operations that can be performed on the key-value runtime module.
18+ /// These actions are included in a KvRequest sent to the kv:distro:sys runtime module.
1619#[ derive( Debug , Serialize , Deserialize , Clone ) ]
1720pub enum KvAction {
21+ /// Opens an existing key-value database or creates a new one if it doesn't exist.
1822 Open ,
23+ /// Permanently deletes the entire key-value database.
1924 RemoveDb ,
25+ /// Sets a value for the specified key in the database.
26+ ///
27+ /// # Parameters
28+ /// * `key` - The key as a byte vector
29+ /// * `tx_id` - Optional transaction ID if this operation is part of a transaction
2030 Set { key : Vec < u8 > , tx_id : Option < u64 > } ,
31+ /// Deletes a key-value pair from the database.
32+ ///
33+ /// # Parameters
34+ /// * `key` - The key to delete as a byte vector
35+ /// * `tx_id` - Optional transaction ID if this operation is part of a transaction
2136 Delete { key : Vec < u8 > , tx_id : Option < u64 > } ,
37+ /// Retrieves the value associated with the specified key.
38+ ///
39+ /// # Parameters
40+ /// * `key` - The key to look up as a byte vector
2241 Get { key : Vec < u8 > } ,
42+ /// Begins a new transaction for atomic operations.
2343 BeginTx ,
44+ /// Commits all operations in the specified transaction.
45+ ///
46+ /// # Parameters
47+ /// * `tx_id` - The ID of the transaction to commit
2448 Commit { tx_id : u64 } ,
49+ /// Creates a backup of the database.
2550 Backup ,
2651}
2752
53+ /// Response types for key-value store operations.
54+ /// These responses are returned after processing a KvAction request.
2855#[ derive( Debug , Serialize , Deserialize ) ]
2956pub enum KvResponse {
57+ /// Indicates successful completion of an operation.
3058 Ok ,
59+ /// Returns the transaction ID for a newly created transaction.
60+ ///
61+ /// # Fields
62+ /// * `tx_id` - The ID of the newly created transaction
3163 BeginTx { tx_id : u64 } ,
64+ /// Returns the key that was retrieved from the database.
65+ ///
66+ /// # Fields
67+ /// * `key` - The retrieved key as a byte vector
3268 Get { key : Vec < u8 > } ,
69+ /// Indicates an error occurred during the operation.
3370 Err ( KvError ) ,
3471}
3572
73+ /// Errors that can occur during key-value store operations.
74+ /// These errors are returned as part of `KvResponse::Err` when an operation fails.
3675#[ derive( Debug , Serialize , Deserialize , Error ) ]
3776pub enum KvError {
77+ /// The requested database does not exist.
3878 #[ error( "kv: DbDoesNotExist" ) ]
3979 NoDb ,
80+ /// The requested key was not found in the database.
4081 #[ error( "kv: KeyNotFound" ) ]
4182 KeyNotFound ,
83+ /// No active transaction found for the given transaction ID.
4284 #[ error( "kv: no Tx found" ) ]
4385 NoTx ,
86+ /// The operation requires capabilities that the caller doesn't have.
87+ ///
88+ /// # Fields
89+ /// * `error` - Description of the missing capability or permission
4490 #[ error( "kv: No capability: {error}" ) ]
4591 NoCap { error : String } ,
92+ /// An internal RocksDB error occurred during the operation.
93+ ///
94+ /// # Fields
95+ /// * `action` - The operation that was being performed
96+ /// * `error` - The specific error message from RocksDB
4697 #[ error( "kv: rocksdb internal error: {error}" ) ]
4798 RocksDBError { action : String , error : String } ,
99+ /// Error parsing or processing input data.
100+ ///
101+ /// # Fields
102+ /// * `error` - Description of what was invalid about the input
48103 #[ error( "kv: input bytes/json/key error: {error}" ) ]
49104 InputError { error : String } ,
105+ /// An I/O error occurred during the operation.
106+ ///
107+ /// # Fields
108+ /// * `error` - Description of the I/O error
50109 #[ error( "kv: IO error: {error}" ) ]
51110 IOError { error : String } ,
52111}
@@ -306,6 +365,105 @@ where
306365 }
307366}
308367
368+ impl Kv < Vec < u8 > , Vec < u8 > > {
369+ /// Get raw bytes directly
370+ pub fn get_raw ( & self , key : & [ u8 ] ) -> anyhow:: Result < Vec < u8 > > {
371+ let res = Request :: new ( )
372+ . target ( ( "our" , "kv" , "distro" , "sys" ) )
373+ . body ( serde_json:: to_vec ( & KvRequest {
374+ package_id : self . package_id . clone ( ) ,
375+ db : self . db . clone ( ) ,
376+ action : KvAction :: Get { key : key. to_vec ( ) } ,
377+ } ) ?)
378+ . send_and_await_response ( self . timeout ) ?;
379+
380+ match res {
381+ Ok ( Message :: Response { body, .. } ) => {
382+ let response = serde_json:: from_slice :: < KvResponse > ( & body) ?;
383+
384+ match response {
385+ KvResponse :: Get { .. } => {
386+ let bytes = match get_blob ( ) {
387+ Some ( bytes) => bytes. bytes ,
388+ None => return Err ( anyhow:: anyhow!( "kv: no blob" ) ) ,
389+ } ;
390+ Ok ( bytes)
391+ }
392+ KvResponse :: Err { 0 : error } => Err ( error. into ( ) ) ,
393+ _ => Err ( anyhow:: anyhow!( "kv: unexpected response {:?}" , response) ) ,
394+ }
395+ }
396+ _ => Err ( anyhow:: anyhow!( "kv: unexpected message: {:?}" , res) ) ,
397+ }
398+ }
399+
400+ /// Set raw bytes directly
401+ pub fn set_raw ( & self , key : & [ u8 ] , value : & [ u8 ] , tx_id : Option < u64 > ) -> anyhow:: Result < ( ) > {
402+ let res = Request :: new ( )
403+ . target ( ( "our" , "kv" , "distro" , "sys" ) )
404+ . body ( serde_json:: to_vec ( & KvRequest {
405+ package_id : self . package_id . clone ( ) ,
406+ db : self . db . clone ( ) ,
407+ action : KvAction :: Set {
408+ key : key. to_vec ( ) ,
409+ tx_id,
410+ } ,
411+ } ) ?)
412+ . blob_bytes ( value. to_vec ( ) )
413+ . send_and_await_response ( self . timeout ) ?;
414+
415+ match res {
416+ Ok ( Message :: Response { body, .. } ) => {
417+ let response = serde_json:: from_slice :: < KvResponse > ( & body) ?;
418+
419+ match response {
420+ KvResponse :: Ok => Ok ( ( ) ) ,
421+ KvResponse :: Err { 0 : error } => Err ( error. into ( ) ) ,
422+ _ => Err ( anyhow:: anyhow!( "kv: unexpected response {:?}" , response) ) ,
423+ }
424+ }
425+ _ => Err ( anyhow:: anyhow!( "kv: unexpected message: {:?}" , res) ) ,
426+ }
427+ }
428+
429+ /// Delete raw bytes directly
430+ pub fn delete_raw ( & self , key : & [ u8 ] , tx_id : Option < u64 > ) -> anyhow:: Result < ( ) > {
431+ let res = Request :: new ( )
432+ . target ( ( "our" , "kv" , "distro" , "sys" ) )
433+ . body ( serde_json:: to_vec ( & KvRequest {
434+ package_id : self . package_id . clone ( ) ,
435+ db : self . db . clone ( ) ,
436+ action : KvAction :: Delete {
437+ key : key. to_vec ( ) ,
438+ tx_id,
439+ } ,
440+ } ) ?)
441+ . send_and_await_response ( self . timeout ) ?;
442+
443+ match res {
444+ Ok ( Message :: Response { body, .. } ) => {
445+ let response = serde_json:: from_slice :: < KvResponse > ( & body) ?;
446+
447+ match response {
448+ KvResponse :: Ok => Ok ( ( ) ) ,
449+ KvResponse :: Err { 0 : error } => Err ( error. into ( ) ) ,
450+ _ => Err ( anyhow:: anyhow!( "kv: unexpected response {:?}" , response) ) ,
451+ }
452+ }
453+ _ => Err ( anyhow:: anyhow!( "kv: unexpected message: {:?}" , res) ) ,
454+ }
455+ }
456+ }
457+
458+ /// Helper function to open a raw bytes key-value store
459+ pub fn open_raw (
460+ package_id : PackageId ,
461+ db : & str ,
462+ timeout : Option < u64 > ,
463+ ) -> anyhow:: Result < Kv < Vec < u8 > , Vec < u8 > > > {
464+ open ( package_id, db, timeout)
465+ }
466+
309467/// Opens or creates a kv db.
310468pub fn open < K , V > ( package_id : PackageId , db : & str , timeout : Option < u64 > ) -> anyhow:: Result < Kv < K , V > >
311469where
0 commit comments