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