-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.Rmd
132 lines (97 loc) · 3.85 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# SSEparser
<!-- badges: start -->
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)
[![CRAN status](https://www.r-pkg.org/badges/version/SSEparser)](https://CRAN.R-project.org/package=SSEparser)
[![R-CMD-check](https://github.com/calderonsamuel/SSEparser/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/calderonsamuel/SSEparser/actions/workflows/R-CMD-check.yaml)
[![Codecov test coverage](https://codecov.io/gh/calderonsamuel/SSEparser/branch/main/graph/badge.svg)](https://app.codecov.io/gh/calderonsamuel/SSEparser?branch=main)
[![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/last-month/SSEparser?color=blue)](https://r-pkg.org/pkg/SSEparser)
<!-- badges: end -->
The goal of SSEparser is to provide robust functionality to parse Server-Sent Events and to build on top of it.
## Installation
You can install `SEEparser` from CRAN like so:
```r
install.packages("SSEparser")
```
Alternatively, you can install the development version like so:
``` r
pak::pak("calderonsamuel/SSEparser")
```
## Example
The `parse_sse()` function takes a string containing a server-sent event and converts it to a R list.
```{r example}
library(SSEparser)
event <- "data: test\nevent: message\nid: 123\n\n"
parse_sse(event)
```
Comments are usually received in a line starting with a colon. They are not parsed.
```{r}
with_comment <- "data: test\n: comment\nevent: example\n\n"
parse_sse(with_comment)
```
## Use in HTTP requests
`parse_sse()` wraps the `SSEparser` R6 class, which is also exported to be used with real-time streaming data. The following code handles a request with MIME type "text/event-stream".
```{r}
parser <- SSEparser$new()
response <- httr2::request("https://postman-echo.com/server-events/3") %>%
httr2::req_body_json(data = list(
event = "message",
request = "POST"
)) %>%
httr2::req_perform_stream(callback = \(x) {
event <- rawToChar(x)
parser$parse_sse(event)
TRUE
})
str(parser$events)
```
## Extending SSEparser
Following the previous example, it should be useful to parse the content of every `data` field to be also an R list instead of a JSON string. For that, we can create a new R6 class which inherits from `SSEparser`. We just need to overwrite the `append_parsed_sse()` method.
```{r}
CustomParser <- R6::R6Class(
classname = "CustomParser",
inherit = SSEparser,
public = list(
initialize = function() {
super$initialize()
},
append_parsed_sse = function(parsed_event) {
parsed_event$data <- jsonlite::fromJSON(parsed_event$data)
self$events = c(self$events, list(parsed_event))
invisible(self)
}
)
)
```
Notice that the only thing we are modifying is the parsing of the data field, not the parsing of the event itself. This is the original method from `SSEparser`:
```{r}
SSEparser$public_methods$append_parsed_sse
```
`CustomParser` uses `jsonlite::fromJSON()` to parse the data field of every chunk in the event stream. We can now use our custom class with the previous request[^1].
[^1]: This endpoint returns random event field names for each chunk in every request, so the response will not be exactly the same.
```{r}
parser <- CustomParser$new()
response <- httr2::request("https://postman-echo.com/server-events/3") %>%
httr2::req_body_json(data = list(
event = "message",
request = "POST"
)) %>%
httr2::req_perform_stream(callback = \(x) {
event <- rawToChar(x)
parser$parse_sse(event)
TRUE
})
str(parser$events)
```
Now instead of a JSON string we can have an R list in the data field **while the stream is still in process**.