2626# ' @param resp,con A streaming [response] created by [req_perform_connection()].
2727# ' @param kb How many kilobytes (1024 bytes) of data to read.
2828# ' @order 1
29+ # ' @examples
30+ # ' req <- request(example_url()) |>
31+ # ' req_template("GET /stream/:n", n = 5)
32+ # '
33+ # ' con <- req |> req_perform_connection()
34+ # ' while (!resp_stream_is_complete(con)) {
35+ # ' lines <- con |> resp_stream_lines(2)
36+ # ' cat(length(lines), " lines received\n", sep = "")
37+ # ' }
38+ # ' close(con)
39+ # '
40+ # ' # You can also see what's happening by setting verbosity
41+ # ' con <- req |> req_perform_connection(verbosity = 2)
42+ # ' while (!resp_stream_is_complete(con)) {
43+ # ' lines <- con |> resp_stream_lines(2)
44+ # ' }
45+ # ' close(con)
2946resp_stream_raw <- function (resp , kb = 32 ) {
3047 check_streaming_response(resp )
3148 conn <- resp $ body
3249
33- readBin(conn , raw(), kb * 1024 )
50+ out <- readBin(conn , raw(), kb * 1024 )
51+ if (resp_stream_show_body(resp )) {
52+ log_stream(" Streamed " , length(out ), " bytes" )
53+ cli :: cat_line()
54+ }
55+ out
3456}
3557
3658# ' @export
@@ -57,12 +79,18 @@ resp_stream_lines <- function(resp, lines = 1, max_size = Inf, warn = TRUE) {
5779 line <- resp_stream_oneline(resp , max_size , warn , encoding )
5880 if (length(line ) == 0 ) {
5981 # No more data, either because EOF or req_perform_connection(blocking=FALSE).
60- # Either way, return what we have
61- return ( lines_read )
82+ # Either way we're done
83+ break
6284 }
6385 lines_read <- c(lines_read , line )
6486 lines <- lines - 1
6587 }
88+
89+ if (resp_stream_show_body(resp )) {
90+ log_stream(lines_read )
91+ cli :: cat_line()
92+ }
93+
6694 lines_read
6795}
6896
@@ -74,19 +102,25 @@ resp_stream_lines <- function(resp, lines = 1, max_size = Inf, warn = TRUE) {
74102# ' @order 1
75103resp_stream_sse <- function (resp , max_size = Inf ) {
76104 event_bytes <- resp_boundary_pushback(resp , max_size , find_event_boundary , include_trailer = FALSE )
77- if (! is.null(event_bytes )) {
78- parse_event(event_bytes )
79- } else {
80- return (NULL )
105+ if (is.null(event_bytes )) {
106+ return ()
107+ }
108+
109+ event <- parse_event(event_bytes )
110+ if (resp_stream_show_body(resp )) {
111+ for (key in names(event )) {
112+ log_stream(cli :: style_bold(key ), " : " , pretty_json(event [[key ]]))
113+ }
114+ cli :: cat_line()
81115 }
116+ event
82117}
83118
84119# ' @export
85120# ' @rdname resp_stream_raw
86121resp_stream_is_complete <- function (resp ) {
87122 check_response(resp )
88-
89- ! isIncomplete(resp $ body )
123+ length(resp $ cache $ push_back ) == 0 && ! isIncomplete(resp $ body )
90124}
91125
92126# ' @export
@@ -187,16 +221,16 @@ find_event_boundary <- function(buffer) {
187221
188222 boundary_end <- which(
189223 (left1 == 0x0A & buffer == 0x0A ) | # \n\n
190- (left1 == 0x0D & buffer == 0x0D ) | # \r\r
191- (left3 == 0x0D & left2 == 0x0A & left1 == 0x0D & buffer == 0x0A ) # \r\n\r\n
224+ (left1 == 0x0D & buffer == 0x0D ) | # \r\r
225+ (left3 == 0x0D & left2 == 0x0A & left1 == 0x0D & buffer == 0x0A ) # \r\n\r\n
192226 )
193227
194228 if (length(boundary_end ) == 0 ) {
195- return (NULL ) # No event boundary found
229+ return (NULL ) # No event boundary found
196230 }
197231
198- boundary_end <- boundary_end [1 ] # Take the first occurrence
199- split_at <- boundary_end + 1 # Split at one after the boundary
232+ boundary_end <- boundary_end [1 ] # Take the first occurrence
233+ split_at <- boundary_end + 1 # Split at one after the boundary
200234 split_at
201235}
202236
@@ -217,7 +251,7 @@ split_buffer <- function(buffer, split_at) {
217251# the vector
218252# @param include_trailer If TRUE, at the end of the response, if there are
219253# bytes after the last boundary, then return those bytes; if FALSE, then those
220- # bytes are silently discarded.
254+ # bytes are discarded with a warning .
221255resp_boundary_pushback <- function (resp , max_size , boundary_func , include_trailer ) {
222256 check_streaming_response(resp )
223257 check_number_whole(max_size , min = 1 , allow_infinite = TRUE )
@@ -228,8 +262,12 @@ resp_boundary_pushback <- function(resp, max_size, boundary_func, include_traile
228262 buffer <- resp $ cache $ push_back %|| % raw()
229263 resp $ cache $ push_back <- raw()
230264
231- print_buffer <- function (buf , label ) {
232- # cat(label, ":", paste(sprintf("%02X", as.integer(buf)), collapse = " "), "\n", file = stderr())
265+ if (resp_stream_show_buffer(resp )) {
266+ print_buffer <- function (buf , label ) {
267+ cli :: cat_line(" * " , label , " : " , paste(as.character(buf ), collapse = " " ))
268+ }
269+ } else {
270+ print_buffer <- function (buf , label ) {}
233271 }
234272
235273 # Read chunks until we find an event or reach the end of input
@@ -261,24 +299,27 @@ resp_boundary_pushback <- function(resp, max_size, boundary_func, include_traile
261299 # one extra byte so we know to error.
262300 n = min(chunk_size , max_size - length(buffer ) + 1 )
263301 )
264-
265302 print_buffer(chunk , " Received chunk" )
266303
267- # If we've reached the end of input, store the buffer and return NULL
268304 if (length(chunk ) == 0 ) {
269305 if (! isIncomplete(resp $ body )) {
270306 # We've truly reached the end of the connection; no more data is coming
271- if (include_trailer && length(buffer ) > 0 ) {
272- return (buffer )
273- } else {
307+ if (length(buffer ) == 0 ) {
274308 return (NULL )
309+ } else {
310+ if (include_trailer ) {
311+ return (buffer )
312+ } else {
313+ cli :: cli_warn(" Premature end of input; ignoring final partial chunk" )
314+ return (NULL )
315+ }
275316 }
317+ } else {
318+ # More data might come later; store the buffer and return NULL
319+ print_buffer(buffer , " Storing incomplete buffer" )
320+ resp $ cache $ push_back <- buffer
321+ return (NULL )
276322 }
277-
278- # More data might come later
279- print_buffer(buffer , " Storing incomplete buffer" )
280- resp $ cache $ push_back <- buffer
281- return (NULL )
282323 }
283324
284325 # More data was received; combine it with existing buffer and continue the
@@ -322,7 +363,6 @@ parse_event <- function(event_data) {
322363check_streaming_response <- function (resp ,
323364 arg = caller_arg(resp ),
324365 call = caller_env()) {
325-
326366 check_response(resp , arg = arg , call = call )
327367
328368 if (resp_body_type(resp ) != " stream" ) {
@@ -353,3 +393,10 @@ isValid <- function(con) {
353393 error = function (cnd ) FALSE
354394 )
355395}
396+
397+ resp_stream_show_body <- function (resp ) {
398+ resp $ request $ policies $ show_streaming_body %|| % FALSE
399+ }
400+ resp_stream_show_buffer <- function (resp ) {
401+ resp $ request $ policies $ show_streaming_buffer %|| % FALSE
402+ }
0 commit comments