Skip to content

Commit 434cbf2

Browse files
committed
ncurl() now returns $status; refactor SHA functions
1 parent 9884e7f commit 434cbf2

File tree

13 files changed

+194
-211
lines changed

13 files changed

+194
-211
lines changed

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ S3method("$<-",sendAio)
88
S3method("[",nano)
99
S3method("[[",nano)
1010
S3method(.DollarNames,nano)
11+
S3method(.DollarNames,ncurlAio)
1112
S3method(.DollarNames,recvAio)
1213
S3method(.DollarNames,sendAio)
1314
S3method(as.character,nanoHash)
@@ -24,6 +25,7 @@ S3method(print,nanoListener)
2425
S3method(print,nanoObject)
2526
S3method(print,nanoSocket)
2627
S3method(print,nanoStream)
28+
S3method(print,ncurlAio)
2729
S3method(print,recvAio)
2830
S3method(print,sendAio)
2931
S3method(print,unresolvedValue)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Implements `sha224()`, `sha256()`, `sha384()` and `sha512()` series of fast, optimised cryptographic hash and HMAC generation functions using the 'Mbed TLS' library.
66
* `ncurl()` and `stream()` gain the argmument 'ca_file' for optionally specifying a certificate authority certificate chain file when connecting to secure sites.
7+
* `ncurl()` now returns an additional `$status` field.
78
* `messenger()` gains the argument 'auth' for authenticating communications based on a pre-shared key.
89
* `random()` gains the argument 'n' for generating a vector of random numbers.
910

R/nano.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,15 @@ print.sendAio <- function(x, ...) {
269269

270270
}
271271

272+
#' @export
273+
#'
274+
print.ncurlAio <- function(x, ...) {
275+
276+
cat("< ncurlAio >\n - $status for status code\n - $raw for raw message\n - $data for message data\n", file = stdout())
277+
invisible(x)
278+
279+
}
280+
272281
#' @export
273282
#'
274283
print.unresolvedValue <- function(x, ...) {
@@ -330,3 +339,7 @@ print.errorValue <- function(x, ...) {
330339
.DollarNames.sendAio <- function(x, pattern = "") grep(pattern, "result",
331340
value = TRUE, fixed = TRUE)
332341

342+
#' @export
343+
#'
344+
.DollarNames.ncurlAio <- function(x, pattern = "") grep(pattern, c("status", "raw", "data"),
345+
value = TRUE, fixed = TRUE)

R/ncurl.R

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@
3434
#' certificate authority certificate chain. If missing or NULL, certificates
3535
#' are not validated.
3636
#'
37-
#' @return Named list of 2 elements:
37+
#' @return Named list of 3 elements:
3838
#' \itemize{
39+
#' \item{\code{$status}} {- integer HTTP repsonse status code (200 - OK)}
3940
#' \item{\code{$raw}} {- raw vector of the received resource (use
4041
#' \code{\link{writeBin}} to save to a file).}
4142
#' \item{\code{$data}} {- converted character string (if \code{'convert' = TRUE}
4243
#' and content is a recognised text format), or NULL otherwise. Other tools
4344
#' can be used to further parse this as html, json, xml etc. if required.}
4445
#' }
4546
#'
46-
#' Or else, if \code{async = TRUE}, a 'recvAio' (object of class 'recvAio').
47+
#' Or else, if \code{async = TRUE}, an 'ncurlAio' (object of class 'ncurlAio'
48+
#' and 'recvAio').
4749
#'
4850
#' @section Redirects:
4951
#'
@@ -72,39 +74,41 @@ ncurl <- function(url,
7274

7375
data <- if (!missing(data)) writeBin(object = data, con = raw())
7476

75-
if (missing(async) || !isTRUE(async)) {
76-
77-
res <- .Call(rnng_ncurl, url, method, headers, data, ca_file)
78-
is.integer(res) && return(res)
79-
80-
if (is.character(res)) {
81-
continue <- if (interactive()) readline(sprintf("Follow redirect to <%s>? [Y/n] ", res)) else "n"
82-
continue %in% c("n", "N", "no", "NO") && return(res)
83-
return(ncurl(res))
84-
}
85-
86-
data <- if (missing(convert) || isTRUE(convert)) tryCatch(rawToChar(res), error = function(e) NULL)
87-
88-
list(raw = res, data = data)
89-
90-
} else {
77+
if (async) {
9178

9279
aio <- .Call(rnng_ncurl_aio, url, method, headers, data, ca_file)
9380
is.integer(aio) && return(aio)
9481

9582
convert <- missing(convert) || isTRUE(convert)
96-
data <- raw <- NULL
83+
status <- raw <- data <- NULL
9784
unresolv <- TRUE
9885
env <- new.env(hash = FALSE)
86+
makeActiveBinding(sym = "status", fun = function(x) {
87+
if (unresolv) {
88+
res <- .Call(rnng_aio_http, aio)
89+
missing(res) && return(.Call(rnng_aio_unresolv))
90+
if (is.integer(res)) {
91+
data <<- raw <<- res
92+
} else {
93+
status <<- res[[1L]]
94+
raw <<- res[[2L]]
95+
data <<- if (convert) tryCatch(rawToChar(raw), error = function(e) NULL)
96+
}
97+
aio <<- env[["aio"]] <<- NULL
98+
unresolv <<- FALSE
99+
}
100+
status
101+
}, env = env)
99102
makeActiveBinding(sym = "raw", fun = function(x) {
100103
if (unresolv) {
101104
res <- .Call(rnng_aio_http, aio)
102105
missing(res) && return(.Call(rnng_aio_unresolv))
103106
if (is.integer(res)) {
104107
data <<- raw <<- res
105108
} else {
106-
raw <<- res
107-
data <<- if (convert) tryCatch(rawToChar(res), error = function(e) NULL)
109+
status <<- res[[1L]]
110+
raw <<- res[[2L]]
111+
data <<- if (convert) tryCatch(rawToChar(raw), error = function(e) NULL)
108112
}
109113
aio <<- env[["aio"]] <<- NULL
110114
unresolv <<- FALSE
@@ -118,15 +122,30 @@ ncurl <- function(url,
118122
if (is.integer(res)) {
119123
data <<- raw <<- res
120124
} else {
121-
raw <<- res
122-
data <<- if (convert) tryCatch(rawToChar(res), error = function(e) NULL)
125+
status <<- res[[1L]]
126+
raw <<- res[[2L]]
127+
data <<- if (convert) tryCatch(rawToChar(raw), error = function(e) NULL)
123128
}
124129
aio <<- env[["aio"]] <<- NULL
125130
unresolv <<- FALSE
126131
}
127132
data
128133
}, env = env)
129-
`class<-`(`[[<-`(`[[<-`(env, "keep.raw", TRUE), "aio", aio), "recvAio")
134+
135+
`class<-`(`[[<-`(env, "aio", aio), c("ncurlAio", "recvAio"))
136+
137+
} else {
138+
139+
res <- .Call(rnng_ncurl, url, convert, method, headers, data, ca_file)
140+
141+
is.integer(res) && return(res)
142+
is.character(res) && {
143+
continue <- if (interactive()) readline(sprintf("Follow redirect to <%s>? [Y/n] ", res)) else "n"
144+
continue %in% c("n", "N", "no", "NO") && return(res)
145+
return(ncurl(res))
146+
}
147+
148+
res
130149

131150
}
132151
}

R/sha.R

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,9 @@ sha224 <- function(x, key = NULL) {
4949

5050
if (!is.raw(x))
5151
x <- if (is.character(x)) charToRaw(x) else serialize(x, NULL)
52-
53-
if (missing(key) || is.null(key)) {
54-
55-
.Call(rnng_sha224, x)
56-
57-
} else {
58-
59-
if (!is.raw(key))
60-
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
61-
.Call(rnng_sha224hmac, x, key)
62-
63-
}
52+
if (!is.null(key) && !is.raw(key))
53+
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
54+
.Call(rnng_sha224, x, key)
6455

6556
}
6657

@@ -97,18 +88,9 @@ sha256 <- function(x, key = NULL) {
9788

9889
if (!is.raw(x))
9990
x <- if (is.character(x)) charToRaw(x) else serialize(x, NULL)
100-
101-
if (missing(key) || is.null(key)) {
102-
103-
.Call(rnng_sha256, x)
104-
105-
} else {
106-
107-
if (!is.raw(key))
91+
if (!is.null(key) && !is.raw(key))
10892
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
109-
.Call(rnng_sha256hmac, x, key)
110-
111-
}
93+
.Call(rnng_sha256, x, key)
11294

11395
}
11496

@@ -145,18 +127,9 @@ sha384 <- function(x, key = NULL) {
145127

146128
if (!is.raw(x))
147129
x <- if (is.character(x)) charToRaw(x) else serialize(x, NULL)
148-
149-
if (missing(key) || is.null(key)) {
150-
151-
.Call(rnng_sha384, x)
152-
153-
} else {
154-
155-
if (!is.raw(key))
156-
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
157-
.Call(rnng_sha384hmac, x, key)
158-
159-
}
130+
if (!is.null(key) && !is.raw(key))
131+
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
132+
.Call(rnng_sha384, x, key)
160133

161134
}
162135

@@ -193,18 +166,9 @@ sha512 <- function(x, key = NULL) {
193166

194167
if (!is.raw(x))
195168
x <- if (is.character(x)) charToRaw(x) else serialize(x, NULL)
196-
197-
if (missing(key) || is.null(key)) {
198-
199-
.Call(rnng_sha512, x)
200-
201-
} else {
202-
203-
if (!is.raw(key))
204-
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
205-
.Call(rnng_sha512hmac, x, key)
206-
207-
}
169+
if (!is.null(key) && !is.raw(key))
170+
key <- if (is.character(key)) charToRaw(key) else serialize(key, NULL)
171+
.Call(rnng_sha512, x, key)
208172

209173
}
210174

README.Rmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ Above it can be seen that the final value resolves into a timeout, which is an i
411411

412412
`ncurl()` is a minimalist http(s) client.
413413

414-
By setting `async = TRUE`, it performs requests asynchronously, returning immediately with a 'recvAio'.
414+
By setting `async = TRUE`, it performs requests asynchronously, returning immediately with an 'ncurlAio'.
415415

416416
For normal use, it takes just the URL. It can follow redirects.
417417

README.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ aio
384384
#> < recvAio >
385385
#> - $data for message data
386386
aio$data |> str()
387-
#> num [1:100000000] -1.531 1.139 -0.256 -0.362 0.17 ...
387+
#> num [1:100000000] -1.431 -1.057 0.272 -0.784 0.329 ...
388388
```
389389

390390
As `call_aio()` is blocking and will wait for completion, an alternative
@@ -527,21 +527,24 @@ message values.
527527
`ncurl()` is a minimalist http(s) client.
528528

529529
By setting `async = TRUE`, it performs requests asynchronously,
530-
returning immediately with a ‘recvAio’.
530+
returning immediately with an ‘ncurlAio’.
531531

532532
For normal use, it takes just the URL. It can follow redirects.
533533

534534
``` r
535535
ncurl("https://httpbin.org/headers")
536+
#> $status
537+
#> [1] 200
538+
#>
536539
#> $raw
537540
#> [1] 7b 0a 20 20 22 68 65 61 64 65 72 73 22 3a 20 7b 0a 20 20 20 20 22 48 6f 73
538541
#> [26] 74 22 3a 20 22 68 74 74 70 62 69 6e 2e 6f 72 67 22 2c 20 0a 20 20 20 20 22
539542
#> [51] 58 2d 41 6d 7a 6e 2d 54 72 61 63 65 2d 49 64 22 3a 20 22 52 6f 6f 74 3d 31
540-
#> [76] 2d 36 33 30 66 36 62 39 63 2d 30 39 35 66 35 66 35 31 37 66 38 32 37 61 35
541-
#> [101] 35 36 36 32 31 38 35 31 37 22 0a 20 20 7d 0a 7d 0a
543+
#> [76] 2d 36 33 30 66 64 66 37 33 2d 30 65 34 33 63 35 34 62 31 37 38 39 36 37 34
544+
#> [101] 31 33 64 66 32 64 30 62 39 22 0a 20 20 7d 0a 7d 0a
542545
#>
543546
#> $data
544-
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-630f6b9c-095f5f517f827a5566218517\"\n }\n}\n"
547+
#> [1] "{\n \"headers\": {\n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-630fdf73-0e43c54b178967413df2d0b9\"\n }\n}\n"
545548
```
546549

547550
For advanced use, supports additional HTTP methods such as POST or PUT.
@@ -551,12 +554,13 @@ res <- ncurl("http://httpbin.org/post", async = TRUE, method = "POST",
551554
headers = c(`Content-Type` = "application/json", Authorization = "Bearer APIKEY"),
552555
data = '{"key": "value"}')
553556
res
554-
#> < recvAio >
555-
#> - $data for message data
557+
#> < ncurlAio >
558+
#> - $status for status code
556559
#> - $raw for raw message
560+
#> - $data for message data
557561

558562
call_aio(res)$data
559-
#> [1] "{\n \"args\": {}, \n \"data\": \"{\\\"key\\\": \\\"value\\\"}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Authorization\": \"Bearer APIKEY\", \n \"Content-Length\": \"16\", \n \"Content-Type\": \"application/json\", \n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-630f6b9c-0b5c391a11ad759e225b0401\"\n }, \n \"json\": {\n \"key\": \"value\"\n }, \n \"origin\": \"79.173.129.2\", \n \"url\": \"http://httpbin.org/post\"\n}\n"
563+
#> [1] "{\n \"args\": {}, \n \"data\": \"{\\\"key\\\": \\\"value\\\"}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Authorization\": \"Bearer APIKEY\", \n \"Content-Length\": \"16\", \n \"Content-Type\": \"application/json\", \n \"Host\": \"httpbin.org\", \n \"X-Amzn-Trace-Id\": \"Root=1-630fdf73-5800665b2a82f9933933d8b3\"\n }, \n \"json\": {\n \"key\": \"value\"\n }, \n \"origin\": \"185.225.45.49\", \n \"url\": \"http://httpbin.org/post\"\n}\n"
560564
```
561565

562566
In this respect, it may be used as a performant and lightweight method
@@ -599,10 +603,10 @@ s |> send('{"action": "subscribe", "symbols": "EURUSD"}')
599603
#> [26] 73 79 6d 62 6f 6c 73 22 3a 20 22 45 55 52 55 53 44 22 7d 00
600604

601605
s |> recv(keep.raw = FALSE)
602-
#> [1] "{\"s\":\"EURUSD\",\"a\":1.00133,\"b\":1.00131,\"dc\":\"-0.1009\",\"dd\":\"-0.0010\",\"ppms\":false,\"t\":1661954973000}"
606+
#> [1] "{\"s\":\"EURUSD\",\"a\":1.00522,\"b\":1.0052,\"dc\":\"0.2865\",\"dd\":\"0.0029\",\"ppms\":false,\"t\":1661984634000}"
603607

604608
s |> recv(keep.raw = FALSE)
605-
#> [1] "{\"s\":\"EURUSD\",\"a\":1.00131,\"b\":1.00129,\"dc\":\"-0.1029\",\"dd\":\"-0.0010\",\"ppms\":false,\"t\":1661954974000}"
609+
#> [1] "{\"s\":\"EURUSD\",\"a\":1.00519,\"b\":1.00517,\"dc\":\"0.2835\",\"dd\":\"0.0029\",\"ppms\":false,\"t\":1661984637000}"
606610

607611
close(s)
608612
```

man/ncurl.Rd

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/aio.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,13 +742,17 @@ SEXP rnng_aio_http(SEXP aio) {
742742

743743
void *dat;
744744
size_t sz;
745-
SEXP vec;
745+
SEXP out, vec;
746746

747+
PROTECT(out = Rf_allocVector(VECSXP, 2));
748+
SET_VECTOR_ELT(out, 0, Rf_ScalarInteger(code));
747749
nng_http_res_get_data(handle->res, &dat, &sz);
748750
vec = Rf_allocVector(RAWSXP, sz);
749751
memcpy(RAW(vec), dat, sz);
752+
SET_VECTOR_ELT(out, 1, vec);
750753

751-
return vec;
754+
UNPROTECT(1);
755+
return out;
752756

753757
}
754758

0 commit comments

Comments
 (0)