---
title: "Web-app development with OpenCpu"
author: "Michael Rustler"
date: "`r format(Sys.time(), '%d %B, %Y')`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Web-app development with OpenCpu}
  %\VignetteEngine{knitr::rmarkdown}
  \usepackage[utf8]{inputenc}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
is_ghactions <- identical(Sys.getenv("CI"), "true")

```

## Background

For developing a web application, which is based on the R package `kwb.qmra` 
the [OpenCPU API](https://www.opencpu.org/api.html) can be used. It has a lot of 
great features which its author Jeroen Ooms describes as follows 
([Source](https://www.quora.com/How-do-plumber-and-OpenCPU-compare-when-it-comes-to-deploying-ML-models)):

>"OpenCPU is mature has been put to the test in production for many years now,
>both in private and public organizations. The system was developed out of a need
>for a reliable, scalable system for embedding R that we used at UCLA for
>teaching R to students, sometimes several classes at once (think about a
>classroom settings with 100+ concurrent students).
>The core implementation of OpenCPU is the opencpu-server stack based on systems
>native Apache2 webserver. The opencpu-server stack has been packaged as deb/rpm
>packages and can be installed out of the box on all popular Linux systems. This
>really provides a super stable production ready system out-of-the-box. Not only
>does it easily scale up but you can configure the server (if you want to add
>auth, proxies, etc) via standard Apache configuration on your server.
>An incredible amount of time and energy has been invested into optimizing the
>internals of opencpu-server for security, reliability and performance. In
>opencpu-server, each incoming request gets processed in a temporary process fork
>which serves as a sandbox that controls memory/cpu limits, access control,
>timeouts, etc. All these are critical to ensure that the stability of the server
>does not get compromised by users or packages (accidentally) messing with the
>system or using excessive resources. I am not aware of any other R server system
>that does this. 
>
>More details about the why and how of OpenCPU are available from these papers:"
>
>- [Towards a Universal Interface for Scientific Computing through Separation of 
>Concerns](https://arxiv.org/abs/1406.4806)
>
>- [Enforcing Security Policies in R Using Dynamic Sandboxing on Linux](https://arxiv.org/abs/1303.4808)


For the `kwb.qmra` R package a very tiny example app (source code on 
[GitHub](https://github.com/KWB-R/kwb.qmra/tree/master/inst/www)) was developed
which uses the [OpenCPU](https://www.opencpu.org) framework. This web app 
performs a quantitative microbiological risk assessment (QMRA) for a 
[dummy configuration](https://github.com/KWB-R/kwb.qmra/tree/master/inst/extdata/configs/dummy) 
and can be tested here: [https://kwb-r.ocpu.io/kwb.qmra/www/](https://kwb-r.ocpu.io/kwb.qmra/www/)


More advanced web-apps can be easily developed by using the [OpenCPU API](https://www.opencpu.org/api.html) 
but will most probably need an own backend server which hosts the OpenCPU 
server, because the [publically freely available OpenCPU server](https://www.opencpu.org/cloud.html) 
might be too limited.

```{r setup, echo = FALSE}
library(kwb.qmra)
data(config_dummy_json)
data(config_default_json)
writeLines(text = config_dummy_json, "config_dummy.json")
writeLines(text = config_default_json, "config_default.json")
```


```{r input_ghactions, echo=FALSE, results='asis', eval=is_ghactions}
cat("## Run risk simulatation

You need to provide the input parameters 
for `kwb.qmra::opencpu_simulate_risk()` 
required in a JSON data structure as provided 
in the example data [config_dummy.json](../config_dummy.json) (for details see: 
`kwb.qmra::config_dummy_json`), which needs to be converted into an R list data
structure (see below)"
)
```

```{r input_nonghactions, echo=FALSE, results='asis', eval=!is_ghactions}
cat("## Run risk simulatation

You need to provide the input parameters 
for `kwb.qmra::opencpu_simulate_risk()` 
required in a JSON data structure as provided 
in the example data [config_dummy.json](config_dummy.json) (for details see: 
`kwb.qmra::config_dummy_json`), which needs to be converted into an R list data
structure (see below)"
)
```


```{r}

### Convert "config.json" to R list
config <- jsonlite::fromJSON("config_dummy.json")

### Optionally directly import a configuration from CSV files
### for details see: https://github.com/KWB-R/kwb.qmra/tree/master/inst/extdata/configs
# config_dir <- system.file("extdata/configs/dummy", package = "kwb.qmra")
# config <- kwb.qmra::config_read(confDir = config_dir)

# Run risk simulation
risk_dummy <- kwb.qmra::opencpu_simulate_risk(config)
risk_dummy_json <- jsonlite::toJSON(risk_dummy, pretty = TRUE)

# Save simulation results in JSON format
writeLines(text = risk_dummy_json, "risk_dummy.json")

```

```{r output_ghactions, echo=FALSE, results='asis', eval=is_ghactions}
cat("The structure of the optimisation results is stored in JSON format in the R object 
`predictions` and also saved. For inspecting it please open the 
[risk_dummy.json](../risk_dummy.json) file."
)
```

```{r output_nonghactions, echo=FALSE, results='asis', eval=!is_ghactions}
cat("The structure of the optimisation results is stored in JSON format in the R object 
`predictions` and also saved. For inspecting it please open the 
[risk_dummy.json](risk_dummy.json) file."
)
```

```{r conclusion_ghactions, echo=FALSE, results='asis', eval=is_ghactions}
cat("Real calculations should be performed using the [config_default.json](../config_default.json) configuration developed
by Christoph Sprenger (@chsprenger). However, due to the large size of the resulting 
`risk_default.json` object (~ 275MB) this default example could not be hosted at 
GitHub (maximum single file size <100MB). Thus this workflow was limited to the 
`dummy` configuration only!")
```
