11use std:: { collections:: HashMap } ;
2- use std:: sync:: { Arc , RwLock } ;
32
43use cap_std:: fs:: Dir ;
54use hyper:: {
@@ -16,6 +15,7 @@ use crate::dispatcher::RoutePattern;
1615use crate :: http_util:: { internal_error, parse_cgi_headers} ;
1716use crate :: request:: { RequestContext , RequestGlobalContext } ;
1817
18+ use crate :: stream_writer:: StreamWriter ;
1919use crate :: wasm_module:: WasmModuleSource ;
2020use crate :: wasm_runner:: { prepare_stdio_streams_for_http, prepare_wasm_instance, run_prepared_wasm_instance} ;
2121
@@ -36,7 +36,7 @@ pub struct WasmRouteHandler {
3636}
3737
3838impl WasmRouteHandler {
39- pub fn handle_request (
39+ pub async fn handle_request (
4040 & self ,
4141 matched_route : & RoutePattern ,
4242 req : & Parts ,
@@ -45,7 +45,25 @@ impl WasmRouteHandler {
4545 global_context : & RequestGlobalContext ,
4646 logging_key : String ,
4747 ) -> Result < Response < Body > , anyhow:: Error > {
48+
49+ // These broken-out functions are slightly artificial but help solve some lifetime
50+ // issues (where otherwise you get errors about things not being Send across an
51+ // await).
52+ let ( stream_writer, instance, store) =
53+ self . set_up_runtime_environment ( matched_route, req, request_body, request_context, global_context, logging_key) ?;
54+ self . spawn_wasm_instance ( instance, store, stream_writer. clone ( ) ) ;
55+
56+ let response = compose_response ( stream_writer) . await ?; // TODO: handle errors
57+
58+ // TODO: c'mon man
59+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_micros ( 1 ) ) . await ;
60+
61+ Ok ( response)
62+ }
63+
64+ fn set_up_runtime_environment ( & self , matched_route : & RoutePattern , req : & Parts , request_body : Vec < u8 > , request_context : & RequestContext , global_context : & RequestGlobalContext , logging_key : String ) -> anyhow:: Result < ( crate :: stream_writer:: StreamWriter , Instance , Store < WasiCtx > ) > {
4865 let startup_span = tracing:: info_span!( "module instantiation" ) . entered ( ) ;
66+
4967 let headers = crate :: http_util:: build_headers (
5068 matched_route,
5169 req,
@@ -57,33 +75,25 @@ impl WasmRouteHandler {
5775 ) ;
5876
5977 let stream_writer = crate :: stream_writer:: StreamWriter :: new ( ) ;
60-
6178 let redirects = prepare_stdio_streams_for_http ( request_body, stream_writer. clone ( ) , global_context, logging_key) ?;
62-
6379 let ctx = self . build_wasi_context_for_request ( req, headers, redirects. streams ) ?;
64-
6580 let ( store, instance) = self . prepare_wasm_instance ( global_context, ctx) ?;
66-
67- // Drop manually to get instantiation time
81+
6882 drop ( startup_span) ;
83+
84+ Ok ( ( stream_writer, instance, store) )
85+ }
6986
87+ fn spawn_wasm_instance ( & self , instance : Instance , store : Store < WasiCtx > , mut stream_writer : StreamWriter ) {
7088 let entrypoint = self . entrypoint . clone ( ) ;
7189 let wasm_module_name = self . wasm_module_name . clone ( ) ;
72- let mut sw = stream_writer . clone ( ) ;
90+
7391 tokio:: spawn ( async move {
7492 match run_prepared_wasm_instance ( instance, store, & entrypoint, & wasm_module_name) {
75- Ok ( ( ) ) => sw . done ( ) . unwrap ( ) , // TODO: <--
93+ Ok ( ( ) ) => stream_writer . done ( ) . unwrap ( ) , // TODO: <--
7694 Err ( e) => tracing:: error!( "oh no {}" , e) , // TODO: behaviour? message? MESSAGE, IVAN?!
7795 } ;
7896 } ) ;
79-
80- let response = Response :: new ( Body :: wrap_stream ( stream_writer. as_stream ( ) ) ) ;
81- // TODO: c'mon man
82- std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) ;
83-
84- // TODO: headers headers headers
85-
86- Ok ( response)
8797 }
8898
8999 fn build_wasi_context_for_request ( & self , req : & Parts , headers : HashMap < String , String > , redirects : crate :: wasm_module:: IOStreamRedirects < crate :: stream_writer:: StreamWriter > ) -> Result < WasiCtx , Error > {
@@ -132,34 +142,12 @@ impl WasmRouteHandler {
132142 }
133143}
134144
135- pub fn compose_response ( stdout_mutex : Arc < RwLock < Vec < u8 > > > ) -> Result < Response < Body > , Error > {
136- // Okay, once we get here, all the information we need to send back in the response
137- // should be written to the STDOUT buffer. We fetch that, format it, and send
138- // it back. In the process, we might need to alter the status code of the result.
139- //
140- // This is a little janky, but basically we are looping through the output once,
141- // looking for the double-newline that distinguishes the headers from the body.
142- // The headers can then be parsed separately, while the body can be sent back
143- // to the client.
144-
145- let out = stdout_mutex. read ( ) . unwrap ( ) ;
146- let mut last = 0 ;
147- let mut scan_headers = true ;
148- let mut buffer: Vec < u8 > = Vec :: new ( ) ;
149- let mut out_headers: Vec < u8 > = Vec :: new ( ) ;
150- out. iter ( ) . for_each ( |i| {
151- if scan_headers && * i == 10 && last == 10 {
152- out_headers. append ( & mut buffer) ;
153- buffer = Vec :: new ( ) ;
154- scan_headers = false ;
155- return ; // Consume the linefeed
156- }
157- last = * i;
158- buffer. push ( * i)
159- } ) ;
160- let mut res = Response :: new ( Body :: from ( buffer) ) ;
145+ pub async fn compose_response ( mut stream_writer : StreamWriter ) -> anyhow:: Result < Response < Body > > {
146+ let header_block = stream_writer. header_block ( ) . await ?;
147+ let mut res = Response :: new ( Body :: wrap_stream ( stream_writer. as_stream ( ) ) ) ;
148+
161149 let mut sufficient_response = false ;
162- parse_cgi_headers ( String :: from_utf8 ( out_headers ) ?)
150+ parse_cgi_headers ( String :: from_utf8 ( header_block ) ?)
163151 . iter ( )
164152 . for_each ( |h| {
165153 use hyper:: header:: { CONTENT_TYPE , LOCATION } ;
0 commit comments