This method allows serializers to return preexec
, postexec
, and aroundexec
() hooks in addition to a serializer.
This is useful for graphics device serializers which need a preexec
and postexec
hook to capture the graphics output.
Usage
endpoint_serializer(
serializer,
preexec_hook = NULL,
postexec_hook = NULL,
aroundexec_hook = NULL
)
Arguments
- serializer
Serializer method to be used. This method should already have its initialization arguments applied.
- preexec_hook
Function to be run directly before a PlumberEndpoint calls its route method.
- postexec_hook
Function to be run directly after a PlumberEndpoint calls its route method.
- aroundexec_hook
Function to be run around a PlumberEndpoint call. Must handle a
.next
argument to continue execution.
Details
preexec
and postexec
hooks happened directly before and after a route is executed.
These hooks are specific to a single PlumberEndpoint's route calculation.
Examples
# The definition of `serializer_device` returns
# * a `serializer_content_type` serializer
# * `aroundexec` hook
print(serializer_device)
#> function (type, dev_on, dev_off = grDevices::dev.off)
#> {
#> stopifnot(!missing(type))
#> stopifnot(!missing(dev_on))
#> stopifnot(is.function(dev_on))
#> stopifnot(length(formals(dev_on)) > 0)
#> if (!any(c("filename", "...") %in% names(formals(dev_on)))) {
#> stop("`dev_on` must contain an arugment called `filename` or have `...`")
#> }
#> stopifnot(is.function(dev_off))
#> endpoint_serializer(serializer = serializer_content_type(type),
#> aroundexec_hook = function(..., .next) {
#> tmpfile <- tempfile()
#> dev_on(filename = tmpfile)
#> device_id <- dev.cur()
#> dev_off_once <- once(function() dev_off(device_id))
#> success <- function(value) {
#> dev_off_once()
#> if (!file.exists(tmpfile)) {
#> stop("The device output file is missing. Did you produce an image?",
#> call. = FALSE)
#> }
#> con <- file(tmpfile, "rb")
#> on.exit({
#> close(con)
#> }, add = TRUE)
#> img <- readBin(con, "raw", file.info(tmpfile)$size)
#> img
#> }
#> cleanup <- function() {
#> dev_off_once()
#> on.exit({
#> unlink(tmpfile)
#> }, add = TRUE)
#> }
#> async <- FALSE
#> on.exit({
#> if (!async) {
#> cleanup()
#> }
#> }, add = TRUE)
#> result <- promises::with_promise_domain(createGraphicsDevicePromiseDomain(device_id),
#> {
#> .next(...)
#> })
#> if (is.promising(result)) {
#> async <- TRUE
#> result %>% then(success) %>% finally(cleanup)
#> }
#> else {
#> success(result)
#> }
#> })
#> }
#> <bytecode: 0x55de9df78e90>
#> <environment: namespace:plumber>