1
+ use crate :: replication:: { frame:: Frame , primary:: frame_stream:: FrameStream , ReplicationLogger } ;
1
2
use crate :: Auth ;
2
3
use anyhow:: { Context , Result } ;
3
4
use hyper:: server:: conn:: AddrIncoming ;
@@ -9,7 +10,11 @@ use tower_http::trace::DefaultOnResponse;
9
10
use tower_http:: { compression:: CompressionLayer , cors} ;
10
11
use tracing:: { Level , Span } ;
11
12
12
- pub ( crate ) async fn run ( auth : Arc < Auth > , addr : SocketAddr ) -> Result < ( ) > {
13
+ pub ( crate ) async fn run (
14
+ auth : Arc < Auth > ,
15
+ addr : SocketAddr ,
16
+ logger : Arc < ReplicationLogger > ,
17
+ ) -> Result < ( ) > {
13
18
tracing:: info!( "listening for HTTP requests on {addr}" ) ;
14
19
15
20
fn trace_request < B > ( req : & Request < B > , _span : & Span ) {
@@ -34,7 +39,8 @@ pub(crate) async fn run(auth: Arc<Auth>, addr: SocketAddr) -> Result<()> {
34
39
)
35
40
. service_fn ( move |req| {
36
41
let auth = auth. clone ( ) ;
37
- handle_request ( auth, req)
42
+ let logger = logger. clone ( ) ;
43
+ handle_request ( auth, req, logger)
38
44
} ) ;
39
45
40
46
let listener = tokio:: net:: TcpListener :: bind ( & addr) . await ?;
@@ -47,7 +53,11 @@ pub(crate) async fn run(auth: Arc<Auth>, addr: SocketAddr) -> Result<()> {
47
53
Ok ( ( ) )
48
54
}
49
55
50
- async fn handle_request ( auth : Arc < Auth > , req : Request < Body > ) -> Result < Response < Body > > {
56
+ async fn handle_request (
57
+ auth : Arc < Auth > ,
58
+ req : Request < Body > ,
59
+ logger : Arc < ReplicationLogger > ,
60
+ ) -> Result < Response < Body > > {
51
61
let auth_header = req. headers ( ) . get ( hyper:: header:: AUTHORIZATION ) ;
52
62
let auth = match auth. authenticate_http ( auth_header) {
53
63
Ok ( auth) => auth,
@@ -60,7 +70,7 @@ async fn handle_request(auth: Arc<Auth>, req: Request<Body>) -> Result<Response<
60
70
} ;
61
71
62
72
match ( req. method ( ) , req. uri ( ) . path ( ) ) {
63
- ( & Method :: POST , "/frames" ) => handle_query ( req, auth) . await ,
73
+ ( & Method :: POST , "/frames" ) => handle_query ( req, auth, logger ) . await ,
64
74
_ => Ok ( Response :: builder ( ) . status ( 404 ) . body ( Body :: empty ( ) ) . unwrap ( ) ) ,
65
75
}
66
76
}
@@ -70,6 +80,25 @@ pub struct FramesRequest {
70
80
pub next_offset : u64 ,
71
81
}
72
82
83
+ #[ derive( Debug , serde:: Deserialize , serde:: Serialize ) ]
84
+ pub struct Frames {
85
+ pub frames : Vec < Frame > ,
86
+ }
87
+
88
+ impl Frames {
89
+ pub fn new ( ) -> Self {
90
+ Self { frames : Vec :: new ( ) }
91
+ }
92
+
93
+ pub fn push ( & mut self , frame : Frame ) {
94
+ self . frames . push ( frame) ;
95
+ }
96
+
97
+ pub fn is_empty ( & self ) -> bool {
98
+ self . frames . is_empty ( )
99
+ }
100
+ }
101
+
73
102
fn error ( msg : & str , code : hyper:: StatusCode ) -> Response < Body > {
74
103
let err = serde_json:: json!( { "error" : msg } ) ;
75
104
Response :: builder ( )
@@ -81,18 +110,58 @@ fn error(msg: &str, code: hyper::StatusCode) -> Response<Body> {
81
110
async fn handle_query (
82
111
mut req : Request < Body > ,
83
112
_auth : crate :: auth:: Authenticated ,
113
+ logger : Arc < ReplicationLogger > ,
84
114
) -> Result < Response < Body > > {
85
115
let bytes = hyper:: body:: to_bytes ( req. body_mut ( ) ) . await ?;
86
116
let FramesRequest { next_offset } = match serde_json:: from_slice ( & bytes) {
87
117
Ok ( req) => req,
88
118
Err ( resp) => return Ok ( error ( & resp. to_string ( ) , hyper:: StatusCode :: BAD_REQUEST ) ) ,
89
119
} ;
90
120
121
+ let mut frame_stream = FrameStream :: new ( logger, next_offset) ;
122
+
123
+ if frame_stream. max_available_frame_no < next_offset {
124
+ tracing:: trace!( "No frames available starting {next_offset}, returning 204 No Content" ) ;
125
+ return Ok ( Response :: builder ( )
126
+ . status ( hyper:: StatusCode :: NO_CONTENT )
127
+ . body ( Body :: empty ( ) )
128
+ . unwrap ( ) ) ;
129
+ }
130
+
131
+ let mut frames = Frames :: new ( ) ;
132
+ loop {
133
+ use futures:: StreamExt ;
134
+
135
+ match frame_stream. next ( ) . await {
136
+ Some ( Ok ( frame) ) => {
137
+ tracing:: trace!( "Read frame {}" , frame_stream. current_frame_no) ;
138
+ frames. push ( frame) ;
139
+ }
140
+ Some ( Err ( e) ) => {
141
+ tracing:: error!( "Error reading frame: {}" , e) ;
142
+ return Ok ( Response :: builder ( )
143
+ . status ( hyper:: StatusCode :: INTERNAL_SERVER_ERROR )
144
+ . body ( Body :: empty ( ) )
145
+ . unwrap ( ) ) ;
146
+ }
147
+ None => break ,
148
+ }
149
+
150
+ // FIXME: also stop when we have enough frames to fill a large buffer
151
+ if frame_stream. max_available_frame_no <= frame_stream. current_frame_no {
152
+ break ;
153
+ }
154
+ }
155
+
156
+ if frames. is_empty ( ) {
157
+ return Ok ( Response :: builder ( )
158
+ . status ( hyper:: StatusCode :: NO_CONTENT )
159
+ . body ( Body :: empty ( ) )
160
+ . unwrap ( ) ) ;
161
+ }
162
+
91
163
Ok ( Response :: builder ( )
92
164
. status ( hyper:: StatusCode :: OK )
93
- . body ( Body :: from ( format ! (
94
- "{{\" comment\" :\" thx for sending the request\" , \" next_offset\" :{}}}" ,
95
- next_offset + 1
96
- ) ) )
165
+ . body ( Body :: from ( serde_json:: to_string ( & frames) ?) )
97
166
. unwrap ( ) )
98
167
}
0 commit comments