@@ -2,6 +2,7 @@ use anyhow::{Context, Result};
22use spin_core:: { async_trait, wasmtime:: component:: Resource } ;
33use spin_resource_table:: Table ;
44use spin_world:: v2:: key_value;
5+ use spin_world:: wasi:: keyvalue as wasi_keyvalue;
56use std:: { collections:: HashSet , sync:: Arc } ;
67use tracing:: { instrument, Level } ;
78
@@ -55,13 +56,22 @@ impl KeyValueDispatch {
5556 }
5657 }
5758
58- pub fn get_store ( & self , store : Resource < key_value :: Store > ) -> anyhow:: Result < & Arc < dyn Store > > {
59+ pub fn get_store < T : ' static > ( & self , store : Resource < T > ) -> anyhow:: Result < & Arc < dyn Store > > {
5960 self . stores . get ( store. rep ( ) ) . context ( "invalid store" )
6061 }
6162
6263 pub fn allowed_stores ( & self ) -> & HashSet < String > {
6364 & self . allowed_stores
6465 }
66+
67+ pub fn get_store_wasi < T : ' static > (
68+ & self ,
69+ store : Resource < T > ,
70+ ) -> Result < & Arc < dyn Store > , wasi_keyvalue:: store:: Error > {
71+ self . stores
72+ . get ( store. rep ( ) )
73+ . ok_or ( wasi_keyvalue:: store:: Error :: NoSuchStore )
74+ }
6575}
6676
6777#[ async_trait]
@@ -141,6 +151,102 @@ impl key_value::HostStore for KeyValueDispatch {
141151 }
142152}
143153
154+ fn to_wasi_err ( e : Error ) -> wasi_keyvalue:: store:: Error {
155+ match e {
156+ Error :: AccessDenied => wasi_keyvalue:: store:: Error :: AccessDenied ,
157+ Error :: NoSuchStore => wasi_keyvalue:: store:: Error :: NoSuchStore ,
158+ Error :: StoreTableFull => wasi_keyvalue:: store:: Error :: Other ( "store table full" . to_string ( ) ) ,
159+ Error :: Other ( msg) => wasi_keyvalue:: store:: Error :: Other ( msg) ,
160+ }
161+ }
162+
163+ #[ async_trait]
164+ impl wasi_keyvalue:: store:: Host for KeyValueDispatch {
165+ async fn open (
166+ & mut self ,
167+ identifier : String ,
168+ ) -> Result < Resource < wasi_keyvalue:: store:: Bucket > , wasi_keyvalue:: store:: Error > {
169+ if self . allowed_stores . contains ( & identifier) {
170+ let store = self
171+ . stores
172+ . push ( self . manager . get ( & identifier) . await . map_err ( to_wasi_err) ?)
173+ . map_err ( |( ) | wasi_keyvalue:: store:: Error :: Other ( "store table full" . to_string ( ) ) ) ?;
174+ Ok ( Resource :: new_own ( store) )
175+ } else {
176+ Err ( wasi_keyvalue:: store:: Error :: AccessDenied )
177+ }
178+ }
179+
180+ fn convert_error (
181+ & mut self ,
182+ error : spin_world:: wasi:: keyvalue:: store:: Error ,
183+ ) -> std:: result:: Result < spin_world:: wasi:: keyvalue:: store:: Error , anyhow:: Error > {
184+ Ok ( error)
185+ }
186+ }
187+
188+ use wasi_keyvalue:: store:: Bucket ;
189+ #[ async_trait]
190+ impl wasi_keyvalue:: store:: HostBucket for KeyValueDispatch {
191+ async fn get (
192+ & mut self ,
193+ self_ : Resource < Bucket > ,
194+ key : String ,
195+ ) -> Result < Option < Vec < u8 > > , wasi_keyvalue:: store:: Error > {
196+ let store = self . get_store_wasi ( self_) ?;
197+ store. get ( & key) . await . map_err ( to_wasi_err)
198+ }
199+
200+ async fn set (
201+ & mut self ,
202+ self_ : Resource < Bucket > ,
203+ key : String ,
204+ value : Vec < u8 > ,
205+ ) -> Result < ( ) , wasi_keyvalue:: store:: Error > {
206+ let store = self . get_store_wasi ( self_) ?;
207+ store. set ( & key, & value) . await . map_err ( to_wasi_err)
208+ }
209+
210+ async fn delete (
211+ & mut self ,
212+ self_ : Resource < Bucket > ,
213+ key : String ,
214+ ) -> Result < ( ) , wasi_keyvalue:: store:: Error > {
215+ let store = self . get_store_wasi ( self_) ?;
216+ store. delete ( & key) . await . map_err ( to_wasi_err)
217+ }
218+
219+ async fn exists (
220+ & mut self ,
221+ self_ : Resource < Bucket > ,
222+ key : String ,
223+ ) -> Result < bool , wasi_keyvalue:: store:: Error > {
224+ let store = self . get_store_wasi ( self_) ?;
225+ store. exists ( & key) . await . map_err ( to_wasi_err)
226+ }
227+
228+ async fn list_keys (
229+ & mut self ,
230+ self_ : Resource < Bucket > ,
231+ cursor : Option < u64 > ,
232+ ) -> Result < wasi_keyvalue:: store:: KeyResponse , wasi_keyvalue:: store:: Error > {
233+ if cursor. unwrap_or_default ( ) != 0 {
234+ return Err ( wasi_keyvalue:: store:: Error :: Other (
235+ "list_keys: cursor not supported" . to_owned ( ) ,
236+ ) ) ;
237+ }
238+
239+ let store = self . get_store_wasi ( self_) ?;
240+ let keys = store. get_keys ( ) . await . map_err ( to_wasi_err) ?;
241+ Ok ( wasi_keyvalue:: store:: KeyResponse { keys, cursor : None } )
242+ }
243+
244+ async fn drop ( & mut self , rep : Resource < Bucket > ) -> anyhow:: Result < ( ) > {
245+ self . stores . remove ( rep. rep ( ) ) ;
246+ Ok ( ( ) )
247+ }
248+ }
249+
144250pub fn log_error ( err : impl std:: fmt:: Debug ) -> Error {
145251 tracing:: warn!( "key-value error: {err:?}" ) ;
146252 Error :: Other ( format ! ( "{err:?}" ) )
0 commit comments