1
- use bytes:: Bytes ;
2
- use http_body_util:: { combinators:: BoxBody , BodyExt , Empty , Full } ;
3
- use hyper:: { body:: Incoming , service:: Service , Request , Response } ;
4
- use hyper_util:: { rt:: TokioIo , server:: conn:: auto} ;
1
+ use std:: convert:: Infallible ;
2
+ use std:: future:: Future ;
3
+ use std:: net:: SocketAddr ;
4
+ use std:: rc:: Rc ;
5
+
6
+ use futures:: future:: LocalBoxFuture ;
7
+ use http_body_util:: { combinators:: BoxBody , BodyExt as _, Empty , Full } ;
8
+ use hyper:: body:: { Bytes , Incoming } ;
9
+ use hyper:: { Request , Response } ;
10
+ use hyper_util:: rt:: TokioIo ;
11
+ use hyper_util:: server:: conn:: auto:: Builder as ServerConnBuilder ;
12
+ use tokio:: net:: TcpListener ;
13
+ use tokio:: task:: LocalSet ;
14
+
5
15
use mlua:: {
6
- chunk, Error as LuaError , Function , Lua , String as LuaString , Table , UserData , UserDataMethods ,
16
+ chunk, Error as LuaError , Function , Lua , RegistryKey , String as LuaString , Table , UserData ,
17
+ UserDataMethods ,
7
18
} ;
8
- use std:: { future:: Future , net:: SocketAddr , pin:: Pin , rc:: Rc } ;
9
- use tokio:: { net:: TcpListener , task:: LocalSet } ;
10
19
20
+ /// Wrapper around incoming request that implements UserData
11
21
struct LuaRequest ( SocketAddr , Request < Incoming > ) ;
12
22
13
23
impl UserData for LuaRequest {
14
24
fn add_methods < ' lua , M : UserDataMethods < ' lua , Self > > ( methods : & mut M ) {
15
- methods. add_method ( "remote_addr" , |_lua, req, ( ) | Ok ( ( req. 0 ) . to_string ( ) ) ) ;
16
- methods. add_method ( "method" , |_lua, req, ( ) | Ok ( ( req. 1 ) . method ( ) . to_string ( ) ) ) ;
25
+ methods. add_method ( "remote_addr" , |_, req, ( ) | Ok ( ( req. 0 ) . to_string ( ) ) ) ;
26
+ methods. add_method ( "method" , |_, req, ( ) | Ok ( ( req. 1 ) . method ( ) . to_string ( ) ) ) ;
27
+ methods. add_method ( "path" , |_, req, ( ) | Ok ( req. 1 . uri ( ) . path ( ) . to_string ( ) ) ) ;
17
28
}
18
29
}
19
30
20
- pub struct Svc ( Rc < Lua > , SocketAddr ) ;
31
+ /// Service that handles incoming requests
32
+ #[ derive( Clone ) ]
33
+ pub struct Svc {
34
+ lua : Rc < Lua > ,
35
+ handler : Rc < RegistryKey > ,
36
+ peer_addr : SocketAddr ,
37
+ }
38
+
39
+ impl Svc {
40
+ pub fn new ( lua : Rc < Lua > , handler : Rc < RegistryKey > , peer_addr : SocketAddr ) -> Self {
41
+ Self {
42
+ lua,
43
+ handler,
44
+ peer_addr,
45
+ }
46
+ }
47
+ }
21
48
22
- impl Service < Request < Incoming > > for Svc {
23
- type Response = Response < BoxBody < Bytes , hyper :: Error > > ;
49
+ impl hyper :: service :: Service < Request < Incoming > > for Svc {
50
+ type Response = Response < BoxBody < Bytes , Infallible > > ;
24
51
type Error = LuaError ;
25
- type Future = Pin < Box < dyn Future < Output = Result < Self :: Response , Self :: Error > > > > ;
52
+ type Future = LocalBoxFuture < ' static , Result < Self :: Response , Self :: Error > > ;
26
53
27
54
fn call ( & self , req : Request < Incoming > ) -> Self :: Future {
28
55
// If handler returns an error then generate 5xx response
29
- let lua = self . 0 . clone ( ) ;
30
- let lua_req = LuaRequest ( self . 1 , req) ;
56
+ let lua = self . lua . clone ( ) ;
57
+ let handler_key = self . handler . clone ( ) ;
58
+ let lua_req = LuaRequest ( self . peer_addr , req) ;
31
59
Box :: pin ( async move {
32
- let handler: Function = lua. named_registry_value ( "http_handler" ) ?;
60
+ let handler: Function = lua. registry_value ( & handler_key ) ?;
33
61
match handler. call_async :: < _ , Table > ( lua_req) . await {
34
62
Ok ( lua_resp) => {
35
63
let status = lua_resp. get :: < _ , Option < u16 > > ( "status" ) ?. unwrap_or ( 200 ) ;
@@ -43,30 +71,19 @@ impl Service<Request<Incoming>> for Svc {
43
71
}
44
72
}
45
73
74
+ // Set body
46
75
let body = lua_resp
47
76
. get :: < _ , Option < LuaString > > ( "body" ) ?
48
- . map ( |b| {
49
- Full :: new ( Bytes :: copy_from_slice ( b. clone ( ) . as_bytes ( ) ) )
50
- . map_err ( |never| match never { } )
51
- . boxed ( )
52
- } )
53
- . unwrap_or_else ( || {
54
- Empty :: < Bytes > :: new ( )
55
- . map_err ( |never| match never { } )
56
- . boxed ( )
57
- } ) ;
77
+ . map ( |b| Full :: new ( Bytes :: copy_from_slice ( b. as_bytes ( ) ) ) . boxed ( ) )
78
+ . unwrap_or_else ( || Empty :: < Bytes > :: new ( ) . boxed ( ) ) ;
58
79
59
80
Ok ( resp. body ( body) . unwrap ( ) )
60
81
}
61
82
Err ( err) => {
62
83
eprintln ! ( "{}" , err) ;
63
84
Ok ( Response :: builder ( )
64
85
. status ( 500 )
65
- . body (
66
- Full :: new ( Bytes :: from ( "Internal Server Error" . as_bytes ( ) ) )
67
- . map_err ( |never| match never { } )
68
- . boxed ( ) ,
69
- )
86
+ . body ( Full :: new ( Bytes :: from ( "Internal Server Error" ) ) . boxed ( ) )
70
87
. unwrap ( ) )
71
88
}
72
89
}
@@ -79,43 +96,47 @@ async fn main() {
79
96
let lua = Rc :: new ( Lua :: new ( ) ) ;
80
97
81
98
// Create Lua handler function
82
- let handler: Function = lua
99
+ let handler: RegistryKey = lua
83
100
. load ( chunk ! {
84
- function( req)
85
- return {
86
- status = 200 ,
87
- headers = {
88
- [ "X-Req-Method" ] = req: method( ) ,
89
- [ "X-Remote-Addr" ] = req: remote_addr( ) ,
90
- } ,
91
- body = "Hello from Lua!\n "
92
- }
93
- end
101
+ function( req)
102
+ return {
103
+ status = 200 ,
104
+ headers = {
105
+ [ "X-Req-Method" ] = req: method( ) ,
106
+ [ "X-Req-Path" ] = req: path( ) ,
107
+ [ "X-Remote-Addr" ] = req: remote_addr( ) ,
108
+ } ,
109
+ body = "Hello from Lua!\n "
110
+ }
111
+ end
94
112
} )
95
113
. eval ( )
96
- . expect ( "cannot create Lua handler" ) ;
114
+ . expect ( "Failed to create Lua handler" ) ;
115
+ let handler = Rc :: new ( handler) ;
97
116
98
- // Store it in the Registry
99
- lua. set_named_registry_value ( "http_handler" , handler)
100
- . expect ( "cannot store Lua handler" ) ;
101
-
102
- let addr = "127.0.0.1:3000" ;
117
+ let listen_addr = "127.0.0.1:3000" ;
118
+ let listener = TcpListener :: bind ( listen_addr) . await . unwrap ( ) ;
119
+ println ! ( "Listening on http://{listen_addr}" ) ;
103
120
104
121
let local = LocalSet :: new ( ) ;
105
- let listener = TcpListener :: bind ( addr) . await . unwrap ( ) ;
106
122
loop {
107
- let ( stream, peer_addr) = listener. accept ( ) . await . unwrap ( ) ;
108
- let io = TokioIo :: new ( stream) ;
123
+ let ( stream, peer_addr) = match listener. accept ( ) . await {
124
+ Ok ( x) => x,
125
+ Err ( err) => {
126
+ eprintln ! ( "Failed to accept connection: {err}" ) ;
127
+ continue ;
128
+ }
129
+ } ;
109
130
110
- let svc = Svc ( lua. clone ( ) , peer_addr) ;
131
+ let svc = Svc :: new ( lua. clone ( ) , handler . clone ( ) , peer_addr) ;
111
132
local
112
133
. run_until ( async move {
113
- if let Err ( err ) = auto :: Builder :: new ( LocalExec )
134
+ let result = ServerConnBuilder :: new ( LocalExec )
114
135
. http1 ( )
115
- . serve_connection ( io , svc)
116
- . await
117
- {
118
- println ! ( "Error serving connection: {:?}" , err ) ;
136
+ . serve_connection ( TokioIo :: new ( stream ) , svc)
137
+ . await ;
138
+ if let Err ( err ) = result {
139
+ eprintln ! ( "Error serving connection: {err :?}" ) ;
119
140
}
120
141
} )
121
142
. await ;
@@ -127,7 +148,7 @@ struct LocalExec;
127
148
128
149
impl < F > hyper:: rt:: Executor < F > for LocalExec
129
150
where
130
- F : std :: future :: Future + ' static , // not requiring `Send`
151
+ F : Future + ' static , // not requiring `Send`
131
152
{
132
153
fn execute ( & self , fut : F ) {
133
154
tokio:: task:: spawn_local ( fut) ;
0 commit comments