Skip to content

Commit 54c1637

Browse files
committed
nanonext 1.1.0
1 parent cfe434a commit 54c1637

File tree

6 files changed

+50
-51
lines changed

6 files changed

+50
-51
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: nanonext
22
Type: Package
33
Title: NNG (Nanomsg Next Gen) Lightweight Messaging Library
4-
Version: 1.0.0.9022
4+
Version: 1.1.0
55
Description: R binding for NNG (Nanomsg Next Gen), a successor to ZeroMQ. NNG is
66
a socket library implementing 'Scalability Protocols', a reliable,
77
high-performance standard for common communications patterns including

NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# nanonext 1.0.0.9022 (development)
1+
# nanonext 1.1.0
22

33
#### New Features
44

R/aio.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ call_aio_ <- function(aio) invisible(.Call(rnng_wait_thread_create, aio))
256256
#' collect_aio(res)
257257
#'
258258
#' msg <- recv_aio(s2, timeout = 100)
259-
#' collect_aio_(res)
259+
#' collect_aio_(msg)
260260
#'
261261
#' close(s1)
262262
#' close(s2)

man/collect_aio.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vignettes/nanonext.Rmd

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ One solution it provides is that of processing real-time data where computation
3737
Create socket in Python using the NNG binding 'pynng':
3838

3939

40-
```python
40+
``` python
4141
import numpy as np
4242
import pynng
4343
socket = pynng.Pair0(listen="ipc:///tmp/nanonext.socket")
@@ -46,7 +46,7 @@ socket = pynng.Pair0(listen="ipc:///tmp/nanonext.socket")
4646
Create nano object in R using `nanonext`, then send a vector of 'doubles', specifying mode as 'raw':
4747

4848

49-
```r
49+
``` r
5050
library(nanonext)
5151
n <- nano("pair", dial = "ipc:///tmp/nanonext.socket")
5252
n$send(c(1.1, 2.2, 3.3, 4.4, 5.5), mode = "raw")
@@ -56,7 +56,7 @@ n$send(c(1.1, 2.2, 3.3, 4.4, 5.5), mode = "raw")
5656
Receive in Python as a NumPy array of 'floats', and send back to R:
5757

5858

59-
```python
59+
``` python
6060
raw = socket.recv()
6161
array = np.frombuffer(raw)
6262
print(array)
@@ -69,7 +69,7 @@ socket.send(msg)
6969
Receive in R, specifying the receive mode as 'double':
7070

7171

72-
```r
72+
``` r
7373
n$recv(mode = "double")
7474
#> [1] 1.1 2.2 3.3 4.4 5.5
7575
```
@@ -81,7 +81,7 @@ n$recv(mode = "double")
8181
`nanonext` implements true async send and receive, leveraging NNG as a massively-scaleable concurrency framework.
8282

8383

84-
```r
84+
``` r
8585
s1 <- socket("pair", listen = "inproc://nano")
8686
s2 <- socket("pair", dial = "inproc://nano")
8787
```
@@ -91,7 +91,7 @@ s2 <- socket("pair", dial = "inproc://nano")
9191
An 'Aio' object returns an unresolved value whilst its asynchronous operation is ongoing, automatically resolving to a final value once complete.
9292

9393

94-
```r
94+
``` r
9595
# an async receive is requested, but no messages are waiting (yet to be sent)
9696
msg <- recv_aio(s2)
9797
msg
@@ -103,7 +103,7 @@ msg$data
103103
For a 'sendAio' object, the result is stored at `$result`.
104104

105105

106-
```r
106+
``` r
107107
res <- send_aio(s1, data.frame(a = 1, b = 2))
108108
res
109109
#> < sendAio | $result >
@@ -115,7 +115,7 @@ res$result
115115
For a 'recvAio' object, the message is stored at `$data`.
116116

117117

118-
```r
118+
``` r
119119
# now that a message has been sent, the 'recvAio' resolves automatically
120120
msg$data
121121
#> a b
@@ -125,7 +125,7 @@ msg$data
125125
Auxiliary function `unresolved()` may be used in control flow statements to perform actions which depend on resolution of the Aio, both before and after. This means there is no need to actually wait (block) for an Aio to resolve, as the example below demonstrates.
126126

127127

128-
```r
128+
``` r
129129
msg <- recv_aio(s2)
130130

131131
# unresolved() queries for resolution itself so no need to use it again within the while loop
@@ -144,14 +144,18 @@ msg$data
144144
The values may also be called explicitly using `call_aio()`. This will wait for completion of the Aio (blocking).
145145

146146

147-
```r
147+
``` r
148148
# will wait for completion then return the resolved Aio
149149
call_aio(msg)
150150

151-
# to access the resolved value directly (waiting if required)
151+
# to access the resolved value (waiting if required):
152152
call_aio(msg)$data
153153
#> [1] "resolved"
154154

155+
# or directly:
156+
collect_aio(msg)
157+
#> [1] "resolved"
158+
155159
close(s1)
156160
close(s2)
157161
```
@@ -167,7 +171,7 @@ Can be used to perform computationally-expensive calculations or I/O-bound opera
167171
[S] Server process: `reply()` will wait for a message and apply a function, in this case `rnorm()`, before sending back the result. This is started in a background 'mirai' process.
168172

169173

170-
```r
174+
``` r
171175
m <- mirai::mirai({
172176
library(nanonext)
173177
rep <- socket("rep", listen = "tcp://127.0.0.1:6556")
@@ -178,7 +182,7 @@ m <- mirai::mirai({
178182
[C] Client process: `request()` performs an async send and receive request and returns immediately with a `recvAio` object.
179183

180184

181-
```r
185+
``` r
182186
library(nanonext)
183187
req <- socket("req", dial = "tcp://127.0.0.1:6556")
184188
aio <- request(context(req), data = 1e8, recv_mode = "double")
@@ -187,7 +191,7 @@ aio <- request(context(req), data = 1e8, recv_mode = "double")
187191
At this point, the client can run additional code concurrent with the server processing the request.
188192

189193

190-
```r
194+
``` r
191195
# do more...
192196
```
193197

@@ -196,13 +200,9 @@ When the result of the server calculation is required, the `recvAio` may be call
196200
The return value from the server request is then retrieved and stored in the Aio as `$data`.
197201

198202

199-
```r
200-
call_aio(aio)
201-
202-
aio
203-
#> < recvAio | $data >
204-
aio$data |> str()
205-
#> num [1:100000000] 1.365 -0.842 -0.816 1.367 -0.813 ...
203+
``` r
204+
call_aio(aio)$data |> str()
205+
#> num [1:100000000] 0.257 -0.413 0.946 0.545 0.071 ...
206206
```
207207

208208
As `call_aio()` is blocking and will wait for completion, an alternative is to query `aio$data` directly. This will return an 'unresolved' logical NA value if the calculation is yet to complete.
@@ -232,7 +232,7 @@ The following shows how condition variables and signalling work in practice.
232232
Example 1: set up a socket, and wait for the other side to connect:
233233

234234

235-
```r
235+
``` r
236236
sock <- socket("pair", listen = "inproc://nanopipe")
237237

238238
cv <- cv() # create new condition variable
@@ -265,7 +265,7 @@ close(sock)
265265
Example 2: wait until a message is received or connection is dropped:
266266

267267

268-
```r
268+
``` r
269269
sock <- socket("pair", listen = "inproc://nanosignal")
270270
sock2 <- socket("pair", dial = "inproc://nanosignal")
271271

@@ -317,11 +317,11 @@ A client configuration requires a PEM-encoded CA certificate (chain) used to ver
317317
Additionally, the convenience function `write_cert()` can automatically generate a 4096 bit RSA key pair and self-signed X.509 certificate in the format required by `tls_config()`. The 'cn' argument must be provided and match exactly the hostname / IP address of the URL that is being used, e.g. in the example below '127.0.0.1' must be used throughout, or alternatively 'localhost', but not a mixture of the two.
318318

319319

320-
```r
320+
``` r
321321
cert <- write_cert(cn = "127.0.0.1")
322322
str(cert)
323323
#> List of 2
324-
#> $ server: chr [1:2] "-----BEGIN CERTIFICATE-----\nMIIFOTCCAyGgAwIBAgIBATANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQDDAkxMjcu\nMC4wLjExETAPBgNV"| __truncated__ "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAuMCkX3Rdm9ssjzAfpLbDndtuwvwceenNXQNO9R2/v99teHdn\nTsjeYb+gNNpP"| __truncated__
324+
#> $ server: chr [1:2] "-----BEGIN CERTIFICATE-----\nMIIFOTCCAyGgAwIBAgIBATANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQDDAkxMjcu\nMC4wLjExETAPBgNV"| __truncated__ "-----BEGIN RSA PRIVATE KEY-----\nMIIJKgIBAAKCAgEA3CPAXY45HOTzvo4z+U15qFP3jvrcATlNio/qO4HU4L0E82k+\nQ2P1aDuWUg7h"| __truncated__
325325
#> $ client: chr [1:2] "-----BEGIN CERTIFICATE-----\nMIIFOTCCAyGgAwIBAgIBATANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQDDAkxMjcu\nMC4wLjExETAPBgNV"| __truncated__ ""
326326

327327
ser <- tls_config(server = cert$server)
@@ -348,7 +348,7 @@ close(s)
348348
`nanonext` fully implements NNG's pub/sub protocol as per the below example. A subscriber can subscribe to one or multiple topics broadcast by a publisher.
349349

350350

351-
```r
351+
``` r
352352
pub <- socket("pub", listen = "inproc://nanobroadcast")
353353
sub <- socket("sub", dial = "inproc://nanobroadcast")
354354

@@ -392,7 +392,7 @@ sub |> recv(mode = "character")
392392
The subscribed topic can be of any atomic type (not just character), allowing integer, double, logical, complex and raw vectors to be sent and received.
393393

394394

395-
```r
395+
``` r
396396
sub |> subscribe(topic = 1)
397397
pub |> send(c(1, 10, 10, 20), mode = "raw")
398398
#> [1] 0
@@ -416,7 +416,7 @@ This type of pattern is useful for applications such as service discovery.
416416
A surveyor sends a survey, which is broadcast to all peer respondents. Respondents are then able to reply, but are not obliged to. The survey itself is a timed event, and responses received after the timeout are discarded.
417417

418418

419-
```r
419+
``` r
420420
sur <- socket("surveyor", listen = "inproc://nanoservice")
421421
res1 <- socket("respondent", dial = "inproc://nanoservice")
422422
res2 <- socket("respondent", dial = "inproc://nanoservice")
@@ -470,7 +470,7 @@ It can be seen that the final value resolves into a timeout, which is an integer
470470
For normal use, it takes just the URL. It can follow redirects.
471471

472472

473-
```r
473+
``` r
474474
ncurl("https://postman-echo.com/get")
475475
#> $status
476476
#> [1] 200
@@ -479,13 +479,13 @@ ncurl("https://postman-echo.com/get")
479479
#> NULL
480480
#>
481481
#> $data
482-
#> [1] "{\n \"args\": {},\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"x-amzn-trace-id\": \"Root=1-6634af61-2a7256825245680a005b73e7\"\n },\n \"url\": \"https://postman-echo.com/get\"\n}"
482+
#> [1] "{\n \"args\": {},\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"x-amzn-trace-id\": \"Root=1-665dccb1-6374c8162c8a5951767e475b\"\n },\n \"url\": \"https://postman-echo.com/get\"\n}"
483483
```
484484

485485
For advanced use, supports additional HTTP methods such as POST or PUT.
486486

487487

488-
```r
488+
``` r
489489
res <- ncurl_aio("https://postman-echo.com/post",
490490
method = "POST",
491491
headers = c(`Content-Type` = "application/json", Authorization = "Bearer APIKEY"),
@@ -496,10 +496,10 @@ res
496496

497497
call_aio(res)$headers
498498
#> $date
499-
#> [1] "Fri, 03 May 2024 09:33:21 GMT"
499+
#> [1] "Mon, 03 Jun 2024 14:01:21 GMT"
500500

501501
res$data
502-
#> [1] "{\n \"args\": {},\n \"data\": {\n \"key\": \"value\"\n },\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"x-amzn-trace-id\": \"Root=1-6634af61-7f19837d47b179ea131ef4e9\",\n \"content-length\": \"16\",\n \"content-type\": \"application/json\",\n \"authorization\": \"Bearer APIKEY\"\n },\n \"json\": {\n \"key\": \"value\"\n },\n \"url\": \"https://postman-echo.com/post\"\n}"
502+
#> [1] "{\n \"args\": {},\n \"data\": {\n \"key\": \"value\"\n },\n \"files\": {},\n \"form\": {},\n \"headers\": {\n \"x-forwarded-proto\": \"https\",\n \"x-forwarded-port\": \"443\",\n \"host\": \"postman-echo.com\",\n \"x-amzn-trace-id\": \"Root=1-665dccb1-74cd2d7d4fe4282876bfb176\",\n \"content-length\": \"16\",\n \"content-type\": \"application/json\",\n \"authorization\": \"Bearer APIKEY\"\n },\n \"json\": {\n \"key\": \"value\"\n },\n \"url\": \"https://postman-echo.com/post\"\n}"
503503
```
504504

505505
In this respect, it may be used as a performant and lightweight method for making REST API requests.
@@ -509,7 +509,7 @@ In this respect, it may be used as a performant and lightweight method for makin
509509
By specifying `convert = FALSE`, the received binary data is made available as a raw vector. This may be fed into 'json' parsers which can operate directly on such data etc.
510510

511511

512-
```r
512+
``` r
513513
sess <- ncurl_session("https://postman-echo.com/get",
514514
convert = FALSE,
515515
headers = c(`Content-Type` = "application/json", Authorization = "Bearer APIKEY"),
@@ -523,7 +523,7 @@ transact(sess)
523523
#>
524524
#> $headers
525525
#> $headers$Date
526-
#> [1] "Fri, 03 May 2024 09:33:22 GMT"
526+
#> [1] "Mon, 03 Jun 2024 14:01:22 GMT"
527527
#>
528528
#> $headers$`Content-Type`
529529
#> [1] "application/json; charset=utf-8"
@@ -534,7 +534,7 @@ transact(sess)
534534
#> [40] 6f 72 77 61 72 64 65 64 2d 70 72 6f 74 6f 22 3a 20 22 68 74 74 70 73 22 2c 0a 20 20 20 20 22 78 2d 66 6f 72 77 61 72
535535
#> [79] 64 65 64 2d 70 6f 72 74 22 3a 20 22 34 34 33 22 2c 0a 20 20 20 20 22 68 6f 73 74 22 3a 20 22 70 6f 73 74 6d 61 6e 2d
536536
#> [118] 65 63 68 6f 2e 63 6f 6d 22 2c 0a 20 20 20 20 22 78 2d 61 6d 7a 6e 2d 74 72 61 63 65 2d 69 64 22 3a 20 22 52 6f 6f 74
537-
#> [157] 3d 31 2d 36 36 33 34 61 66 36 32 2d 37 38 31 63 34 34 38 66 35 30 37 65 61 62 64 65 33 31 35 61 66 35 37 35 22 2c 0a
537+
#> [157] 3d 31 2d 36 36 35 64 63 63 62 32 2d 31 39 34 62 62 66 39 35 30 64 30 32 64 65 36 33 36 30 32 38 66 32 34 31 22 2c 0a
538538
#> [196] 20 20 20 20 22 63 6f 6e 74 65 6e 74 2d 74 79 70 65 22 3a 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 22 2c
539539
#> [235] 0a 20 20 20 20 22 61 75 74 68 6f 72 69 7a 61 74 69 6f 6e 22 3a 20 22 42 65 61 72 65 72 20 41 50 49 4b 45 59 22 0a 20
540540
#> [274] 20 7d 2c 0a 20 20 22 75 72 6c 22 3a 20 22 68 74 74 70 73 3a 2f 2f 70 6f 73 74 6d 61 6e 2d 65 63 68 6f 2e 63 6f 6d 2f
@@ -544,7 +544,7 @@ transact(sess)
544544
Optimised functions for base64 encoding and decoding from the 'Mbed TLS' library are also exposed as convenience utilities:
545545

546546

547-
```r
547+
``` r
548548
base64enc("hello world!")
549549
#> [1] "aGVsbG8gd29ybGQh"
550550

@@ -561,7 +561,7 @@ base64dec(base64enc("hello world!"))
561561
The stream interface can be used to communicate with (secure) websocket servers. The argument `textframes = TRUE` can be specified where the websocket server uses text rather than binary frames.
562562

563563

564-
```r
564+
``` r
565565
# connecting to an echo service
566566
s <- stream(dial = "wss://echo.websocket.events/", textframes = TRUE)
567567
s
@@ -574,7 +574,7 @@ s
574574
`send()` and `recv()`, as well as their asynchronous counterparts `send_aio()` and `recv_aio()` can be used on Streams in the same way as Sockets. This affords a great deal of flexibility in ingesting and processing streaming data.
575575

576576

577-
```r
577+
``` r
578578
s |> recv()
579579
#> [1] "echo.websocket.events sponsored by Lob.com"
580580

@@ -612,7 +612,7 @@ See the function documentation page for a list of common options.
612612
Once a dialer or listener has started, it is not generally possible to change its configuration. In this case, the dialer or listener should be created specifying 'autostart = FALSE'.
613613

614614

615-
```r
615+
``` r
616616
s <- socket(listen = "inproc://options", autostart = FALSE)
617617

618618
# no maximum message size
@@ -635,7 +635,7 @@ This can be used on a Socket, Listener or Dialer to query useful statistics such
635635
See the function documentation page for available statistics.
636636

637637

638-
```r
638+
``` r
639639
s <- socket(listen = "inproc://stat")
640640

641641
# no active connections (pipes)

vignettes/nanonext.Rmd.orig

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,12 @@ The values may also be called explicitly using `call_aio()`. This will wait for
137137
# will wait for completion then return the resolved Aio
138138
call_aio(msg)
139139

140-
# to access the resolved value directly (waiting if required)
140+
# to access the resolved value (waiting if required):
141141
call_aio(msg)$data
142142

143+
# or directly:
144+
collect_aio(msg)
145+
143146
close(s1)
144147
close(s2)
145148

@@ -184,11 +187,7 @@ When the result of the server calculation is required, the `recvAio` may be call
184187
The return value from the server request is then retrieved and stored in the Aio as `$data`.
185188

186189
```{r rpcclient3}
187-
call_aio(aio)
188-
189-
aio
190-
aio$data |> str()
191-
190+
call_aio(aio)$data |> str()
192191
```
193192

194193
As `call_aio()` is blocking and will wait for completion, an alternative is to query `aio$data` directly. This will return an 'unresolved' logical NA value if the calculation is yet to complete.

0 commit comments

Comments
 (0)