websocket

WebSocket client for R

https://github.com/rstudio/websocket

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (11.3%) to scientific vocabulary

Keywords from Contributors

shiny web-app web-development rmarkdown unit-testing event-loop shinydashboard package-creation geo reactivity
Last synced: 10 months ago · JSON representation

Repository

WebSocket client for R

Basic Info
Statistics
  • Stars: 94
  • Watchers: 14
  • Forks: 20
  • Open Issues: 38
  • Releases: 9
Created over 8 years ago · Last pushed about 1 year ago
Metadata Files
Readme Changelog Contributing License

README.md

websocket

CRAN status R build status <!-- badges: end -->

This is an R WebSocket client library backed by the websocketpp C++ library. WebSocket I/O is handled on a separate thread from R.

Usage examples

```R library(websocket)

ws <- WebSocket$new("ws://echo.websocket.org/", autoConnect = FALSE) ws$onOpen(function(event) { cat("Connection opened\n") }) ws$onMessage(function(event) { cat("Client got msg: ", event$data, "\n") }) ws$onClose(function(event) { cat("Client disconnected with code ", event$code, " and reason ", event$reason, "\n", sep = "") }) ws$onError(function(event) { cat("Client failed to connect: ", event$message, "\n") }) ws$connect() ```

(If you're not writing these commands at a console—for instance, if you're using a WebSocket as part of a Shiny app—you can leave off autoConnect=FALSE and ws$connect(). These are only necessary when the creation of the WebSocket object and the registering of the onOpen/onMessage/onClose handlers don't happen within the same function call, because in those cases the connection may open and/or messages received before the handlers are registered.)

Once connected, you can send commands as follows:

```R

Send text messages

ws$send("hello")

Send binary messages

ws$send(charToRaw("hello"))

Finish

ws$close() ```

Note that if you want to send() a message as soon as it connects, without having to wait at the console, you can put the ws$send() inside of the ws$onOpen callback, as in:

R ws <- WebSocket$new("wss://echo.websocket.org/") ws$onMessage(function(event) { cat("Client got msg: ", event$data, "\n") }) ws$onOpen(function(event) { ws$send("hello") })

Examples

WebSocket proxy

The websocket (client) package can be used with a WebSocket server, implemented as a httpuv web application, to act as a WebSocket proxy. This proxy can be modified do things like log the traffic in each direction, or modify messages sent in either direction.

The proxy will listen to port 5002 on the local machine, and connect to the remote machine at wss://echo.websocket.org:80. In this example, after starting the proxy, we'll connect to it with a WebSocket client in a separate R process, then send a message from that process. Here's what will happen in the proxy:

  • The client will send the message "hello".
  • The proxy will receive "hello" from the client, convert it to "HELLO", then send it to the remote echo server.
  • The echo server will receive "HELLO" and send it back.
  • The proxy will receive "HELLO" from the server, convert it to "HELLO, world", then send it to the client.
  • The client will receive "HELLO, world".

To run this proxy, run the code below in an R session:

```R library(curl) library(httpuv) library(websocket)

URL of the remote websocket server

target_host <- "echo.websocket.org:80"

Should be "ws" or "wss"

target_protocol <- "ws"

Port this computer will listen on

listen_port <- 5002

==============================================================================

Functions for translating header strings between HTTP request and Rook formats

==============================================================================

reqrooktocurl <- function(req, host) { # Rename headers. Example: HTTPCACHE_CONTROL => Cache-Control r <- as.list(req)

# Uncomment to print out request headers # cat("== Original ==\n") # cat(capture.output(print(str(r))), sep = "\n")

r <- r[grepl("^HTTP", names(r))] nms <- names(r) nms <- sub("^HTTP", "", nms) nms <- tolower(nms) nms <- gsub("_", "-", nms, fixed = TRUE) nms <- gsub("\b([a-z])", "\U\1", nms, perl = TRUE) names(r) <- nms # Overwrite host field r$Host <- host

# Uncomment to print out modified request headers # cat("== Modified ==\n") # cat(capture.output(print(str(r))), sep = "\n") r }

resphttrtorook <- function(resp) { status <- as.integer(sub("^HTTP\S+ (\d+).*", "\1", curl::parseheaders(resp$headers)[1])) list( status = status, headers = parseheaderslist(resp$headers), body = resp$content ) }

==============================================================================

Websocket proxy app

==============================================================================

These functions are called from the server app; defined here so that they

can be modified while the application is running.

onHeaders <- function(req) { # Print out the headers received from server # str(as.list(req$HEADERS)) NULL }

call <- function(req) { reqcurl <- reqrooktocurl(req, targethost) h <- newhandle() do.call(handlesetheaders, c(h, reqcurl)) respcurl <- curlfetchmemory(paste0("http://", targethost, req$PATHINFO), handle = h) resphttrtorook(resp_curl) }

onWSOpen <- function(clientWS) { # The httpuv package contains a WebSocket server class and the websocket # package contains a WebSocket client class. It may be a bit confusing, but # both of these classes are named "WebSocket", and they have slightly # different interfaces. serverWS <- websocket::WebSocket$new(paste0(targetprotocol, "://", targethost))

msgfromclientbuffer <- list() # Flush the queued messages from the client flushmsgfromclientbuffer <- function() { for (msg in msgfromclientbuffer) { serverWS$send(msg) } msgfromclient_buffer <<- list() } clientWS$onMessage(function (isBinary, msgFromClient) { cat("Got message from client: ", msgFromClient, "\n")

# NOTE: This is where we modify the messages going from the client to the
# server. This simply converts to upper case. You can modify to suit your
# needs.
msgFromClient <- toupper(msgFromClient)
cat("Converting toupper() and then sending to server: ", msgFromClient, "\n")

if (serverWS$readyState() == 0) {
  msg_from_client_buffer[length(msg_from_client_buffer) + 1] <<- msgFromClient
} else {
  serverWS$send(msgFromClient)
}

}) serverWS$onOpen(function(event) { serverWS$onMessage(function(msgFromServer) { cat("Got message from server: ", msgFromServer$data, "\n")

  # NOTE: This is where we could modify the messages going from the server
  # to the client. You can modify to suit your needs.
  msg <- paste0(msgFromServer$data, ", world")
  cat('Appending ", world" and then sending to client: ', msg, "\n")

  clientWS$send(msg)
})
flush_msg_from_client_buffer()

}) }

Start the websocket proxy app

s <- startServer("0.0.0.0", listen_port, list( onHeaders = function(req) { onHeaders(req) }, call = function(req) { call(req) }, onWSOpen = function(clientWS) { onWSOpen(clientWS) } ) )

Run this to stop the server:

s$stop()

If you want to run this code with Rscript -e "source('server.R')", also

uncomment the following so that it doesn't immediately exit.

httpuv::service(Inf)

```

In a separate R session, you can connect to this proxy and send a message.

```R

Connect to proxy

ws <- websocket::WebSocket$new("ws://localhost:5002") ws$onMessage(function(event) { cat(paste0('Received message from proxy: "', event$data, '"\n')) })

Send message to proxy

ws$send("hello")

> Received message from proxy: "HELLO, world"

```

In the R process running the proxy, you will see:

Got message from client: hello Converting toupper() and then sending to server: HELLO Got message from server: HELLO Appending ", world" and then sending to client: HELLO, world

Testing the websocket client with a WebSocket echo server

This is a simple WebSocket echo server implemented with httpuv. You can run it and interact with using the WebSocket client code below.

```R library(httpuv) cat("Starting server on port 8080...\n") s <- startServer("0.0.0.0", 8080, list( onHeaders = function(req) { # Print connection headers cat(capture.output(str(as.list(req))), sep = "\n") }, onWSOpen = function(ws) { cat("Connection opened.\n")

  ws$onMessage(function(binary, message) {
    cat("Server received message:", message, "\n")
    ws$send(message)
  })
  ws$onClose(function() {
    cat("Connection closed.\n")
  })
}

) ) ```

This code will connect to the echo server and send a message:

```R library(websocket)

ws <- WebSocket$new("ws://127.0.0.1:8080/", headers = list(Cookie = "Xyz"), accessLogChannels = "all" # enable all websocketpp logging )

ws$onOpen(function(event) { cat("Connection opened\n") }) ws$onMessage(function(event) { cat("Client got msg: ", event$data, "\n") }) ws$onClose(function(event) { cat("Client disconnected with code ", event$code, " and reason ", event$reason, "\n", sep = "") }) ws$onError(function(event) { cat("Client failed to connect: ", event$message, "\n") })

ws$send("hello")

ws$send(charToRaw("hello"))

ws$close() ```

If you want it to send the message as soon as it connects (without having to wait for a moment at the console), you can tell it to do that in the onOpen callback:

R ws$onOpen(function(event) { cat("Connection opened\n") ws$send("hello") })

Owner

  • Name: RStudio
  • Login: rstudio
  • Kind: organization
  • Email: info@rstudio.org
  • Location: Boston, MA

GitHub Events

Total
  • Create event: 2
  • Release event: 1
  • Issues event: 9
  • Watch event: 4
  • Member event: 1
  • Issue comment event: 10
  • Push event: 14
  • Pull request review event: 1
  • Pull request event: 11
  • Fork event: 1
Last Year
  • Create event: 2
  • Release event: 1
  • Issues event: 9
  • Watch event: 4
  • Member event: 1
  • Issue comment event: 10
  • Push event: 14
  • Pull request review event: 1
  • Pull request event: 11
  • Fork event: 1

Committers

Last synced: about 1 year ago

All Time
  • Total Commits: 253
  • Total Committers: 9
  • Avg Commits per committer: 28.111
  • Development Distribution Score (DDS): 0.506
Past Year
  • Commits: 17
  • Committers: 4
  • Avg Commits per committer: 4.25
  • Development Distribution Score (DDS): 0.353
Top Committers
Name Email Commits
Winston Chang w****n@s****g 125
Alan Dipert a****n@d****g 58
Joe Cheng j****e@r****m 23
Barret Schloerke s****e@g****m 20
Barbara Borges Ribeiro b****o@g****m 10
trestletech j****n@t****t 8
Jeroen Ooms j****s@g****m 4
Charlie Gao 5****o 4
Tomas Kalibera t****a@g****m 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 11 months ago

All Time
  • Total issues: 76
  • Total pull requests: 45
  • Average time to close issues: about 1 month
  • Average time to close pull requests: 6 days
  • Total issue authors: 51
  • Total pull request authors: 12
  • Average comments per issue: 2.14
  • Average comments per pull request: 0.6
  • Merged pull requests: 40
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 6
  • Pull requests: 8
  • Average time to close issues: 8 days
  • Average time to close pull requests: 2 days
  • Issue authors: 5
  • Pull request authors: 5
  • Average comments per issue: 0.5
  • Average comments per pull request: 0.75
  • Merged pull requests: 7
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • wch (15)
  • cawthm (3)
  • jcheng5 (3)
  • vspinu (3)
  • QuLogic (3)
  • alandipert (2)
  • ericfeder (2)
  • r2evans (2)
  • yihui (1)
  • gsainsbury86 (1)
  • hbastidas (1)
  • Tazovsky (1)
  • SatoshiReport (1)
  • rosaliepl (1)
  • lassehjorthmadsen (1)
Pull Request Authors
  • wch (18)
  • shikokuchuo (8)
  • schloerke (6)
  • jcheng5 (5)
  • jeroen (5)
  • trestletech (2)
  • alandipert (2)
  • karangattu (2)
  • kalibera (2)
  • jonthegeek (1)
  • TobiasMadsen (1)
  • gtritchie (1)
Top Labels
Issue Labels
Priority: High (8) Need Info (7) Difficulty: Advanced (6) Effort: Low (6) Difficulty: Intermediate (6) Type: Bug (5) Type: Enhancement (5) Priority: Medium (4) Platform: Windows (4) Needs Repro (2) Docs (2) Help Wanted (2) Effort: Medium (2) Priority: Low (2) Effort: High (1) Type: Question (1)
Pull Request Labels

Packages

  • Total packages: 2
  • Total downloads:
    • cran 51,436 last-month
  • Total docker downloads: 99,983
  • Total dependent packages: 9
    (may contain duplicates)
  • Total dependent repositories: 48
    (may contain duplicates)
  • Total versions: 19
  • Total maintainers: 1
proxy.golang.org: github.com/rstudio/websocket
  • Versions: 9
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Dependent packages count: 5.5%
Average: 5.7%
Dependent repos count: 5.9%
Last synced: 11 months ago
cran.r-project.org: websocket

'WebSocket' Client Library

  • Versions: 10
  • Dependent Packages: 9
  • Dependent Repositories: 48
  • Downloads: 51,436 Last month
  • Docker Downloads: 99,983
Rankings
Downloads: 3.2%
Dependent repos count: 3.6%
Forks count: 4.1%
Stargazers count: 4.1%
Dependent packages count: 5.7%
Average: 7.2%
Docker downloads count: 22.5%
Maintainers (1)
Last synced: 11 months ago

Dependencies

DESCRIPTION cran
  • R6 * imports
  • later >= 1.2.0 imports
  • httpuv * suggests
  • knitr * suggests
  • rmarkdown * suggests
  • testthat * suggests
.github/workflows/R-CMD-check.yaml actions