1- use std:: { collections:: HashMap , path:: PathBuf } ;
1+ use std:: { collections:: HashMap , env , path:: PathBuf , time :: SystemTime } ;
22
33use magnus:: {
44 eval, exception, function, method,
@@ -8,6 +8,7 @@ use magnus::{
88} ;
99use structopt:: StructOpt ;
1010use wizer:: Wizer ;
11+ use wasi_virt;
1112
1213static RUBY_WASM : value:: Lazy < RModule > =
1314 value:: Lazy :: new ( |ruby| ruby. define_module ( "RubyWasmExt" ) . unwrap ( ) ) ;
@@ -222,6 +223,99 @@ impl ComponentEncode {
222223 }
223224}
224225
226+ #[ wrap( class = "RubyWasmExt::WasiVirt" ) ]
227+ struct WasiVirt ( std:: cell:: RefCell < Option < wasi_virt:: WasiVirt > > ) ;
228+
229+ impl WasiVirt {
230+ fn new ( ) -> Self {
231+ Self ( std:: cell:: RefCell :: new ( Some ( wasi_virt:: WasiVirt :: new ( ) ) ) )
232+ }
233+
234+ fn virt < R > (
235+ & self ,
236+ body : impl FnOnce ( & mut wasi_virt:: WasiVirt ) -> Result < R , Error > ,
237+ ) -> Result < R , Error > {
238+ let mut virt = self . 0 . take ( ) . ok_or_else ( || {
239+ Error :: new (
240+ exception:: standard_error ( ) ,
241+ "wasi virt is already consumed" . to_string ( ) ,
242+ )
243+ } ) ?;
244+ let result = body ( & mut virt) ?;
245+ self . 0 . replace ( Some ( virt) ) ;
246+ Ok ( result)
247+ }
248+
249+ fn allow_all ( & self ) -> Result < ( ) , Error > {
250+ self . virt ( |virt| {
251+ virt. allow_all ( ) ;
252+ // Disable sockets for now since `sockets/ip-name-lookup` is not
253+ // supported by @bytecodealliance/preview2-shim yet
254+ virt. sockets ( false ) ;
255+ Ok ( ( ) )
256+ } )
257+ }
258+
259+ fn map_dir ( & self , guest_dir : String , host_dir : String ) -> Result < ( ) , Error > {
260+ self . virt ( |virt| {
261+ virt. fs ( ) . virtual_preopen ( guest_dir, host_dir) ;
262+ Ok ( ( ) )
263+ } )
264+ }
265+
266+ fn finish ( & self ) -> Result < bytes:: Bytes , Error > {
267+ self . virt ( |virt| {
268+ let result = virt. finish ( ) . map_err ( |e| {
269+ Error :: new (
270+ exception:: standard_error ( ) ,
271+ format ! ( "failed to generate virtualization adapter: {}" , e) ,
272+ )
273+ } ) ?;
274+ Ok ( result. adapter . into ( ) )
275+ } )
276+ }
277+
278+ fn compose ( & self , component_bytes : bytes:: Bytes ) -> Result < bytes:: Bytes , Error > {
279+ let virt_adapter = self . finish ( ) ?;
280+ let tmpdir = env:: temp_dir ( ) ;
281+ let tmp_virt = tmpdir. join ( format ! ( "virt{}.wasm" , timestamp( ) ) ) ;
282+ std:: fs:: write ( & tmp_virt, & virt_adapter) . map_err ( |e| {
283+ Error :: new (
284+ exception:: standard_error ( ) ,
285+ format ! ( "failed to write virt adapter: {}" , e) ,
286+ )
287+ } ) ?;
288+ let tmp_component = tmpdir. join ( format ! ( "component{}.wasm" , timestamp( ) ) ) ;
289+ std:: fs:: write ( & tmp_component, & component_bytes) . map_err ( |e| {
290+ Error :: new (
291+ exception:: standard_error ( ) ,
292+ format ! ( "failed to write component: {}" , e) ,
293+ )
294+ } ) ?;
295+
296+ use wasm_compose:: { composer, config} ;
297+ let config = config:: Config {
298+ definitions : vec ! [ tmp_virt] ,
299+ ..Default :: default ( )
300+ } ;
301+ let composer = composer:: ComponentComposer :: new ( & tmp_component, & config) ;
302+ let composed = composer. compose ( ) . map_err ( |e| {
303+ Error :: new (
304+ exception:: standard_error ( ) ,
305+ format ! ( "failed to compose component: {}" , e) ,
306+ )
307+ } ) ?;
308+ return Ok ( composed. into ( ) ) ;
309+
310+ fn timestamp ( ) -> u64 {
311+ match SystemTime :: now ( ) . duration_since ( SystemTime :: UNIX_EPOCH ) {
312+ Ok ( n) => n. as_secs ( ) ,
313+ Err ( _) => panic ! ( ) ,
314+ }
315+ }
316+ }
317+ }
318+
225319#[ magnus:: init]
226320fn init ( ruby : & Ruby ) -> Result < ( ) , Error > {
227321 let module = RUBY_WASM . get_inner_with ( ruby) ;
@@ -266,5 +360,12 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
266360 ) ?;
267361 component_encode. define_method ( "encode" , method ! ( ComponentEncode :: encode, 0 ) ) ?;
268362
363+ let wasi_virt = module. define_class ( "WasiVirt" , ruby. class_object ( ) ) ?;
364+ wasi_virt. define_singleton_method ( "new" , function ! ( WasiVirt :: new, 0 ) ) ?;
365+ wasi_virt. define_method ( "allow_all" , method ! ( WasiVirt :: allow_all, 0 ) ) ?;
366+ wasi_virt. define_method ( "map_dir" , method ! ( WasiVirt :: map_dir, 2 ) ) ?;
367+ wasi_virt. define_method ( "finish" , method ! ( WasiVirt :: finish, 0 ) ) ?;
368+ wasi_virt. define_method ( "compose" , method ! ( WasiVirt :: compose, 1 ) ) ?;
369+
269370 Ok ( ( ) )
270371}
0 commit comments